首页 > Java > DBUtils(数据库操作框架)
2014
08-26

DBUtils(数据库操作框架)

05. DBUtils(数据库操作框架)17

1、框架分类

1)ORM框架:Object Relation Mapping

    • JPA:Java Persistent API,ORM标准(借鉴了Hibernate)
    • Hibernate:非常流行(有两套,一套原有的,一套实现了JPA标准)
    • MyBatis:2010年开始。之前叫做iBatis

2)JDBC封装框架

    • DBUtils
    • Spring JDBC Template

2、编写自己的JDBC框架

1)了解:数据库元数据的获取(做框架用的),包括DataBaseMetaData、ParameterMetaData、ResultSetMetaData。

【注:本文使用的DBCPUtil工具类见《数据库连接池(DataSource)》一文

① DataBaseMetaData

@Test
public void test1() throws SQLException{
	Connection conn = DBCPUtil.getConnection();
	DatabaseMetaData dmd = conn.getMetaData();
	//获取数据库名称、版本
	String name = dmd.getDatabaseProductName();
	String version = dmd.getDatabaseProductVersion();
	System.out.println(name+" "+version);
	//获取数据库默认的隔离级别
	int isolation = dmd.getDefaultTransactionIsolation();
	System.out.println(isolation);
}

② ParameterMetaData

@Test
public void test2() throws SQLException{
	Connection conn = DBCPUtil.getConnection();
	PreparedStatement stmt = conn.prepareStatement("????");

	ParameterMetaData pmd = stmt.getParameterMetaData();
	//获取SQL语句中参数的个数,其实就是'?'的个数
	int count = pmd.getParameterCount();
	System.out.println(count);
}

③ ResultSetMetaData

@Test
public void test3() throws SQLException{
	Connection conn = DBCPUtil.getConnection();
	PreparedStatement stmt = conn.prepareStatement("select * from account");
	ResultSet rs = stmt.executeQuery();

	ResultSetMetaData rsmd = rs.getMetaData();
	//获取结果集的列数
	int count = rsmd.getColumnCount();
	System.out.println(count);

	for(int i = 0;i < count;i ++){
		String fieldName = rsmd.getColumnName(i+1);
		//获取结果集每一列的类型和列名
		int type = rsmd.getColumnType(i+1);
		System.out.println(type + " " +fieldName);
	}
}

2)编写JDBC框架(策略设计模式):DBAssist

框架介绍:针对DAO层需要频繁的进行update和query操作,本框架对这一过程进行了封装,对外提供了update、query方法直接调用。在执行query操作时,需要额外提供一个ResultSetHandler实例,该实例表示对查询结果集的处理策略。框架同时提供了该接口的两种实现:

BeanHandler:当查询结果集只有一条记录时,将结果集封装到JavaBean对象中返回。

BeanListHandler:当查询结果集有多条记录时,将结果集封装到List对象中返回。

用户也可以实现ResultSetHandler接口,定义自己的封装策略,相关API见下图:

05. DBUtils(数据库操作框架)1922

① 核心类:org.flyne.dbassist.DBAssist

public class DBAssist {
	//由用户传入数据源
	private DataSource dataSource;
	public DBAssist(DataSource dataSource){
		this.dataSource = dataSource;
	}

	/**
	 * 写:添加、删除、更新
	 * @param sql 支持参数化的SQL语句
	 * @param params params参数要和sql中的参数占位符对应
	 */
	public void update(String sql,Object...params){
		Connection conn = null;
		PreparedStatement stmt = null;
		try {
			conn = dataSource.getConnection();
			stmt = conn.prepareStatement(sql);
			ParameterMetaData pmd = stmt.getParameterMetaData();
			//获得SQL语句的参数个数
			int count = pmd.getParameterCount();
			if(count > 0){
				if(params == null || count != params.length){
					throw new RuntimeException("请检查参数是否正确");
				}
				for(int i = 0;i < count;i ++){ 					stmt.setObject(i+1, params[i]); 				} 			} 			stmt.executeUpdate(); 		} catch (SQLException e) { 			throw new RuntimeException(e); 		}finally{ 			release(null, stmt, conn);//释放资源 		} 	} 	/** 	 * 读:查询 	 * @param rsh 返回结果集的封装策略 	 * @return 没有查询到返回null 	 */ 	public Object query(String sql,ResultSetHandler rsh,Object...params){ 		Connection conn = null; 		PreparedStatement stmt = null; 		ResultSet rs = null; 		try{ 			conn = DBCPUtil.getConnection(); 			stmt = conn.prepareStatement(sql); 			ParameterMetaData pmd = stmt.getParameterMetaData(); 			int count = pmd.getParameterCount(); 			if(count > 0){
				if(params == null || count != params.length){
					throw new RuntimeException("请检查参数是否正确");
				}
				for(int i = 0;i < count;i ++){
					stmt.setObject(i+1, params[i]);
				}
			}
			rs = stmt.executeQuery();
			//根据结果集处理程序(ResultSetHandler)中定义的封装策略封装结果集
			return rsh.handler(rs);
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally{
			release(rs, stmt, conn);
		}
	}
}

