动态SQL数据层框架(2):框架结构
这是一个简单的数据层框架,可以实现动态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事务管理
1、BaseDao接口
定义了最基础的实体增删改查方法。
其中查询有以下方式:
- 根据id查询一个实体对象
- 根据Map条件查询一个实体对象
- 查询全部实体对象
- 根据Map条件查询实体对象集合
- 根据Map条件、页码、数据量查询实体对象集合
- 根据Map条件查询数据量
1 public interface BaseDao<E> { 2 int addObject(E e); 3 boolean deleteObject(Integer id); 4 boolean updateObject(E e); 5 E getObject(Integer id); 6 E getObject(Map<String, Object> paramaters); 7 List<E> getObjects(); 8 List<E> getObjects(Map<String, Object> paramaters); 9 List<E> getObjects(Map<String, Object> params, Integer num,Integer size); 10 int count(Map<String, Object> paramaters); 11 }
2、BaseDaoSupport类
该类实现了BaseDao接口。
使用DBUtils进行JDBC操作,使用DynamicSQLParser进行动态SQL解析,核心方法实现过程如下:
addObject方法,首先使用DynamicSQLParser获取SQL,然后使用反射技术从参数对象中获取需要注入到SQL中参数,并封装为集合,最后执行SQL。
deleteObject方法,首先使用DynamicSQLParser获取SQL,传入id参数后即执行SQL。
updateObject方法,和addObject方法类似。
getObject(int)方法,首先使用DynamicSQLParser获取SQL,不需要动态解析,然后获取一下ResultSetHandler,子类可以重写getResultSetHandler()进行自定义,传入id参数后即执行SQL并返回结果。
getObject(Map)方法,首先使用DynamicSQLParser获取SQL,需要根据Map条件进行动态解析,然后从Map中获取注入到SQL中参数,并封装为集合,获取一下ResultSetHandler,子类可以重写getResultSetHandler()进行自定义,最后执行SQL并返回结果。
getObjects、getObjects(Map)、getObjects(Map, int, int)、count(Map)等方法获取SQL注入参数的过程和上面一样,只是结果集封装稍有区别。
除了实现BaseDao接口中的方法之外,这个类还定义了其他方法:
execute(String sqlId, Object... args)方法根据指定sqlId从模板中获取SQL执行,此方法不支持动态SQL解析。
selectColumn(String sqlId, Map<String, Object> paramaters)方法根据指定sqlId从模板中获取SQL,使用Map为查询条件赋值,返回一列数据的集合。
selectColumns(String sqlId, Map<String, Object> paramaters)方法根据指定sqlId从模板中获取SQL,使用Map为查询条件赋值,返回多列数据Map的集合。
getResultSetHandler()和getResultSetListHandler()方法子类可以重写这两个方法自定义结果集的封装方式。
3、DynamicSQLParser类
动态SQL解析工具,里面会涉及到XML解析和freemarker模板框架。
我们使用XML文件配置SQL。
dynamic-sql.xml是主配置文件,配置实体sql文件存放路径。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE dynamic-sql SYSTEM "dynamic-sql.dtd"> 3 <files> 4 <file path="org/net5ijy/dao/sql/employee.xml"></file> 5 <file path="org/net5ijy/dao/sql/department.xml"></file> 6 <file path="org/net5ijy/dao/sql/student.xml"></file> 7 <file path="org/net5ijy/dao/sql/teacher.xml"></file> 8 </files>
employee.xml是实体sql配置文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE sql SYSTEM "sql.dtd"> 3 <sqls> 4 5 <!-- SQL for Employee --> 6 7 <sql id="Employee_addObject"> 8 <![CDATA[ 9 insert into base_dao_employee 10 (name, gender, salary, phone, email, birthday, join_date, create_time, department_id) 11 values 12 (#name#, #gender#, #salary#, #phone#, #email#, #birthday#, #joinDate#, #createTime#, #departmentId#) 13 ]]> 14 </sql> 15 <sql id="Employee_updateObject"> 16 <![CDATA[ 17 update base_dao_employee set 18 name = #name#, gender = #gender#, salary = #salary#, phone = #phone#, email = #email#, 19 birthday = #birthday#, join_date = #joinDate#, department_id = #departmentId#, version = version+1 20 where id = #id# and version = #version# 21 ]]> 22 </sql> 23 24 <sql id="Employee_getObject_int"> 25 <![CDATA[ 26 select 27 id, name, gender, salary, phone, email, birthday, join_date as joinDate, 28 create_time as createTime, department_id as departmentId, version 29 from base_dao_employee where id = ? 30 ]]> 31 </sql> 32 33 ...... 34 35 </sqls>
解析配置文件分为两步:
- 加载dynamic-sql.xml获取实体配置文件位置
- 逐一解析实体配置文件把SQL模板加载到Freemarker的Template缓存中去
这个类使用单例模式,对外提供parseSql方法对指定id的SQL进行动态解析。
4、TransactionManager类
这是一个工具类,用于获取、关闭连接,开启、回滚、提交事务。
首先,这个类使用ThreadLocal把当前线程和一个数据库Connection绑定在一起。
在使用getConnection()方法获取连接时,先在ThreadLocal中获取,如果没有才调用DBCPUtil的getConnection()方法获取连接,绑定到ThreadLocal之后再返回连接对象。
其余的startTransacation()、commit()、rollback()、close()等方法也是针对当前线程绑定的Connection进行操作。
5、@Transactional注解、BeanFactory工厂和动态代理工具
@Transactional注解标注在需要使用事务的业务层类和方法上。
我们使用BeanFactory实例化、管理全局的DAO和Service对象,在实例化bean对象、依赖注入完成之后,会再次扫描BeanFactory中的对象,如果某个对象所属类标注了@Transactional注解,会使用Cglib创建这个对象的动态代理对象,然后再存放到工厂中。
工厂使用的配置文件是beans.properties
## 接口名 = 实现类全名 AccountDao=org.net5ijy.aop.dao.jdbc.AccountDaoImpl AccountService=org.net5ijy.aop.service.impl.AccountServiceImpl
这个动态代理对象的作用就是在业务层方法调用之前获取一个数据库Connection绑定到当前线程上,如果要执行的方法也标注了@Transactional注解,会开启事务,方法执行之后会提交事务,出现异常会回滚事务,最后在finally中会关闭数据库连接。
动态代理对象的创建提供了两种方式:一种是JDK自带的Proxy方式;一种是cglib动态代理。
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号