Foxnic-SQL (11) —— DAO 特性 : 事务管理

LeeFJ
• 阅读 406

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

点赞
收藏
评论区
推荐文章
Easter79 Easter79
3年前
springboot+mybatis 使用事务
一、一些概念声明式的事务管理是基于AOP的,在springboot中可以通过@Transactional注解的方式获得支持,这种方式的优点是:1)非侵入式,业务逻辑不受事务管理代码的污染。2)方法级别的事务回滚,合理划分方法的粒度可以做到符合各种业务场景的事务管理。本文使用目前最常用的mybatis框架来配置springboot的事务
Easter79 Easter79
3年前
spring事物管理之传播行为和隔离级别
大家在使用spring的注解式事务管理时,对事务的传播行为和隔离级别可能有点不知所措,下边就详细的介绍下以备方便查阅。事物注解方式:@Transactional当标于类前时,表示类中所有方法都进行事物处理例子:@TransactionalpublicclassTestServiceBeanimplementsTest
Easter79 Easter79
3年前
springboot2.x如何添加事务
什么时候需要添加事务呢?一般情况下,如果该方法有两条SQL语句或者以上都需要添加(个人感觉:)).首先需要在我们的启动类加上@EnableTransactionManagement//开启事务管理接着我们在需要添加事务的方法上加上@Transactional(propagationPropagati
Wesley13 Wesley13
3年前
@Transactional 回滚不生效原因
事务的管理方式有两种,第一种是编程式事务管理,需要将数据库的自动提交等取消,并且需要自己编写事务代码,第二种则是声明式事务管理模式,spring利用springAOP特性编写了注解即题目中所提到的方式来管理事务,避免开发人员编写大量的事务代码。一、特性先来了解一下@Transactional注解的特性吧,可以更好排查问题1\.service类
Wesley13 Wesley13
3年前
@Transactional注解失效的解决方案
一、前言  开发中我们经常使用@Transactional注解来启用Spring事务管理,但是如果使用方法不当,会遇到注解不生效该事务回滚的地方却没有回滚的问题。总结下一般是以下几个原因:1.@Transactional注解只能应用到public可见度的方法上。如果应用在protected、private或者p
Wesley13 Wesley13
3年前
Spring声明式事务注解@Transactional
spring支持编程式事务管理和声明式事务管理两种方式。编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创
LeeFJ LeeFJ
2年前
Foxnic-SQL (5) —— 创建与初始化DAO
DAO对象是FoxnicSQL执行语句并返回结果的核心对象。它包含了众多方法,包括语句的执行、查询、序列、存储过程,元数据等。本文中的示例代码均可在https://gitee.com/LeeFJ/foxnicsamples项目中找到。
LeeFJ LeeFJ
2年前
Foxnic-SQL (6) —— DAO 特性 : 基本信息与元数据
DAO对象创建后就可以使用DAO对象了,DAO最基本的特性就是获取数据库的一些基础信息,这些信息有利于开发者在某些场景下做出正确的判断。本文中的示例代码均可在https://gitee.com/LeeFJ/foxnicsamples项目中找到。
LeeFJ LeeFJ
2年前
Foxnic-SQL (7) —— DAO 特性 : 执行 SQL 语句
FoxnicSQL支持多种语句执行方式,包括直接执行SQL字符串、执行SQL对象,SQL对象自执行,多语句执行与批量执行。FoxnicSQL显著的特征是DAO对象既可以执行字符串的SQL语句,也可以执行对象化的SQL语句。
LeeFJ LeeFJ
2年前
Foxnic-SQL (8) —— DAO 特性 : 数据查询
FoxnicSQL的DAO对象包含了非常丰富的查询功能,可以查询记录、数据实体(Po对象)、单值。针对不同的数据库DAO对象已经实现了默认的分页功能。DAO中所有的查询方法都支持SQL字符串查询、SQL对象查询。下面我们来具体看一下这些功能。