【JavaWeb-11】DBUtils、QueryRunner的query/update/batch、ResultSetHandler的9个处理器、ThreadLocal管理conn进行事务处理的案例
2016-09-24 17:58
399 查看
1、DBUtils也是Apache开发的。它的作用是操作数据库的,相比之前的那些有什么优势呢?
它的读操作可以把结果直接转化成Array、List和Set等集合。
它的写操作非常简单,只需要写sql语句即可。
它当然可以与数据源的操作结合起来,使用连接池等技术。
所以DBUtils的核心还是简化操作数据库的代码。
2、DBUtils的3个核心对象。QueryRunner类(里面有query查询、update增删改和batch批处理)、ResultSetHandler接口(用于select后如何封装数据的)、DBUtils类(定义了关闭资源和事务处理的方法)。
3、准备工作的第一步肯定是导入jar包。我们还需要mysql连接的jar包,还需要c3p0的jar包。
4、我们一个个说说上面的文件和内容。我们先成最高层的应用说起,看DBUtilsServlet这个类,主要内容就下面的一段代码。这里我们先实例化了一个QueryRunner类,这个类需要的是一个数据源。然后我们用这个实例化出来的qr来调用个查询方法,并且把查询结果封装到BeanListHandler里面并复制给一个变量list,最后把这个list遍历出来。
——这个数据源就是我们利用我们上一个课程里面的C3P0方法得来的。
——在这里我们注意到,有两个地方需要扩展的。一个就是我们例子里面使用的是QueryRunner的query方法,还有另外两个需要学习。还有一个扩展的地方就是返回的结果封装,我们只用了一个BeanListHandler,还有好几个封装类需要我们去学习。
5、我们先对上面的查询做一个扩展,就是加不确定的参数,加一个问号,就在后面加1个参数。
——同理update函数也是,只是update函数有一个conn用于事务处理。
——batch是批处理。所以需要的参数是一个数组,这个数组第一个参数代表执行的次数,比如下面的5次,第二个参数代表需要的参数个数,下面是3个。所以就需要创建一个二维数组,把这个二维数组赋值过去。
6、我们接下来要扩展的是几个结果处理器。
——ArrayHandler,适合取1条记录,把这条记录的每列都封装到一维数组中。如果我们select语句是查询多条语句的话,它也只取第1条记录放到这个数组中。
——ArrayListHandler。就是把上面的数组封装到了List中。
——ColumnListHandler,取某一列的值,每一列是一个Object并且把这些Object封装到List里。我好奇的是为什么不用Array,毕竟同一列的值类型至少都是一样的?反正不管了,先记住再说,这里相当于取1条记录然后封装到Array里面的ArrayHandler。里面参数2表示取查询结果里的第二列值。
——KeyedHandler适合查询多条记录,最终是一个Map,但是里面还有一个Map。它是先把每条记录的字段名和值封装成小Map,然后根据你规定的大Map的key值,再把每一个小Map当做value值封装到大Map里面去。下面我们给的数字是1,就是制定第一列id未大Map的key。
——MapListHandler。就是把上面那个结果集封装到List里面。
——ScalarHandler去某列某一个值。一般我们用来和聚合函数进行配合,后面的参数表示取第几列。如果我们只给了第几列,但是前面查询的不是聚合函数结果,那么它只取该列的第1个值。需要注意的是如果与
——BeanHandler取1条记录封装成类。如果查询了多条记录,那么只取第1条。
——BeanListHandler上面说过,就是把类再封装到List里面。
7、我们现在再回顾一下如何结合事务来使用我们的DBUtils。结合事务的原理就是给一个Connection,但是需要保证是同一个Connection,这个时候就需要用ThreadLocal线程的知识。
——我们先来看一下目录结构和最重要的线程管理类。就是运用了ThreadLocal来管理我们的Connection。以后处理事务的时候需要的Connection都是从ThreadLocal里面拿,这样能保证是同一个Connection。这个ThreadLocalManager类相当于在C3P0Util上再封装了一遍。
——从最高层的应用层开始,也就是只需要一个服务类,这个服务类提供了一个转账的方法,方法提供3个参数:
——看看这个服务类内容是什么?这个服务类的主要目的是更新账户,但是更新的是做过修改的账户。我们直接传递的是账户类。所以需要先获取到涉及双方的账户,然后修改账户里面的金额,最后在更新这个账户。(这个类遵循惯例是继承自一个接口)。
——上面用到的AccountDao接口和它的实现类AccountDaoImpl,我们看实现类。实现类里面我们在使用QueryRunner的query和update方法时增加了一个Connection参数,这个Connection参数就是从ThreadLocalManager里面获取的,而不是直接从C3P0Util获取的。
源代码:JavaEE DBUtil结合ThreadLocal处理事务的案例
它的读操作可以把结果直接转化成Array、List和Set等集合。
它的写操作非常简单,只需要写sql语句即可。
它当然可以与数据源的操作结合起来,使用连接池等技术。
所以DBUtils的核心还是简化操作数据库的代码。
2、DBUtils的3个核心对象。QueryRunner类(里面有query查询、update增删改和batch批处理)、ResultSetHandler接口(用于select后如何封装数据的)、DBUtils类(定义了关闭资源和事务处理的方法)。
3、准备工作的第一步肯定是导入jar包。我们还需要mysql连接的jar包,还需要c3p0的jar包。
4、我们一个个说说上面的文件和内容。我们先成最高层的应用说起,看DBUtilsServlet这个类,主要内容就下面的一段代码。这里我们先实例化了一个QueryRunner类,这个类需要的是一个数据源。然后我们用这个实例化出来的qr来调用个查询方法,并且把查询结果封装到BeanListHandler里面并复制给一个变量list,最后把这个list遍历出来。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { QueryRunner qr=new QueryRunner(C3P0Util.getDs()); try { List<User> list=qr.query("select * from fuser", new BeanListHandler<User>(User.class)); for(User u : list){ System.out.println(u); } } catch (SQLException e) { e.printStackTrace(); } }
——这个数据源就是我们利用我们上一个课程里面的C3P0方法得来的。
——在这里我们注意到,有两个地方需要扩展的。一个就是我们例子里面使用的是QueryRunner的query方法,还有另外两个需要学习。还有一个扩展的地方就是返回的结果封装,我们只用了一个BeanListHandler,还有好几个封装类需要我们去学习。
5、我们先对上面的查询做一个扩展,就是加不确定的参数,加一个问号,就在后面加1个参数。
List<User> list=qr.query("select * from fuser where username=?", new BeanListHandler<User>(User.class),"eric");
——同理update函数也是,只是update函数有一个conn用于事务处理。
qr.update("insert into fuser(username,pwd,email) values(?,?,?)", "wang","1234","wang@163.com");
qr.update("update fuser set username=?,pwd=? where email=?", "li","123","wang@163.com");
qr.update("delete from fuser where email=?", "wang@163.com");
——batch是批处理。所以需要的参数是一个数组,这个数组第一个参数代表执行的次数,比如下面的5次,第二个参数代表需要的参数个数,下面是3个。所以就需要创建一个二维数组,把这个二维数组赋值过去。
Object[][] params=new Object[5][]; for(int i=0;i<params.length;i++){ params[i]=new Object[]{"tom"+i,"000"+i,i+"@163.com"}; } qr.batch("insert into fuser(username,pwd,email) values(?,?,?)", params);
6、我们接下来要扩展的是几个结果处理器。
——ArrayHandler,适合取1条记录,把这条记录的每列都封装到一维数组中。如果我们select语句是查询多条语句的话,它也只取第1条记录放到这个数组中。
Object[] ob=qr.query("select * from fuser where id=?", new ArrayHandler(),1); for(Object o : ob){ System.out.println(o); }
——ArrayListHandler。就是把上面的数组封装到了List中。
List<Object[]> list=qr.query("select * from fuser", new ArrayListHandler()); for(Object[] os : list){ for(Object o : os){ System.out.println(o); } }
——ColumnListHandler,取某一列的值,每一列是一个Object并且把这些Object封装到List里。我好奇的是为什么不用Array,毕竟同一列的值类型至少都是一样的?反正不管了,先记住再说,这里相当于取1条记录然后封装到Array里面的ArrayHandler。里面参数2表示取查询结果里的第二列值。
List<Object> list=qr.query("select username,pwd from fuser", new ColumnListHandler(2)); for(Object o : list){ System.out.println(o); }
——KeyedHandler适合查询多条记录,最终是一个Map,但是里面还有一个Map。它是先把每条记录的字段名和值封装成小Map,然后根据你规定的大Map的key值,再把每一个小Map当做value值封装到大Map里面去。下面我们给的数字是1,就是制定第一列id未大Map的key。
Map<Object,Map<String,Object>> map=qr.query("select * from fuser", new KeyedHandler(1)); for(Map.Entry<Object, Map<String,Object>> mm : map.entrySet()){ System.out.println("大Map的key是:"+mm.getKey()); for(Map.Entry<String, Object> m : mm.getValue().entrySet()){ System.out.println(m.getKey()+":"+m.getValue()); } System.out.println("--------------------"); }
——MapListHandler。就是把上面那个结果集封装到List里面。
List<Map<String,Object>> list=qr.query("select * from fuser", new MapListHandler()); for(Map<String,Object> m : list){ for(Map.Entry<String, Object> mm : m.entrySet()){ System.out.println(mm.getKey()+":"+mm.getValue()); } System.out.println("----------"); }
——ScalarHandler去某列某一个值。一般我们用来和聚合函数进行配合,后面的参数表示取第几列。如果我们只给了第几列,但是前面查询的不是聚合函数结果,那么它只取该列的第1个值。需要注意的是如果与
count(*)配合的话Object的类型是long,其他的是String类型。
Object o=qr.query("select count(*) from fuser", new ScalarHandler(1)); Object o=qr.query("select * from fuser", new ScalarHandler(2)); System.out.println(o);
——BeanHandler取1条记录封装成类。如果查询了多条记录,那么只取第1条。
User u=qr.query("select * from fuser where id=?", new BeanHandler<User>(User.class),2); System.out.println(u);
——BeanListHandler上面说过,就是把类再封装到List里面。
7、我们现在再回顾一下如何结合事务来使用我们的DBUtils。结合事务的原理就是给一个Connection,但是需要保证是同一个Connection,这个时候就需要用ThreadLocal线程的知识。
——我们先来看一下目录结构和最重要的线程管理类。就是运用了ThreadLocal来管理我们的Connection。以后处理事务的时候需要的Connection都是从ThreadLocal里面拿,这样能保证是同一个Connection。这个ThreadLocalManager类相当于在C3P0Util上再封装了一遍。
——从最高层的应用层开始,也就是只需要一个服务类,这个服务类提供了一个转账的方法,方法提供3个参数:
TransferServiceImpl tsi=new TransferServiceImpl(); try { tsi.transfer("andy", "eric", 100); } catch (SQLException e) { e.printStackTrace(); }
——看看这个服务类内容是什么?这个服务类的主要目的是更新账户,但是更新的是做过修改的账户。我们直接传递的是账户类。所以需要先获取到涉及双方的账户,然后修改账户里面的金额,最后在更新这个账户。(这个类遵循惯例是继承自一个接口)。
public class TransferServiceImpl implements TransferService { public void transfer(String fromName, String toName, int money) throws SQLException { AccountDaoImpl accountDao=new AccountDaoImpl(); try { ThreadLocalManager.startTransaction(); // 获取账户 Account fromAccount=accountDao.findAccountByName(fromName); Account toAccount=accountDao.findAccountByName(toName); // 计算金额 fromAccount.setMoney(fromAccount.getMoney()-money); toAccount.setMoney(toAccount.getMoney()+money); // 更新账户 accountDao.update(fromAccount); accountDao.update(toAccount); ThreadLocalManager.commit(); } catch (Exception e) { ThreadLocalManager.rollback(); e.printStackTrace(); }finally{ ThreadLocalManager.close(); } } }
——上面用到的AccountDao接口和它的实现类AccountDaoImpl,我们看实现类。实现类里面我们在使用QueryRunner的query和update方法时增加了一个Connection参数,这个Connection参数就是从ThreadLocalManager里面获取的,而不是直接从C3P0Util获取的。
public void update(Account account) throws SQLException { QueryRunner qr=new QueryRunner(C3P0Util.getDs()); qr.update(ThreadLocalManager.getConnection(),"update account set money=? where name=?",account.getMoney(),account.getName()); } public Account findAccountByName(String name) throws SQLException { QueryRunner qr=new QueryRunner(C3P0Util.getDs()); return qr.query(ThreadLocalManager.getConnection(),"select * from account where name=?", new BeanHandler<Account>(Account.class),name); }
源代码:JavaEE DBUtil结合ThreadLocal处理事务的案例
相关文章推荐
- dbutils使用---QueryRunner(query_update)、BeanList\BeanHandler、MapList\MapHandler、ScalarHandler
- UpdateBatch与事务处理的一点总结
- javaweb银行转账案例(事务处理)JDBC常见知识点(三)
- 使用CDatabase进行事务处理
- Executing a batch in a transaction--PHP DATA OBJECT(PDO)事务处理中的批量操作
- JavaBean中使用JDBC方式进行事务处理
- 使用.NET Framework 进行事务处理
- 一个iBatis框架进行batch处理的问题
- 使用Ado.Net进行简单事务处理的四种实现及比较
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处
- 如何使用Transact-SQL进行事务处理[示例]
- "新事务不能登记到指定的事务处理器中"异常的处理----MSDTC的正确配置
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处
- 关于在多处理器suse11上中断处理中使用current宏的问题及解决方法
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处理
- 利用C#事务处理对数据库进行多重操作
- .net企业应用高级编程 第五章 自动化处理和事务处理(基于C# XML)案例
- JavaBean中使用JDBC方式进行事务处理
- PHP对MYSQL数据库进行事务处理及表锁定
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处理