DBUtils
基本方法
- DBUtils是JDBC的简单封装,可以和JDBC混合使用。
- DBUtils对结果集自动封装为JavaBean是有着苛刻要求的:必须满足JavaBean的规范,其次Bean的getter与setter方法的名字与结果集的列名一一对应,而不要求JavaBean的私有成员与表结果集列名一一对应。
-
DBUtils可以将结果集封装为各种类型,主要有:
Bean/List<Bean>
,Map/List<Map>/Map<Map>
,数组/List<数组>
,列/List<列>
,这些类型。 -
DBUtils执行插入操作的时候,无法返回自增主键,这是一个很严重的问题,当然不能怪DBUtils,可以通过变通的方法来实现,比如在MySQL中,执行完了一个插入SQL后,接着执行
SELECT LAST_INSERT_ID()
语句,就可以获取到自增主键。 - DBUtils的性能和JDBC性能是一样,测试过程中没发现性能损失,拥有了很高性能的同时,而不失JDBC的灵活性。
对于Map<Map>
的类型使用KeyedHandler作为结果集处理器,内层的Map是列名-值
对,
外层的Map是主键-内层Map的引用
,但此处的主键不一定就是数据库的主键,可以随意指定,
比如:
ResultSetHandler h = new KeyedHandler("id"); Map found = (Map) queryRunner.query("select id, name, age from person", h); Map jane = (Map) found.get(new Long(1)); // jane's id is 1 String janesName = (String) jane.get("name"); Integer janesAge = (Integer) jane.get("age");
DbUtils类
提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
-
public static void close(…) throws java.sql.SQLException
: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。 -
public static void closeQuietly(…)
: 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLException。 -
public static void commitAndCloseQuietly(Connection conn)
: 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。 -
public static boolean loadDriver(java.lang.String driverClassName)
:这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。
QueryRunner类
该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。 QueryRunner类提供了两个构造方法:
默认的构造方法: QueryRunner()
需要一个javax.sql.DataSource
来作参数的构造方法。 QueryRunner(DataSource ds)
QueryRunner类
-
public Object query(Connection conn, String sql, Object[] params, ResultSetHandler rsh) throws SQLException
:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。 -
public Object query(String sql, Object[] params, ResultSetHandler rsh) throws SQLException
: 几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,并且它是从提供给构造方法的数据源(DataSource) 或使用的setDataSource 方法中重新获得 Connection。 -
public Object query(Connection conn, String sql, ResultSetHandler rsh) throws SQLException
: 执行一个不需要置换参数的查询操作。 -
public int update(Connection conn, String sql, Object[] params) throws SQLException
:用来执行一个更新(插入、更新或删除)操作。 -
public int update(Connection conn, String sql) throws SQLException
:用来执行一个不需要置换参数的更新操作。
ResultSetHandler接口
该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。
ResultSetHandler 接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)
。
ResultSetHandler 接口的实现类
-
ArrayHandler( )
:把结果集中的第一行数据转成对象数组。 -
ArrayListHandler( )
:把结果集中的每一行数据都转成一个数组,再存放到List中。 -
BeanHandler(Class type)
:将结果集中的第一行数据封装到一个对应的JavaBean实例中。 -
BeanListHandler(Class type)
:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。 -
ColumnListHandler(int columnIndex / String columnName)
:将结果集中某一列的数据存放到List中。 -
KeyedHandler( int columnIndex / String columnName )
:将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,并将其columnName的值作为指定的key。 -
MapHandler( )
:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。 -
MapListHandler( )
:将结果集中的每一行数据都封装到一个Map里,然后再存放到List -
ScalarHandler( )
:将结果集中的某一列 装入到一个对象中。
简单例子
例子1:
package com.crm.db.base; import java.sql.SQLException; import java.util.List; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import com.crm.domain.User; import com.crm.util.Constants; public class DBBase { private static DBBase dbBase; private static QueryRunner run ; private DataSource dataSource; public DataSource getDataSource() { return dataSource; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } private DBBase() {} private void init() { dbBase = this; run=new QueryRunner(dataSource); } public static DBBase getInstance() { return dbBase; } /** * eg: * select count(1) from user * * @param sql * @param params * @return */ public int count(String sql, Object[] params) { Object o = getAnAttr(sql,params); if(o instanceof Integer) { return (Integer) o; } if(o instanceof Long) { Long l = (Long)o; return l.intValue(); } String s = (String)o; try{ return Integer.parseInt(s); }catch (NumberFormatException e) { return 0; } } /** * 获得第一个查询第一行第一列 * @param sql * @param params * @return */ public Object getAnAttr(String sql, Object[] params) { showSql(sql); Object s=null; try { s = run.query(sql, new ScalarHandler(1),params); } catch (SQLException e) { e.printStackTrace(); } return s; } /** * 查询返回单个对象 * @param sql * @param clazz * @return */ public <T> T queryForObject(String sql,Object param[],Class<T> clazz) { T obj = null; try { showSql(sql); obj = (T)run.query(sql,new BeanHandler(clazz), param); } catch (SQLException e) { e.printStackTrace(); } return obj; } /** * 查询返回list对象 * @param sql * @param clazz * @return */ public <T> List<T> queryForOList(String sql,Object[] param,Class<T> clazz) { List<T> obj = null; try { showSql(sql); obj = (List<T>)run.query(sql,new BeanListHandler(clazz),param); } catch (SQLException e) { e.printStackTrace(); } return obj; } /** * 保存返回主键 * @param sql * @param param * @return */ public int storeInfoAndGetGeneratedKey(String sql,Object[] param) { int pk=0; try { showSql(sql); run.update(sql,param); pk = ((Long)run.query("SELECT LAST_INSERT_ID()", new ScalarHandler(1))).intValue(); }catch(SQLException e) { e.printStackTrace(); } return pk; } /** * 更新 * @param sql * @return */ public int update(String sql,Object[] param) { int i=0; try { showSql(sql); i = run.update(sql,param); }catch(SQLException e) { e.printStackTrace(); } return i; } private void showSql(String sql) { if(Constants.SHOW_SQL) { System.out.println(sql); } } /** * @param args */ public static void main(String[] args) { String uri = "jdbc:mysql://localhost:3306/miccrm"; DataSource ds = setupDataSource(uri); DBBase db = new DBBase(); db.setDataSource(ds); db.init(); String sql = "select count(1) from user"; int i = db.count(sql,null); sql="select name from user"; List<User> us = DBBase.getInstance().queryForOList(sql, null, User.class); for(User u:us) { System.out.println(u.getName()); } sql = "insert into user(name) values(?)"; int pk = DBBase.getInstance().storeInfoAndGetGeneratedKey(sql, new Object[]{"a"}); System.out.println(pk); sql ="select name from user where id =?"; String a =(String) DBBase.getInstance().getAnAttr(sql, new Object[]{1}); System.out.println(a); } private static DataSource setupDataSource(String connectURI) { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUsername("root"); ds.setPassword("123456"); ds.setUrl(connectURI); return ds; } }
DBUtils与Spring结合
DBUtils和Spring可以一起使用。
用DBUtils实现DAO,让Spring管理Datasource和transaction, 把DBBase声明为Spring可管理的bean,把datasource注入到DBBase中。 可能要用构造函数注入,因为需要在构造函数中创建QueryRunner。
DBBase中所有包含数据库操作的函数都让它抛出Runtime Exception, 或者直接借用Spring的DataAccessException。
DataSource应该使用Spring的一个DataSource代理TransactionAwareDataSourceProxy:
<bean id="dataSourceTarget" scope="singleton" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>oracle.jdbc.driver.OracleDriver</value> </property> <property name="url"> <value>jdbc:oracle:thin:@localhost:1521:dbname</value> </property> <property name="username"><value>user_bask_app</value></property> <property name="password"><value>user_bask_app</value></property> </bean> <bean id="dataSource" scope="singleton" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> <constructor-arg> <ref bean="dataSourceTarget"/> </constructor-arg> </bean> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner"> <constructor-arg> <ref bean="dataSource"/> </constructor-arg> </bean>