“SQL对象”级别的封装方案,即以一条SQL语句的粒度为单位,将其包装成一个DBObject,利用@DBCondition来声明SQL的输入条件、@DBResult来声明查询所返回的结果,Connector类实现对大量JDBC方法的封装,从而实现对DBObject对象进行处理,完成“SQL对象”中所对应的SQL的运行和结果集的返回,其中所有的JDBC方法细节均由Connector代理,框架使用者不需要进行过多关注。
(1)引入DBObject接口及声明
利用声明(Annotation)特性和BDObject接口来规范SQL对象(以一条SQL为单位粒度),实现对SQL对象类的基本定义。
一个极简的BDObject接口代码参考如下:
public interface DBObject {
public String getSQL();
}
创建@DBCondition声明,在继承DBObject接口的SQL对象类中,使用其对get方法进行声明,从而标识所有的SQL中的需要参数赋值内容,@DBCondition声明代码参考如下代码片段:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DBCondition {
int seq();
}
创建@DBResult声明,在继承DBObject接口的SQL对象类中,使用其对set方法进行声明,从而标识结果集返回的列信息,@DBResult声明代码参考如下代码片段:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DBResult {
String type();
int index();
}
通过以上方法,就可以创建BDObject类,从而来定义一个SQL对象,一个典型SQL对象的实现代码参考如下代码片段:
public class LoginDBObject implements DBObject{
private String username = null;
private String[] password = null;
@Override
public String getSQL() {
// TODO Auto-generated method stub
return "SELECT PASSWORD FROM USERS WHERE USERNAME = ?";
}
@DBCondition(seq = 1)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String[] getPassword() {
return password;
}
@DBResult(index = 1, type = "String[]")
public void setPassword(String[] password) {
this.password = password;
}
}
(2)Connector类实现代理
Connector类将用于对上篇文章框架中所提出的经装饰后的相关数据库方法进行封装(当然也可以剥离上篇文章中的相关方法,对纯JDBC对应方法进行封装),为支持一般的使用,至少需提供以下代理方法:
- queryExecute(DBObject o)封装 PoolablePreparedStatement相关的查询方法;
- noQueryExecute(DBObject o) 封装PoolablePreparedStatement相关的非查询方法;
- simpleQueryExecute(DBObject o) 封装 PoolableStatement相关的查询方法;
- simpleNoQueryExecute(DBObject o) 封装PoolableStatement相关的非查询方法;
- startTransaction()和endTransaction()用于控制事务的范围
- queryExecuteInTransaction(DBObject o)和noQueryExecuteInTransaction(DBObject o)用于封装基于事务控制的相关方法。
利用反射机制,通过fillPreparedStatement (DBObject o)自动根据DBObject对象内部的@DBCondition声明来填充SQL中的?参数占位符,参考如下代码片段:
private void fillPreparedStatement(DBObject o) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SQLException{
Class<?> clazz = o.getClass();
for(Method method : clazz.getMethods()){
for(Annotation annotation : method.getAnnotations()){
if(annotation instanceof DBCondition){
String type = method.getReturnType().toString();
int index = ((DBCondition) annotation).seq();
switch(type){
case "int" : {
pstmt.setInt(index, (int)method.invoke(o));
break;
}
case "long" : {
pstmt.setLong(index, (long)method.invoke(o));
break;