DBUtils工具
为了更加简单地使用JDBC,Apache组织提供了一个工具类库commons-dbutils,它是操作数据库地一个组件,实现一个对JDBC的简单封装,可以在不影响性能的情况下极大地简化JDBC地编码工作量。
API介绍
commons-dbutils的核心是两个类org.apache.commons.DbUtils、org.apache.commons.dbutils.QueryRunner和一个接口org.apache.commons.dbutils.ResultSetHealer。
DBUtils类
DBUtils类主要为如关闭连接、装载JDBC驱动程序之类的常规工作提供方法,它提供的方法都是静态方法。
1、close()方法
在DBUtils类中,提供了三个重载的close()方法,这些方法都是用来关闭数据连接,并且在关闭连接时,首先会检查参数是否为NULL,如果不是,该方法就会关闭Connection、Statement、ResultSet这三个对象。
2、closeQuietly(Connection conn,Statement stmt,ResultSet rs)方法
该方法用于关闭Connection、Statement和ResultSet对象。与close()方法相比,closeQuietly()方法不仅能Connection、Statement和ResultSet对象为NULL的情况下避免关闭,还能隐藏一些在程序中抛出的SQL异常。
3、commitAndCloseQuietly(Connection conn)方法
commitAndCloseQuietly()方法用来提交连接,然后关闭连接,并且在关闭连接时不抛出异常。
4、loadDriver(java.lang.String driverClassName)方法
loadDriver()方法用于装载并注册JDBC驱动程序,如果成功就返回true。使用该方法时,不需要捕捉ClassNotFoundException异常。
QueryRunner类
QueryRunner类简化了执行SQL语句的代码,它与ResultSetHandler组合在一起就能完成大部分的数据库操作,大大减少编码量。
QueryRunner类提供了两个构造方法,一个是默认的构造方法,一个是需要javax.sql.DataSource作为参数的构造方法。因此在不用为一个方法提供一个数据库连接的情况下,提供给构造器的DataSource就可以用来获得连接。但是,在使用JDBC操作数据库时,需要使用Connection对象对事务进行操作,QueryRunner类提供了不同的方法。
1、query(Connection conn,String sql,ResultSetHandler rsh,Object[] params)方法
该方法用于执行查询操作,其中,参数params表示一个对象数组,该数组中每个元素的值都被用来作为查询语句的置换参数。需要注意的是,该方法会自动处理PreparedStatement和ResultSet的创建和关闭。
值得一提的是,QueryRunner中还有一个方法是query(Connection conn,String sql,Object[] params,ResultSetHandler rsh)该方法与上述方法唯一不同的地方就是参数的位置。但是可变参数必须位于最后一项,所以此方法已过期。
2、query(String sql,ResultSetHandler rsh,Object[] params)方法
该方法用于执行查询操作,与第一个方法相比,它不需要将Connection对象传递给方法,它可以从提供给构造方法的数据源DataSource或使用的setDataSource()方法中获得连接。
3、query(Connection conn,String sql,ResultSetHandler rsh)方法
该方法用于执行一个不需要置换参数的查询结果。
4、update(Connection conn,String sql,Object[] params)方法
该方法用于执行插入、更新或者删除操作,其中,参数params表示SQL语句中的置换参数。
5、update(Connection conn,String sql)方法
该方法用于执行插入、更新或者删除操作,它不需要置换参数。
ResultSetHandler接口
ResultSetHandler接口用于处理ResultSet结果集,它可以将结果集中的数据转为不同的形式。根据结果集中数据类型的不同,ResultSetHandler提供了不同的实现类。
1)AbstractKeyedHandler:该类为抽象类,能够把结果集里面的数据转换为用Map存储。
2)AbstractListHandler:该类为抽象类,能够把结果集里面的数据转化为用List存储。
3)ArrayHandler:把结果集中的第一行数据转成对象数组。
4)ArrayListHandler:把结果集中的每一行数据转成一个对象数组,再将数组存放到List中。
5)BaseResultSetHandler:把结果集转化为其他对象的扩展。
6)BeanHandler:将结果集中的第一行数据存放到一个对应的javaBean实例中。
7)BeanListHandler:把结果集中的每一行数据存放到一个对应的javaBean实例中,再将JavaBean实例存放到List中。
8)BeanMapHandler:把结果集中的每一行数据存放到一个对应的javaBean实例中,再根据指定的key把每个JavaBean再存放到一个Map里。
9)ColumnListHandler:将结果集中的某一列的数据存放到List中
10)KeyedHandler:把结果集中的每一行数据封装到一个Map中,再根据指定的key把每个JavaBean再存放到一个Map里。
11)MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value是对应的值。
12)MapListHandler:把结果集中的每一行数据封装到一个Map中,再存放到List中。
13)ScalarHandler:将结果集中某一条记录的其中一列的数据存储成Object对象。
另外,在ResultSetHandler接口中,提供了一个单独的方法handle(java.sql.ResultSet rs),如果上述实现类没有提供想要的功能,可以通过自定义一个实现ResultSetHandler接口的类,然后通过重写handle()方法,实现结果集的处理。
ArrayHandler和ArrayListHandler
1)创建chapter03数据库,然后再数据库中创建一个表users,
create database chapter03;
use chapter03;
create table user(
id int(3) primary key auto_increment,
name varchar(20) not null,
password varchar(20) not null
);
insert into user(name,password) values('zhangsan','123456');
insert into user(name,password) values('lisi','123456');
insert into user(name,password) values('wangwu','123456');
2)引入DBUtils包,并编写java
BaseDao.java
package DBUtils;
import java.sql.*;
import org.apache.commons.dbutils.*;
import JDBC.JDBCUtils;
public class BaseDao {
public static Object query(String sql,ResultSetHandler<?>rsh,Object...params)throws SQLException{
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try{
conn=JDBCUtils.getConnection();
pstmt=conn.prepareStatement(sql);
if(params!=null){
for(int i=0;i<params.length;++i){
pstmt.setObject(i+1, params[i]);
}
}
rs=pstmt.executeQuery();
Object obj=rsh.handle(rs);
return obj;
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs, pstmt, conn);
}
return rs;
}
}
ResultSetTest1.java
package DBUtils;
import java.sql.SQLException;
import org.apache.commons.dbutils.handlers.ArrayHandler;
public class ResultSetTest1 {
public static void testArrayHandler()throws SQLException{
BaseDao basedao=new BaseDao();
String sql="select * from user where id=?";
Object[] arr=(Object[]) basedao.query(sql, new ArrayHandler(), new Object[]{1});
for(int i=0;i<arr.length;++i){
System.out.print(arr[i]+",");
}
}
public static void main(String[] args)throws SQLException{
testArrayHandler();
}
}
ResultSetTest2.java
package DBUtils;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
public class ResultSetTest2 {
public static void testArrayHandler()throws SQLException{
BaseDao basedao=new BaseDao();
String sql="select * from user";
List list=(List) basedao.query(sql, new ArrayListHandler());
for(int i=0;i<list.size();++i){
Object[] arr=(Object[])list.get(i);
for(int j=0;j<arr.length;j++){
System.out.print(arr[j]+",");
}
System.out.println();
}
}
public static void main(String[] args)throws SQLException{
testArrayHandler();
}
}
BeanHandler、BeanListHandler和BeanMapHandler
这三个类是将结果集的数据封装到对应的JavaBean实例中,这也是实际开发中最常见的结果集处理方法。
User.java
package DBUtils;
public class User {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
ResultSetTest3 .java
package DBUtils;
import org.apache.commons.dbutils.handlers.*;
import java.sql.*;
public class ResultSetTest3 {
public static void testBeanHandler()throws SQLException{
BaseDao basedao=new BaseDao();
String sql="select * from user where id=?";
User user=(User)basedao.query(sql, new BeanHandler(User.class), 1);
System.out.print("id为1的User对象的name值为:"+user.getName());
}
public static void main(String[] args)throws SQLException{
testBeanHandler();
}
}
ResultSetTest4.java
package DBUtils;
import org.apache.commons.dbutils.handlers.*;
import java.sql.*;
import java.util.ArrayList;
public class ResultSetTest4 {
public static void testBeanListHandler()throws SQLException{
String sql="select * from user";
ArrayList<User>list=(ArrayList<User>)BaseDao.query(sql, new BeanListHandler(User.class));
for(int i=0;i<list.size();++i){
System.out.println("第"+(i+1)+"条数据的username值为:"+list.get(i).getName());
}
}
public static void main(String[] args)throws SQLException{
testBeanListHandler();
}
}
ResultSetTest5.java
package DBUtils;
import java.sql.SQLException;
import java.util.Map;
import org.apache.commons.dbutils.handlers.BeanMapHandler;
public class ResultSetTest5 {
public static void testBeanMapHandler()throws SQLException{
String sql="select id,name,password from user";
Map<Integer,User>map=(Map<Integer,User>)BaseDao.query(sql, new BeanMapHandler<Integer,User>(User.class,"id"));
User u=map.get(1);
String uName=u.getName();
String uPassword=u.getPassword();
System.out.print("id为1的User对象的name值为:"+uName+",password值为"+uPassword);
}
public static void main(String[] args)throws SQLException{
testBeanMapHandler();
}
}
MapHandler和MapListHandler
ResultSetTest6.java
package DBUtils;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.apache.commons.dbutils.handlers.*;
public class ResultSetTest6 {
public static void testMapHandler()throws SQLException{
BaseDao basedao=new BaseDao();
String sql="select * from user where id=?";
Map map=(Map)basedao.query(sql, new MapHandler(), 1);
System.out.println(map);
}
public static void testMapListHandler()throws SQLException{
BaseDao basedao=new BaseDao();
String sql="select * from user";
List list=(List)basedao.query(sql, new MapListHandler());
System.out.println(list);
}
public static void main(String[] args)throws SQLException{
//testMapHandler();
testMapListHandler();
}
}
ColumnListHandler
ResultSetTest7.java
package DBUtils;
import java.sql.SQLException;
import java.util.*;
import org.apache.commons.dbutils.handlers.*;
public class ResultSetTest7 {
public static void testColumnListHandler()throws SQLException{
BaseDao basedao=new BaseDao();
String sql="select * from user";
List list=(ArrayList<User>)basedao.query(sql, new ColumnListHandler("name"));
System.out.println(list);
}
public static void main(String[] args)throws SQLException{
testColumnListHandler();
}
}
ScalarHandler
ResultSetTest8.java
package DBUtils;
import java.sql.SQLException;
import org.apache.commons.dbutils.handlers.*;
public class ResultSetTest8 {
public static void testScalarHandler()throws SQLException{
BaseDao basedao=new BaseDao();
String sql="select * from user where id=?";
Object arr=(Object)basedao.query(sql, new ScalarHandler("name"),1);
System.out.println(arr);
}
public static void main(String[] args)throws SQLException{
testScalarHandler();
}
}
KeyedHandler
ResultSetTest9.java
package DBUtils;
import java.sql.SQLException;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.dbutils.handlers.*;
import org.apache.commons.dbutils.QueryRunner;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class ResultSetTest9 {
public static DataSource ds=null;
static{
ComboPooledDataSource cpds=new ComboPooledDataSource();
ds=cpds;
}
public static void testKeyedHandler()throws SQLException{
String sql="select id,name,password from user";
QueryRunner qr=new QueryRunner(ds);
Map<Object,Map<String,Object>>map=qr.query(sql, new KeyedHandler<Object>("id"));
Map umap=(Map)map.get(new Integer(1));
String uName=(String)umap.get("name");
String uPassword=(String)umap.get("password");
System.out.println(uName+":"+uPassword);
}
public static void main(String[] args)throws SQLException{
testKeyedHandler();
}
}
DBUtils实现增删改查
C3p0Utils.java
package DBUtils;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3p0Utils {
private static DataSource ds;
static{
ds=new ComboPooledDataSource();
}
public static DataSource getDataSource(){
return ds;
}
}
DBUtilsDao.java
package DBUtils;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import JDBC.JDBCUtils;
public class DBUtilsDao {
public List findAll()throws SQLException{
QueryRunner runner=new QueryRunner(C3p0Utils.getDataSource());
String sql="select * from user";
List list=(List)runner.query(sql, new BeanListHandler(User.class));
return list;
}
public User find(int id)throws SQLException{
QueryRunner runner=new QueryRunner(C3p0Utils.getDataSource());
String sql="select * from user where id=?";
User user=(User)runner.query(sql, new BeanHandler(User.class),new Object[]{id});
return user;
}
public Boolean insert(User user)throws SQLException{
QueryRunner runner=new QueryRunner(C3p0Utils.getDataSource());
String sql="insert into user(name,password)values(?,?)";
int num=runner.update(sql, new Object[]{
user.getName(),
user.getPassword()
});
if(num>0){
return true;
}
return false;
}
public Boolean update(User user)throws SQLException{
QueryRunner runner=new QueryRunner(C3p0Utils.getDataSource());
String sql="update user set name=?,password=? where id=?";
int num=runner.update(sql, new Object[]{
user.getName(),
user.getPassword(),
user.getId()
});
if(num>0)return true;
return false;
}
public Boolean delete(int id)throws SQLException{
QueryRunner runner=new QueryRunner(C3p0Utils.getDataSource());
String sql="delete from user where id=?";
int num=runner.update(sql, id);
if(num>0)return true;
return false;
}
}
这样,就实现了用DBUtils框架对数据库的基本操作。需要注意的是,在查询方法中,用到了BeanHeadler和BeanListHeadler实现类来处理结果集,查询一条数据用的是能够处理一行数据的BeanHandler类,查询所有数据时用的是能处理所有行数据的BeanListHandler类,切勿使用错误,否则会造成程序报错。
增加功能
DBUtilsDaoTest1.java
package DBUtils;
import java.sql.SQLException;
public class DBUtilsDaoTest1 {
private static DBUtilsDao dao=new DBUtilsDao();
public static void testInsert() throws SQLException{
User user=new User();
user.setName("zhaoliu");
user.setPassword("666666");
boolean b=dao.insert(user);
System.out.println(b);
}
public static void main(String[] args)throws SQLException{
testInsert();
}
}
修改功能
DBUtilsDaoTest2.java
package DBUtils;
import java.sql.SQLException;
public class DBUtilsDaoTest2 {
private static DBUtilsDao dao=new DBUtilsDao();
public static void testInsert() throws SQLException{
User user=new User();
user.setName("zhaoliu");
user.setPassword("333333");
user.setId(4);
boolean b=dao.update(user);
System.out.println(b);
}
public static void main(String[] args)throws SQLException{
testInsert();
}
}
删除功能
DBUtilsDaoTest3.java
package DBUtils;
import java.sql.SQLException;
public class DBUtilsDaoTest3 {
private static DBUtilsDao dao=new DBUtilsDao();
public static void testDelete() throws SQLException{
boolean b=dao.delete(4);
System.out.println(b);
}
public static void main(String[] args)throws SQLException{
testDelete();
}
}
查询功能
DBUtilsDaoTest4.java
package DBUtils;
import java.sql.SQLException;
public class DBUtilsDaoTest4 {
private static DBUtilsDao dao=new DBUtilsDao();
public static void testFind() throws SQLException{
User user=dao.find(3);
System.out.println(user.getId()+","+user.getName()+","+user.getPassword());;
}
public static void main(String[] args)throws SQLException{
testFind();
}
}
DBUtils处理事务
前面我们用DBUtils完成了对数据库增删改查的操作,其中使用了QueryRunner类中有参数的构造方法,参数即数据源,这时,框架会自动创建数据库连接,并释放连接。但这是处理一般操作的时候,当要进行事务操作时,连接的创建和释放就要由程序员自己实现了。
1)建立所需的数据库account作为账目记录表,并添加数据
use chapter03;
create table account(
id int primary key auto_increment,
name varchar(40),
money float
);
insert into account(name,money)values('a',1000);
insert into account(name,money)values('b',2000);
2)创建实体类Account
package DBUtils;
public class Account {
private int id;
private String name;
private float money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getMoney() {
return money;
}
public void setMoney(float money) {
this.money = money;
}
}
3)创建类JDBCUtils,该类封装了创建连接、开启事务、关闭事务等方法。需要注意的是,请求中的一个事务涉及多个数据库操作,如果这些操作中的Connection是从连接池获得的,两个DAO操作就要用到两个Connection,这样是没有办法完成一个事务的,因此需要借助ThreadLocal类。
ThreadLocal类的作用是在一个线程里记录变量。可以生成一个连接放在这个线程里,只要是这个线程的任何对象都可以共享这个连接,当线程结束后就删除这个连接。这样就保证了一个事务,一个连接、
JDBCUtils.java
package DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils {
private static ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>();
private static DataSource ds=new ComboPooledDataSource();
public static DataSource getDataSource(){
return ds;
}
public static Connection getConnection() throws SQLException{
Connection conn=threadLocal.get();
if(conn==null){
conn=ds.getConnection();
threadLocal.set(conn);
}
return conn;
}
public static void startTransaction(){
try{
Connection conn=getConnection();
conn.setAutoCommit(false);
}catch(SQLException e){
e.printStackTrace();
}
}
public static void commit(){
try{
Connection conn=threadLocal.get();
if(conn!=null)conn.commit();
}catch(SQLException e){
e.printStackTrace();
}
}
public static void rollback(){
try{
Connection conn=threadLocal.get();
if(conn!=null)conn.rollback();
}catch(SQLException e){
e.printStackTrace();
}
}
public static void close(){
Connection conn=threadLocal.get();
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}finally{
threadLocal.remove();
conn=null;
}
}
}
}
4)创建类AccountDao,该类封装了转账所需的数据库操作,包括查询用户,转入,转出操作。
AccountDao.java
package DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
public class AccountDao {
public Account find(String name)throws SQLException{
QueryRunner runner=new QueryRunner();
Connection conn=JDBCUtils.getConnection();
String sql="select * from account where name=?";
Account account=(Account)runner.query(conn, sql, new BeanHandler(Account.class),new Object[]{name});
return account;
}
public void update(Account account)throws SQLException{
QueryRunner runner=new QueryRunner(C3p0Utils.getDataSource());
Connection conn=JDBCUtils.getConnection();
String sql="update account set money=? where name=?";
runner.update(conn,sql,new Object[]{account.getMoney(),account.getName()});
}
}
5)创建类Business,该类包括转账过程的逻辑方法,导入了封装事务操作的JDBCUtils类和封装数据库操作的AccountDao类,完成转账操作。
Business.java
package DBUtils;
import java.sql.SQLException;
public class Business {
public static void transfer(String sourceAccountName,String toAccountName,float money){
try{
JDBCUtils.startTransaction();
AccountDao dao=new AccountDao();
Account accountFrom=dao.find(sourceAccountName);
Account accountto=dao.find(toAccountName);
if(money<accountFrom.getMoney()){
accountFrom.setMoney(accountFrom.getMoney()-money);
}else{
System.out.println("转出账户余额不足");
}
accountto.setMoney(accountto.getMoney()+money);
dao.update(accountFrom);
dao.update(accountto);
JDBCUtils.commit();
System.out.print("提交成功");
}catch(SQLException e){
System.out.println("提交失败");
JDBCUtils.rollback();
e.printStackTrace();
}finally{
JDBCUtils.close();
}
}
public static void main(String[] args)throws SQLException{
transfer("a","b",200);
}
}