动态SQL数据层框架(3):BaseDao接口和BaseDaoSupport抽象类

 

这是一个简单的数据层框架,可以实现动态SQL查询、自动化事务管理、IOC和依赖注入,使用了以下技术:

1) Maven管理依赖,Github托管代码  2) DBUtils框架作为JDBC底层框架  3) JDK动态代理实现的AOP  4) 注解  5) Freemarker来做动态SQL模板的解析  6) 工厂设计模式  7) 反射和XML解析


从使用方式开始介绍,逐步深入地去理解框架的各个知识点。

框架主要分为两部分:
1) dynamic-sql-dao是框架主体
2) dynamic-sql-dao-test是一个demo含有测试用例


Github地址

https://github.com/xuguofeng/dynamic-sql-dao
https://github.com/xuguofeng/dynamic-sql-dao-test

 

文章目录

动态SQL数据层框架(0):一个基于FreeMarker和DBUtils的动态SQL框架
动态SQL数据层框架(1):DBUtils框架基础
动态SQL数据层框架(2):框架结构
动态SQL数据层框架(3):BaseDao接口和BaseDaoSupport抽象类
动态SQL数据层框架(4):DynamicSQLParser工具类和配置文件
动态SQL数据层框架(5):AOP事务管理

 

BaseDao接口用于定义最基础的数据操作的方法。BaseDaoSupport抽象类对BaseDao中的方法做了实现。本文将作详细介绍

 

一、BaseDao接口介绍

首先,这是一个泛型接口,实现类需要指定泛型的具体类型。

 

此接口定义了实体操作的通用增删改查方法

 

插入实体数据到数据库并返回插入数据的主键

int addObject(E e);

 

删除指定主键的数据并返回操作是否成功

boolean deleteObject(Integer id);

 

修改指定实体数据并返回操作是否成功

boolean updateObject(E e);

 

根据主键获取一个实体对象

E getObject(Integer id);

 

根据动态查询条件获取一个实体对象

E getObject(Map<String, Object> paramaters);

 

获取全部实体对象的集合

List<E> getObjects();

 

根据动态查询条件获取实体对象的集合

List<E> getObjects(Map<String, Object> paramaters);

 

根据动态查询条件获取分页实体对象的集合

List<E> getObjects(Map<String, Object> paramaters, Integer pageNum, Integer pageSize);

 

根据动态查询条件获取实体对象的数量

int count(Map<String, Object> paramaters);

 

 

二、BaseDaoSupport抽象类详解

该类实现了BaseDao接口。使用DBUtils进行JDBC操作,使用DynamicSQLParser进行动态SQL解析

 

注意:在使用DynamicSQLParser获取SQL时传入的id需要和sql配置文件中<sql>标签的id属性一致。

 

1、核心字段

1 // 用于动态SQL解析
2 private DynamicSQLParser sqlParser = DynamicSQLParser.getDynamicSQLParser();
3 
4 // 匹配SQL中的#arg#
5 private static Pattern argPattern = Pattern.compile("#([^\\s]+)#");
6 
7 // 泛型类型
8 protected Class<E> entityClass = GenericsUtil.getSuperClassGenricType(getClass());

 

2、增删改方法

addObject方法

首先使用DynamicSQLParser获取SQL(不进行动态解析,所以SQL中不要含有动态标签),然后使用反射技术从参数对象中获取需要注入到SQL中参数,并封装为集合,最后执行SQL

 1 QueryRunner qr = new QueryRunner();
 2 try {
 3 
 4     Connection conn = TransactionManager.getConnection();
 5 
 6     // 获取插入数据类型的简单名
 7     String clazzName = this.entityClass.getSimpleName();
 8 
 9     // 保存全部注入参数
10     List<Object> l = new ArrayList<Object>();
11 
12     // 获取SQL模板
13 // SQL的key为:数据类型简单名 拼上 _addObject
14 // 不需要进行动态SQL解析,所以后两个参数分别为null、false
15     String sql = this.sqlParser.parseSql(clazzName + "_addObject", null, false);
16 
17     // 匹配SQL中全部待赋值的参数
18     Matcher m = argPattern.matcher(sql);
19     while (m.find()) {
20         String arg = m.group(1);
21         try {
22             PropertyDescriptor pd = new PropertyDescriptor(arg, this.entityClass);
23             Method getter = pd.getReadMethod();
24             Object ret = getter.invoke(e);
25             l.add(ret);
26         } catch (Exception e1) {}
27     }
28 // 替换占位符
29     sql = sql.replaceAll("#([^\\s]+)#", "?");
30     // 执行SQL获取id
31     return qr
32             .insert(conn, sql, new ScalarHandler<Long>(1), l.toArray())
33             .intValue();
34 } catch (SQLException e1) {
35     throw new RuntimeException(e1.getMessage(), e1);
36 }
View Code

 