② 结果集处理程序:org.flyne.dbassist.ResultSetHandler

public interface ResultSetHandler {
	/**
	 * 结果集的封装策略:如何把结果中的数据封装到指定的对象中
	 * @param rs
	 * @return 封装了数据的对象
	 */
	Object handle(ResultSet rs);
}

③ 框架提供的ResultHandler的两种实现

public class BeanHandler implements ResultSetHandler {
	private Class clazz;

	public BeanHandler(Class clazz) {
		this.clazz = clazz;
	}

	public Object handle(ResultSet rs) {
		Object bean = null;
		try {
			if (rs.next()) {
				bean = clazz.newInstance();
				ResultSetMetaData rsmd = rs.getMetaData();
				int count = rsmd.getColumnCount();
				for (int i = 0; i < count; i++) {
					String cname = rsmd.getColumnName(i + 1);
					Object obj = rs.getObject(cname);
					// 通过反射给bean中的属性赋值
					Field f = clazz.getDeclaredField(cname);
					f.setAccessible(true);
					f.set(bean, obj);
				}
			}
			return bean;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
----------------------------------------------------
public class BeanListHandler implements ResultSetHandler {
	private Class clazz;
	public BeanListHandler(Class clazz) {
		this.clazz = clazz;
	}

	public Object handle(ResultSet rs) {
		List list = new ArrayList();
		try {
			while (rs.next()) {
				Object bean = clazz.newInstance();
				ResultSetMetaData rsmd = rs.getMetaData();
				int count = rsmd.getColumnCount();
				for (int i = 0; i < count; i++) {
					String cname = rsmd.getColumnName(i + 1);
					Object obj = rs.getObject(cname);
					// 通过反射给bean中的属性赋值
					Field f = clazz.getDeclaredField(cname);
					f.setAccessible(true);
					f.set(bean, obj);
				}
				list.add(bean);
			}
			return list;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

3、DBUtils框架

DBUtils是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装。

1) QueryRunner类:

DBUtils中有个核心类QueryRunner,封装了常用的JDBC操作,其作用类似于上面自定义框架中的DBAssist类,常用方法可分为两组,如下图所示:

05. DBUtils(数据库操作框架)5512

QueryRunner中update、batch的用法如下:

public class Demo {
	private QueryRunner qr = new QueryRunner(DBCPUtil.getDataSource());

	@Test
	public void testAdd() throws SQLException{
		qr.update("insert into account values(?,?)","e",3000);
	}

	@Test
	public void testUpdate() throws SQLException{
		qr.update("update account set money = ? where name = ?",50000,"e");
	}
	@Test
	public void testDel() throws SQLException{
		qr.update("delete from account where name = ?","e");
	}

	//批处理插入10条
	@Test
	public void testBatch() throws SQLException{
		//第一维:记录的条数;第二纬:每条记录需要的参数
		Object params[][] = new Object[10][];
		for(int i = 0;i < params.length;i ++){
			params[i] = new Object[]{"N"+(i+1),1000*i};
		}
		qr.batch("insert into account(name,money) values(?,?)", params);
	}
}

2)ResultSetHandler接口:代表对结果集(ResultSet)的处理策略,同DBAssist中的ResultSetHandler接口。DBUtils包中提供了很多ResultsetHandler的实现,除了BeanHandler、BeanListHandler外,还有如下一些实现:

    • ArrayHandler:适合结果只有一条的情况。把第一条记录的每列的值封装到一个Object[]数组中。
    • ArrayListHandler:适合结果有多条的情况。把每列的值封装到Object[]数组中,把Object[]放到List中。
    • ColumnListHandler:适合取某列的值。把取到值封装到List中
    • KeyedHandler:查询多条记录。每条记录封装到一个Map中,key:字段名,value:字段值。再把该Map作为value放到另外一个Map中,该Map的key为指定的列值作为key。
    • MapHandler:适合一条结果。封装到一个Map中,key:字段名,value:字段值
    • MapListHandler:适合多条结果。把每条封装到一个Map中,key:字段名,value:字段值,在把Map封装到List中
    • ScalarHandler:适合取结果只有一行和一列的情况。

留下一个回复

你的email不会被公开。