Foxnic-SQL (11) —— DAO 个性 : 事务管理
概述
事务管理是任何一个数据层工具所必须的,Foxnic-SQL 既然是基于 Spring JDBC 的天然默认就反对 @Transactional 注解,另外 Foxnic-SQL 的 DAO 对象还反对手动事务。
本文中的示例代码均可在 https://gitee.com/LeeFJ/foxnic-samples 我的项目中找到。
手动事务
手动事务通过 DAO 对象的 beginTransaction() 办法、commit() 办法、rollback() 办法实现,上面是一个手动事务的例子:
public class DAO_ManualTransactionDemo { public static void main(String[] args) { demo1(true); demo1(false); } /*** 1、查问不分页记录集* */ public static void demo1(boolean exp) { // 通过 DBInstance 拿到 DAO 对象 DAO dao=DBInstance.DEFAULT.dao(); String id = null; try { // 启动事务 dao.beginTransaction(); System.out.println("开始事务"); // 插入数据 id=insertAddress(dao,"13777-"+exp); if(exp) { throw new RuntimeException("模仿异样"); } // 提交 dao.commit(); System.out.println("提交事务"); } catch (Exception e) { // 回滚 dao.rollback(); System.out.println("回滚事务"); } Rcd address=queryAddress(dao,id); if(address==null) { System.out.println("数据未插入"); } else { System.out.println("数据已插入"); } } /*** 插入数据* */ public static String insertAddress(DAO dao,String phone) { // 创立语句对象 Insert insert=new Insert("example_address"); String id= IDGenerator.getSnowflakeIdString(); // 设置值 insert.set("id",id) .set("name","leefj") // 如果是 null 则不连入SQL语句 .setIf("phone_number",phone) .set("address","宁波") .set("region_type","国内") .set("create_time",new Date()) // 设置数据库表达式 .setExpr("update_time","now()"); // 输入语句 System.out.println(insert.getSQL()); // 执行语句 Integer suc=dao.execute(insert); // 如果执行胜利,返回ID,否则返回 null if(suc==1) { return id; } else { return null; } } /*** 查问* */ public static Rcd queryAddress(DAO dao,String id) { // 创立语句对象 Select select=new Select("example_address"); // 设置值 select.where().and("id=?",id); // 输入语句 System.out.println(select.getSQL()); // 执行语句 Rcd address=dao.queryRecord(select); // 如果执行胜利,返回记录对象,否则返回 null return address; }}
主动事务
主动事务的前提是被注解 @Transactional 的对象须要是 Spring 容器治理的 Bean。所以主动事务通常会在 Web 利用中应用。主动事务须要首先定义数据源和事务管理器,并将两者绑定,如下代码所示:
@Configuration public class DatasourceConfig { public static final String PRIMARY_DATASOURCE_CONFIG_KEY = "spring.datasource.druid.primary"; public static final String PRIMARY_DATA_SOURCE_NAME = "primaryDataSource"; @Bean(name = PRIMARY_DATA_SOURCE_NAME) @ConfigurationProperties(PRIMARY_DATASOURCE_CONFIG_KEY) public DruidDataSource primaryDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean @Primary public DataSourceTransactionManager primaryTransactionManager( @Qualifier(PRIMARY_DATA_SOURCE_NAME) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
@Transactional注解
如果须要更高级的事务管制,则应用@Transactional注解,@Transactional 注解尽管不便地实现事务托管,然而还是有很多中央须要留神的,上面咱们来理解一下在应用@Transactional注解时须要留神的点。
1、多数据源时需指定事务管理器名称;
2、Spring事务是通过ThreadLocal类来实现,所以只有主线程有事务管理,一个线程一个事务。
3、@Transactiona 注解须要事务管理器反对,若无事务管理器反对,则不失效。
4、@Transactional 注解可用于接口定义、接口办法、类定义、类public办法四个地位,非public办法事务不失效。
5、Spring事务管制是基于AOP的,请明确代理类型。proxy-target-class=true时,应用cglib的基于类的代理;proxy-target-class=false时,应用JDK的基于接口的代理。基于上述情况,@Transactional 注解倡议放到类定义或类办法上。
6、如果类定义中无 @Transactional 注解,它的办法A无 @Transactional 注解,但办法B有 @Transactional 注解,此时若在同一个类中,由A调用B,则B上的事务有效。如果类定义中有@Transactional注解,则它的办法,无论有无 @Transactional 注解,事务均无效。总之,如果要使事务无效,调用时进入类的第一个类办法必须有 @Transactional 注解。
7、Spring 应用申明式事务处理,默认状况下, 如果被注解的数据库操作方法中产生了 unchecked 异样(编译器不查看的异样,如 RuntimeException),所有的数据库操作将 rollback;如果产生的异样是 checked 异样(编译器查看,须要用try cathch 捕捉解决的异样,如 Exception),默认状况下数 据库操作还是会提交的。当然也可在 @Transactional 注解中指定回滚的异样类型。
上面是应用 @Transactional 事务托管的几个示例:
@Transactional(AppDAO.TRANSACTION_MANAGER)public String te1(String act) throws Exception{ if(act==null) act="none"; dao.execute("update trans set name=? where code='119'",act+":"+System.currentTimeMillis()); if(act.equals("checked")) { //事务不回滚 throw new Exception("异样"); } if(act.equals("unchecked")) { //事务回滚 throw new RuntimeException("异样"); } return "OK";}
变更默认的回滚异样,指定回滚或不回滚的异样类型:
@Transactional(transactionManager=AppDAO.TRANSACTION_MANAGER,rollbackFor= {Exception.class},noRollbackFor= {RuntimeException.class})public String te2(String act) throws Exception{ if(act==null) act="none"; dao.execute("update trans set name=? where code='119'",act+":"+System.currentTimeMillis()); if(act.equals("checked")) { //事务回滚 throw new Exception("异样"); } if(act.equals("unchecked")) { //事务不回滚 throw new RuntimeException("异样"); } return "OK";}
事务流传
Spring 的事务的流传行为,默认值为 Propagation.REQUIRED。 可选的值有:
1、Propagation.REQUIRED:如果以后存在事务,则退出该事务,如果以后不存在事务,则创立一个新的事务。
2、Propagation.SUPPORTS:如果以后存在事务,则退出该事务;如果以后不存在事务,则以非事务的形式持续运行。
3、Propagation.MANDATORY:如果以后存在事务,则退出该事务;如果以后不存在事务,则抛出异样。
4、Propagation.REQUIRES_NEW:从新创立一个新的事务,如果以后存在事务,暂停以后的事务。
5、Propagation.NOT_SUPPORTED:以非事务的形式运行,如果以后存在事务,暂停以后的事务。
6、Propagation.NEVER:以非事务的形式运行,如果以后存在事务,则抛出异样。
7、Propagation.NESTED:和 Propagation.REQUIRED 成果一样。
事务隔离
isolation 属性,事务的隔离级别,默认值为 Isolation.DEFAULT。可选的值有:
1、Isolation.DEFAULT:应用底层数据库默认的隔离级别。MYSQL:默认为 REPEATABLE_READ 级别;SQLSERVER:默认为 READ_COMMITTED 级别;Oracle:默认为 READ_COMMITTED 级别。
2、Isolation.READ_UNCOMMITTED
3、Isolation.READ_COMMITTED
4、Isolation.REPEATABLE_READ
5、Isolation.SERIALIZABLE
其它参数
1、timeout 属性:事务的超时工夫,默认值为-1。如果超过该工夫限度但事务还没有实现,则主动回滚事务。
2、readOnly 属性:指定事务是否为只读事务,默认值为 false;为了疏忽那些不须要事务的办法,比方读取数据,能够设置 read-only 为 true。
小结
本节次要介绍了在 Foxni-SQL 中的事务管理,包含了手动事务个 Spring 托管的主动事务。在应用主动事务时要留神本文中提到的针对 @Transactional 注解应用的注意事项。
相干我的项目
https://gitee.com/LeeFJ/foxnic
https://gitee.com/LeeFJ/foxnic-web
https://gitee.com/lank/eam
https://gitee.com/LeeFJ/foxnic-samples
官网文档
http://foxnicweb.com/docs/doc.html