deleteObject方法

首先使用DynamicSQLParser获取SQL(不进行动态解析,所以SQL中不要含有动态标签,传入id参数后即执行SQL

 1 QueryRunner qr = new QueryRunner();
 2 try {
 3     Connection conn = TransactionManager.getConnection();
 4     // 获取插入数据类型的简单名
 5     String clazzName = this.entityClass.getSimpleName();
 6 
 7     // 获取SQL模板
 8 // SQL的key为:数据类型简单名 拼上 _deleteObject
 9 // 不需要进行动态SQL解析,所以后两个参数分别为null、false
10     String sql = this.sqlParser.parseSql(clazzName + "_deleteObject", null, false);
11 
12     // 执行SQL获取影响的行数
13     int rows = qr.update(conn, sql, id);
14     return rows == 1;
15 } catch (SQLException e1) {
16     throw new RuntimeException(e1.getMessage(), e1);
17 }
View Code

 

updateObject方法

 1 QueryRunner qr = new QueryRunner();
 2 try {
 3     Connection conn = TransactionManager.getConnection();
 4 
 5     // 获取插入数据类型的简单名
 6     String clazzName = this.entityClass.getSimpleName();
 7 
 8     // 保存全部注入参数
 9     List<Object> l = new ArrayList<Object>();
10 
11     // 获取SQL模板
12 // SQL的key为:数据类型简单名 拼上 _updateObject
13 // 不需要进行动态SQL解析,所以后两个参数分别为null、false
14     String sql = this.sqlParser.parseSql(clazzName + "_updateObject", null, false);
15     // 匹配SQL中待赋值的参数
16     Matcher m = argPattern.matcher(sql);
17     while (m.find()) {
18         String arg = m.group(1);
19         try {
20             PropertyDescriptor pd = new PropertyDescriptor(arg, this.entityClass);
21             Method getter = pd.getReadMethod();
22             Object ret = getter.invoke(e);
23             l.add(ret);
24         } catch (Exception e1) {}
25     }
26 // 替换占位符
27     sql = sql.replaceAll("#([^\\s]+)#", "?");
28     // 执行SQL获取影响的行数
29     int rows = qr.update(conn, sql, l.toArray());
30     return rows == 1;
31 } catch (SQLException e1) {
32     throw new RuntimeException(e1.getMessage(), e1);
33 }
View Code

 

3、查询方法

getObject(int)方法

首先使用DynamicSQLParser获取SQL(不需要动态解析),然后获取ResultSetHandler,子类可以重写getResultSetHandler()进行自定义,传入id参数后执行SQL并返回结果。

 1 QueryRunner qr = new QueryRunner();
 2 try {
 3     Connection conn = TransactionManager.getConnection();
 4     // 获取插入数据类型的简单名
 5     String clazzName = this.entityClass.getSimpleName();
 6     // 获取SQL模板
 7 // SQL的key为:数据类型简单名 拼上 _getObject_int
 8 // 不需要进行动态SQL解析,所以后两个参数分别为null、false
 9     String sql = this.sqlParser.parseSql(clazzName + "_getObject_int", null, false);
10     // 执行SQL获取返回对象
11     ResultSetHandler<E> rsh = getResultSetHandler();
12     E e = (E) qr.query(conn, sql, rsh, id);
13     return e;
14 } catch (SQLException e1) {
15     throw new RuntimeException(e1.getMessage(), e1);
16 }
View Code

 

getObject(Map)方法

首先使用DynamicSQLParser获取SQL需要根据Map条件进行动态解析,然后从Map中获取注入到SQL参数,并封装为集合,获取ResultSetHandler,子类可以重写getResultSetHandler()进行自定义,最后执行SQL并返回结果。

 1 QueryRunner qr = new QueryRunner();
 2 try {
 3     Connection conn = TransactionManager.getConnection();
 4 
 5     // 获取插入数据类型的简单名
 6     String clazzName = this.entityClass.getSimpleName();
 7 
 8     // 保存全部注入参数
 9     List<Object> l = new ArrayList<Object>();
10 
11     // 获取SQL模板
12 // SQL的key为:数据类型简单名 拼上 _getObject_map
13     String sql = this.sqlParser.parseSql(clazzName + "_getObject_map", paramaters, true);
14 
15     // 匹配SQL中待赋值的参数
16     Matcher m = argPattern.matcher(sql);
17     while (m.find()) {
18         String arg = m.group(1);
19         Object val = paramaters.get(arg);
20         if (val instanceof List) {
21             StringBuilder sb = new StringBuilder();
22             List v = (List) val;
23             int iMax = v.size() - 1;
24             for (int i = 0;; i++) {
25                 sb.append("?");
26                 l.add(v.get(i));
27                 if (i == iMax) {
28                     break;
29                 }
30                 sb.append(", ");
31             }
32             sql = sql.replace("#" + arg + "#", sb.toString());
33         } else {
34             l.add(val);
35         }
36     }
37 // 替换占位符
38     sql = sql.replaceAll("#([^\\s]+)#", "?");
39     ResultSetHandler<E> rsh = getResultSetHandler();
40     // 执行SQL获取返回对象
41     E e = (E) qr.query(conn, sql, rsh, l.toArray());
42     return e;
43 } catch (SQLException e1) {
44     throw new RuntimeException(e1.getMessage(), e1);
45 }
View Code

 

4、其他方法

execute(String sqlId, Object... args)方法

根据指定sqlId从模板中获取SQL执行,此方法不支持动态SQL解析。通常用于执行一些维护关联关系的添加、更新和删除语句。

 1 protected boolean execute(String sqlId, Object... args) {
 2     QueryRunner qr = new QueryRunner();
 3     try {
 4         Connection conn = TransactionManager.getConnection();
 5         // 获取SQL模板
 6         String sql = this.sqlParser.parseSql(sqlId, null, false);
 7         return qr.update(conn, sql, args) > 0;
 8     } catch (SQLException e1) {
 9         throw new RuntimeException(e1.getMessage(), e1);
10     }
11 }

 

selectColumn(String sqlId, Map<String, Object> paramaters)方法

根据指定sqlId从模板中获取SQL,使用Map为查询条件赋值,返回某一列数据的集合。通常可以用于执行获取countsum值的语句。

 1 protected <T> List<T> selectColumn(String sqlId, Map<String, Object> paramaters) {
 2     QueryRunner qr = new QueryRunner();
 3     try {
 4         Connection conn = TransactionManager.getConnection();
 5 
 6         // 保存全部注入参数
 7         List<Object> l = new ArrayList<Object>();
 8 
 9         // 获取SQL模板
10         String sql = this.sqlParser.parseSql(sqlId, paramaters, true);
11 
12         // 匹配SQL中待赋值的参数
13         Matcher m = argPattern.matcher(sql);
14         while (m.find()) {
15             String arg = m.group(1);
16             Object val = paramaters.get(arg);
17             if (val instanceof List) {
18                 StringBuilder sb = new StringBuilder();
19                 List v = (List) val;
20                 int iMax = v.size() - 1;
21                 for (int i = 0;; i++) {
22                     sb.append("?");
23                     l.add(v.get(i));
24                     if (i == iMax) {
25                         break;
26                     }
27                     sb.append(", ");
28                 }
29                 sql = sql.replace("#" + arg + "#", sb.toString());
30             } else {
31                 l.add(val);
32             }
33         }
34         sql = sql.replaceAll("#([^\\s]+)#", "?");
35         // 执行SQL获取返回指定列的集合
36         return qr
37                 .query(conn, sql, new ColumnListHandler<T>(1), l.toArray());
38     } catch (SQLException e1) {
39         throw new RuntimeException(e1.getMessage(), e1);
40     }
41 }
View Code

 

selectColumns(String sqlId, Map<String, Object> paramaters)方法

selectColumn方法类似,不做介绍了

 

5、获取ResultSetHandler对象

以下两个方法用于获取解析结果集的ResultSetHandler对象,如果子类需要使用不同的方式解析ResultSet就要重写这两个方法

1 protected ResultSetHandler<E> getResultSetHandler() {
2     return new BeanHandler<E>(this.entityClass);
3 }
4 
5 protected ResultSetHandler<List<E>> getResultSetListHandler() {
6     return new BeanListHandler<E>(this.entityClass);
7 }

 

posted @ 2018-08-18 14:36  用户不存在!  阅读(532)  评论(0编辑  收藏  举报