DButils的通用数据库方法有两种,一种是用于增删改的Update方法,一种是用于查询的Query方法。
根据其通用性的思想,对update方法和query方法的底层实现进行解析。
根据DButils的两个方法思考,思路是:
1.传入带占位符(?)的数据库语句,如:insert into bank values(null,?,?)。
2.传入通用型的参数,并且传入的参数个数可变。
Update(增删改):
//通用的增删改
/*
* @param sql 需要操作的sql语句
* @param args 可变参数,...表示有几个占位符就传入几个参数,args相当于一个可变数组
* */
public void update(String sql,Object ... args) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCutil02.getConn();
ps = conn.prepareStatement(sql);
for (int i=0;i
通过(Object ... name)(可变参数)的方式,可以传入任意个数的参数,并且Object类型可以接受任意类型的参数。
然后通过for循环,遍历args 数组,通过PrepareStatement的setObject方法,一个个为占位符赋值。
但是这样有隐患,那就是如果输入的参数个数与占位符不一样,遍历次数就会有问题,将会出错。
所以为了解决这个隐患,使用参数元数据 ParameterMetaData 来获取参数SQL中有多少个问号,通过计算占位符的数量,从而消除遍历次数不正确的问题。
优化后的Update:
/*
元数据:描述数据的数据
* 优化版的update语句,防止可变参数数量传错,以问号个数为准
* 通过 参数元数据ParameterMetaData 来获取参数中有多少个问号
* */
public void update02(String sql,Object ... args) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCutil02.getConn();
ps = conn.prepareStatement(sql);
//元数据
//获取到有几个问号,占位符
ParameterMetaData metaData = ps.getParameterMetaData();
int count = metaData.getParameterCount();
for (int i=0;i
Query的底层实现稍微上有点复杂,前两个问题与update一样,占位符个数和参数,稍有不同的时候,查询语句会返回结果集,并且数据库返回的结果集需要进行封装,还需要将封装的结果集返回,所以query的重点就在:
数据获取与数据封装
解决方法:由于我们不清楚具体要封装成什么对象,所以选择将结果集交给调用者自行去封装。
使用方法:
具体代码:
ResultSetHandler接口:
import java.sql.ResultSet;
import java.sql.SQLException;
public interface ResultSetHandler {
/*
* 定义了数据封装的规则。规范
* */
T Handle(ResultSet rs);
}
Query 方法:
/*查询
可能出现的问题
select * from aa
select * from aa where id =?
select * from aa where name=? and gender=?
问题一:数据获取,以及数据封装成什么对象返回。因为调用的地方需要的数据不一样,数据封装问题
解决方法:将结果集交给用户自行去封装,定义一个ResultSetHandler的接口,里面声明一个handle方法。
然后query方法中添加一个ResultSetHandler接口参数,然后通过匿名实现类的方式实现handle方法,然后对其中的结果集数据进行封装。
*/
public T query(String sql,ResultSetHandler handler,Object ... args){
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCutil02.getConn();
ps = conn.prepareStatement(sql);
//元数据
//获取到有几个问号,占位符
ParameterMetaData metaData = ps.getParameterMetaData();
int count = metaData.getParameterCount();
for (int i=0;i
Query 方法的调用:
/*
* ResultSetHandler参数其实等同于
* ResultSetHandler handle = new A();A是具体实现类,这里使用了匿名实现类的方式,指向实现类的引用,相当于接口的向上转型。
* */
@Test
public void testQuery(){
Bank bank = query("select * from bank where id = ?", new ResultSetHandler() {
@Override
public Bank Handle(ResultSet rs) {
try {
Bank bank = new Bank();
while (rs.next()){
String name = rs.getString("name");
double money = rs.getDouble("money");
bank.setName(name);
bank.setMoney(money);
}
return bank;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
},3);
System.out.println(bank);
}
其上基本上就是DButils框架的update和query方法的解析,其中update方法比较简单,因为只需要执行即可。
query方法的重点主要就是在数据的封装方面,如何做到可以通用型的封装数据以及返回通用型的数据。
通过泛型类型的方式,让调用者指定封装数据的对象类型,并且将数据封装的工作交给调用者来进行,而无论使用匿名实现类的方式在调用query方法的时候再定义封装方法,还是提前写好继承接口的类作为参数传入。
核心思想都是将我们无法确定的数据封装,数据对象类型,交给调用者来处理,从而达成定义通用方法的目的。