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);}
}