一、【数据库元数据的获取】(做框架用时非常实用)主要有以下java接口(都在java.sql.*包中):
1>DataBaseMetaData 数据库元数据
元数据:数据库本身及表结构、字段类型等的信息,称之为元数据。
好处:获取一些数据库的信息,比如数据库方言,数据库版本,建表的一些信息等。
如:DatabaseMetaData md = conn.getMetaData();然后可用md.getDatabaseProductName
2>ParameterMetaData 可获取 PreparedStatement 对象中每个参数标记的类型和属性信息的对象
如: ParameterMetaData md = stmt.getParameterMetaData();
md.getParameterCount() 获取参数?的个数。
md.getParameterTypeName(int index) 获取指定参数对应数据库中的类型名称。
等等。
3>ResultSetMetaData 可获取ResultSet 对象中列的类型和属性信息的对象。
如:ResultSetMetaData md = rs.getMetaData();
int count = md.getColumnCount(); 获取结果集中存在几列。
md.getColumnName(int index); 获取指定列的列名名称。
md.getColumnTypeName(int column); 获取指定列的数据库特定的类型名称。
等等。
二、【自定义框架原理】
1>可通过上面的三个元数据类,获取比如参数的个数。将需要执行的sql与参数数组传递进框架中,然后通过PrepardeStatment stmt=conn.preparedStatement(sql);获取到stmt对象。那么通过stmt.getParameterMetaData().getParameterCount()获取到参数的个数后,可以写相关的循环,用stmt.setObject(index,arg[i])分别设置好参数。直接executeUpdate或executeQuery即可。
对于DML语句来说,是用executeUpdate方法执行的,所以不需要返回值,基本上一个核心方法即可搞定。
2>而对于DQL语句来说,Select出来的结果集,可以被封装成多个不同类型的java对象。所以可以在执行rs = stmt.executeQuery();(注意前面的设置参数也是上面的提成的,直接用ParameterMetaDate获取的参数个数后,循环分别将数组中元素用setObject搞定),然后可将rs作为参数传递到ResultSetHandler接口的handler方法中。此handler方法返回Object类型,由用户自行去实现ResultSetHandler接口,这样用户可以对rs处理后,封装成自己想要的对象。
3>当然为了方便实现框架最好提供默认的BeanHandler(Class clazz)类的实现,此类对handler方法的实现只是将rs结果集封装成传递到BeanHandler类构造参数的clazz类实例中。
4>同理还需要提供一个常用的BeanListHandler(Class clazz)类实现,将rs结果集先封装成指定clazz的javabean中,再将这些javabean全部放入到List容器中。(以上两个方法必须要用反射实现)。
三、【开源jdbc框架DBUtils】 是apache提供一个优秀的jdbc框架,原理就是上面自定义框架原理。
核心类QueryRunner
1、有2个构造方法,需要一个 javax.sql.DataSource 来作参数的构造方法,通过这个数据源,来获取Connection
2、QueryRunner主要方法有2个 query和update。来分别提供对DQL与DML语句的支持。
3、对于查询到的结果集,提供了一个接口 ResultSetHandler
框架中提供了以下对ResultSetHandler接口实现的类
ArrayHandler:将查询到的某一行封装到一个数组当中,这个数组中的元素就是这一行中的一列
ArrayListHandler:将查询到的很多行结果,封装到一个容器当中,这个容器中存放都是数组
BeanHandler:将查询到的结果封装到javaBean中在创建这个对象的时候,需要指定javaBean的type(ClassName.Class)
BeanListHandler:将查询到的很多javaBean封装到一个容器中
ColumnListHandler: 将结果集中某一列的数据存放到List中。 创建对象的时候,参数需要指定列名
KeyedHandler:
将结果集中的每一行数据都封装到一个Map<列名,列值>里,
再把这些map再存到一个大map里,小map的key作为大map的key
MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
ScalarHandler:取一行中的某一列的值。(用于select count(*) from ...)
示例代码如下:
public class ResultHandlerDemo {
//获取QueryRunner对象。
private QueryRunner qr = new QueryRunner(DbcpUtil.getDataSource());
@Test
public void test1() throws SQLException{
String sql = "select * from person where id=?";
Object params = 1;
Person person = qr.query(sql, new BeanHandler(Person.class), params);//执行DQL,用query
System.out.println(person);
}
@Test
public void test2() throws SQLException{
String sql = "delete from person where id=?";
Object params = 1;
qr.update(sql, params);//执行DML,用update
}
}
四、简单了解下其它jdbc框架
在spring中还集成了一个简单实用的jdbc框架,那就是JdbcTemplate。原理也上面的自定义框架原理,类似于dbutls。对外提供了一个RowMapper接口,用户实现接口中的mapRow(ResultSet rs,int rowNum) 就可以封装成自己想要的数据了。当然spring也提供了类型dbutils的BeanHandler类对接口的默认实现,如BeanPropertyRowMapper等等。这里只简单的提下,有兴趣的用户可以自行去了解下。
特别说明下,若用spring进行对应用的创建对象管理,比如dao层对象、service层对象、action层对象的创建管理。而dao层依赖相关的持久化核对类,比如dbutls的QueryRunner类,JdbcTemplate框架跌 JdbcTemplate类,都是需要数据源的。
但QueryRunner类,比较扯淡没有setDateSource的方法。也就是直spring不能直接将ds设置到QueryRunner类中,但可以通过一些变通方法。比如用装饰模式,在工具包中,新建一工具类,QueryRunnerWapper,继承QueryRunner类,然后弄三个实例化变量 QueryRunner qr、DateSource ds,和一个随便的String initQueryRunner。然后提供两个sett方法(ds属性与initQueryRunner属性),qr实例实现不需要setter方法。在initQueryRunner属性setter方法体中,自己实例化qr的对象,指定构造方法,传入一个ds即可。