spring事物配置,声明式事务管理和基于@Transactional注解的使用
 https://blog.csdn.net/bao19901210/article/details/41724355

事物管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的一致性。

spring支持编程式事务管理和声明式事务管理两种方式。

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

spring事务特性

spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

其中TransactionDefinition接口定义以下特性:

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
    TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
    TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
    TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
    TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
    TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
    TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
    TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

事务只读属性

只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。
默认为读写事务。

“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。

但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。

因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可

spring事务回滚规则

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

myBatis为例   基于注解的声明式事务管理配置@Transactional

spring.xml

<span style="background-color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 204, 153);"><!-- mybatis config -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="configLocation">
                <value>classpath:mybatis-config.xml</value>
            </property>
        </bean>
        
        <!-- mybatis mappers, scanned automatically -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage">
                <value>
                    com.baobao.persistence.test
                </value>
            </property>
            <property name="sqlSessionFactory" ref="sqlSessionFactory" />
        </bean>
        
        <!-- 配置spring的PlatformTransactionManager,名字为默认值 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        
        <!-- 开启事务控制的注解支持 -->
        <tx:annotation-driven transaction-manager="transactionManager"/></span></span>

添加tx名字空间

<span style="background-color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 204, 153);">xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
     
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"</span></span>

MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。

@Transactional注解

@Transactional属性
属性     类型     描述
value     String     可选的限定描述符,指定使用的事务管理器
propagation     enum: Propagation     可选的事务传播行为设置
isolation     enum: Isolation     可选的事务隔离级别设置
readOnly     boolean     读写或只读事务,默认读写
timeout     int (in seconds granularity)     事务超时时间设置
rollbackFor     Class对象数组,必须继承自Throwable     导致事务回滚的异常类数组
rollbackForClassName     类名数组,必须继承自Throwable     导致事务回滚的异常类名字数组
noRollbackFor     Class对象数组,必须继承自Throwable     不会导致事务回滚的异常类数组
noRollbackForClassName     类名数组,必须继承自Throwable     不会导致事务回滚的异常类名字数组

用法

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

@Autowired
        private MyBatisDao dao;
        
        @Transactional
        @Override
        public void insert(Test test) {
            dao.insert(test);
            throw new RuntimeException("test");//抛出unchecked异常,触发事物,回滚
        }

noRollbackFor

@Transactional(noRollbackFor=RuntimeException.class)
        @Override
        public void insert(Test test) {
            dao.insert(test);
            //抛出unchecked异常,触发事物,noRollbackFor=RuntimeException.class,不回滚
            throw new RuntimeException("test");
        }

类,当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性

@Transactional
    public class MyBatisServiceImpl implements MyBatisService {
     
        @Autowired
        private MyBatisDao dao;
        
        
        @Override
        public void insert(Test test) {
            dao.insert(test);
            //抛出unchecked异常,触发事物,回滚
            throw new RuntimeException("test");
        }

propagation=Propagation.NOT_SUPPORTED

@Transactional(propagation=Propagation.NOT_SUPPORTED)
        @Override
        public void insert(Test test) {
            //事物传播行为是PROPAGATION_NOT_SUPPORTED,以非事务方式运行,不会存入数据库
            dao.insert(test);
        }

myBatis为例   基于注解的声明式事务管理配置,xml配置

主要为aop切面配置,只看xml就可以了

<!-- 事物切面配置 -->
        <tx:advice id="advice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
                <tx:method name="insert" propagation="REQUIRED" read-only="false"/>
            </tx:attributes>
        </tx:advice>
        
        <aop:config>
            <aop:pointcut id="testService" expression="execution (* com.baobao.service.MyBatisService.*(..))"/>
            <aop:advisor advice-ref="advice" pointcut-ref="testService"/>
        </aop:config>>

spring 事务注解配置以及实践

2017年04月19日 16:15:49 wive 阅读数:532

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/curiouslearnerdhh/article/details/70241700

参考文章:原文链接

事务隔离级别:

隔离级别所要解决的问题是在应用程序中,存在多个事务同时在运行时,需要解决和处理好的问题!
脏读(dirty read)  
         一个事物更新了数据库中的某些数据,另一个事物读取了这些数据,这时前一个事物由于某些原因回滚了,那么第二个事物读取的数据就是“脏数据” 
不可重复读(non-repeatable read)
         一个事物两次查询同一数据,但两次查询中间可能有另外一个事物更改了这个数据,导致前一个事物两次读出的数据不一致。
幻读 (phantom read)
         一个事物两次查询同一个表,但两次查询中间可能有另外一个事物又向这个表中插入了一些新数据,导致前一个事物的两次查询不一致

Spring中@Transactional中Isolation有具备的值:

DEFAULT  使用各个数据库默认的隔离级别
 Read Uncommited :读未提交数据( 会出现脏读,不可重复读,幻读)
 Read Commited :读已提交的数据(会出现不可重复读,幻读)
 Repeatable Read :可重复读(会出现幻读)
 Serializable :串行化

注意:
如果开启了bin-log日志,配置Read Uncommited或者Read Commited会报错:
Caused by: java.sql.SQLException: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT 
and at least one table uses a storage engine limited to row-based logging. 
InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.

原因:mysql默认的binlog_format是STATEMENT,而在READ COMMITTED或READ UNCOMMITTED隔离级别下,innodb只能使用的binlog_format是ROW

事务的配置:

web.xml中:

 
  1. <!-- Spring为我们提供的OpenSessionInViewFilter过滤器,主要功能是用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定

  2. 目的是为了实现"Open Session in View"的模式。例如: 它允许在事务提交之后延迟加载显示所需要的对象-->

  3. <filter>

  4. <filter-name>Spring OpenSessionInViewFilter</filter-name>

  5. <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>

  6. <init-param>

  7. <!-- 指定org.springframework.orm.hibernate3.LocalSessionFactoryBean在spring配置文件中的名称,默认值为sessionFactory

  8. 如果LocalSessionFactoryBean在spring中的名称不是sessionFactory,该参数一定要指定,否则会出现找不到sessionFactory的例外 -->

  9. <param-name>sessionFactoryBeanName</param-name>

  10. <param-value>sessionFactory</param-value>

  11. </init-param>

  12. </filter>

  13. <filter-mapping>

  14. <filter-name>Spring OpenSessionInViewFilter</filter-name>

  15. <url-pattern>/*</url-pattern>

  16. </filter-mapping>

ApplicationContext.xml配置:

 
  1. <!-- =============================== 事务管理 ================================== -->

  2. <!--配置事务管理器-->

  3. <bean id ="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

  4. <!-- 注入sessionFactory-->

  5. <property name="sessionFactory" ref="sessionFactory"></property>

  6. </bean>

  7. <!--开启事务注解-->

  8. <tx:annotation-driven transaction-manager="transactionManager"/>

重点以及感悟:

1、使用误区:
无论在service层或者dao层调用,session对象获得都是sessionFactory.getCurrentSession();
userDao调用不同的方法,如:userDao.save(user);   userDao.update(user);  用到的session对象是同一个(得到的session用hashcode打印出来,可以看出是一个对象)

事务起不起作用,一个注意点:
用@Transaction的方法必须抛出运行时异常。这样方法里面的代码才可能被回滚。
如果方面里面被try catch处理了,将不能抛出异常,那么即使有运行时异常也被catch处理了,所以就不能回滚了,

错误实例:

 
  1. @Transactional

  2. @Override

  3. public void batchAdd() throws Exception {

  4. try {

  5. User user = new User();

  6. user.setName("dhh");

  7. user.setPassword("xxxxxx");

  8. user.setSex("男");

  9. user.setTimetag(new Date());

  10. this.save(user); //写库处理,和下面的逻辑要事务处理

  11. Thread.sleep(5000);

  12. int i = 5/0; //另外的写库处理,模拟异常

  13. System.out.println(i);

  14. } catch (Exception e) { //异常被catch了,不能抛出异常,将不能回滚

  15. e.printStackTrace();

  16. }

  17. }

个人思路:事务操作最好放到dao层处理,异常集中到service层处理,所以service最好别抛抛异常给controller

2、@Transactional之value
value这里主要用来指定不同的事务管理器;主要用来满足在同一个系统中,存在不同的事务管理器。
比如在Spring中,声明了两种事务管理器txManager1, txManager2.

然后,用户可以根据这个参数来根据需要指定特定的txManager.

那有同学会问什么情况下会存在多个事务管理器的情况呢? 
 比如在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的。

3、Propagation支持7种不同的传播机制:
REQUIRED
     业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务.这是spring默认的传播行为.。 
SUPPORTS:  
     如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
 MANDATORY:
     只能在一个已存在事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,就抛异常
 REQUIRES_NEW
     业务方法总是会为自己发起一个新的事务,如果方法已运行在一个事务中,则原有事务被挂起,新的事务被创建,直到方法结束,新事务才结束,原先的事务才会恢复执行.
 NOT_SUPPORTED
     声明方法需要事务,如果方法没有关联到一个事务,容器不会为它开启事务.如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行.
NEVER:
     声明方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常.只有没关联到事务,才正常执行.
 NESTED:
     如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动的事务,则按REQUIRED属性执行.它使用了一个单独的事务, 
     这个事务拥有多个可以回滚的保证点.内部事务回滚不会对外部事务造成影响, 它只对DataSourceTransactionManager 事务管理器起效.

3、使用范围:
@Transactional写在类前,那么所有的方法,都具有事务特性,
如果某个方法不需要propagation=Propagation.NOT_SUPPORTED

 
  1. @Transactional(value="transactionManager",propagation=Propagation.NOT_SUPPORTED,isolation=Isolation.REPEATABLE_READ)

  2. @Override

  3. public void batchAdd() throws Exception {

  4. }

具体Transaction有哪些参数,以及值怎么填写,打开源码就一清二楚了!!!

4、想法验证:
我之前想在dao的基类中定义@Repository
那么继承这个基类的dao方法都继承这个变量,经过检验,是行不通
同理,在接口上定义@Repository
也是行不通的

编程式事务管理使用Transaction相关推荐

  1. 全面分析 Spring 的编程式事务管理及声明式事务管理(转)

    摘要 Spring 的事务管理是 Spring 框架中一个比较重要的知识点,该知识点本身并不复杂,只是由于其比较灵活,导致初学者很难把握.本教程从基础知识开始,详细分析了 Spring 事务管理的使用 ...

  2. 全面分析 Spring 的编程式事务管理及声明式事务管理--转

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

  3. Spring中两种编程式事务管理

    Spring中两种编程式事务管理 在代码中显示调用beginTransaction,commit,rollback等与事务处理相关的方法,这就是编程式事务管理,当只有少数事务操作时,编程式事务管理才比 ...

  4. 编程式事务管理(详解)

    第一章:编程式事务管理(详解) 1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模板类即可!! 2. 手 ...

  5. 全面分析 Spring 的编程式事务管理及声明式事务管理

    转自:http://www.open-open.com/lib/view/open1414310646012.html 关于本教程 本教程将深切讲授 Spring 庞杂而丁壮夜的事务治理功用,包括编程 ...

  6. java 编程式事务管理_spring-编程式事务管理

    一.创建spring项目 项目名称:spring101310 二.在项目上添加jar包 1.在项目中创建lib目录 /lib 2.在lib目录下添加spring支持 com.springsource. ...

  7. Spring的4种事务管理(1种编程式事务+三种声明事务)

    2019独角兽企业重金招聘Python工程师标准>>> Spring的4种事务管理(1种编程式事务+三种声明事务) 一.Spring事务的介绍 二.编程式事务xml的配置 注入后直接 ...

  8. Spring事务处理之 编程式事务 和 声明式事务

    对事务概念还不了解的可以先看一下 MySQL事务管理(初步了解) 这篇文章 !!! Spring事务管理学习步骤: 1.掌握Spring事务属性 2.掌握Spring事务核心API 3.掌握Sprin ...

  9. java编程式事务_Spring编程式和声明式事务实例讲解

    Spring事务管理 Spring支持两种方式的事务管理: 编程式事务管理: 通过Transaction Template手动管理事务,实际应用中很少使用, 使用XML配置声明式事务: 推荐使用(代码 ...

  10. Spring事务管理2----编程式事务管理

    编程式事务管理 通过使用将Spring框架提供的TransactionTemplate模板注入到业务层来进行事务管理,这样对业务层原来的代码修改过多.不利于项目的后期维护. 以下是声明式事务管理的具体 ...

最新文章

  1. Collection 和 Collections区别
  2. linux重定向命令是干嘛的,Linux系统下重定向命令应用及其语法有什么?
  3. win7装postgresql10.4
  4. 组织架构递归_映射架构和递归管理数据–第2部分
  5. mysql5.7编译安装
  6. OCR文字识别技术总结(二)
  7. Eclipse编译去除svn文件夹
  8. C++实现包含空格、标点、字符、数字的字符串的逆序输出,并且还可以实现一句语言中每个单词的倒序输出
  9. linux中最常用命令
  10. IE 9 beta 下载地址
  11. no ip domain-lookup 是什么意思?
  12. 基于SSM超越宠物医院诊治系统
  13. 永磁直驱风力发电机组并网仿真模型搭建
  14. 【shell】【sed】在行前/行后插入一新行
  15. 一次控制文件control file sequential read 等待性能案例分析
  16. fractions -- 分数
  17. 中国房价必跌的40个理由
  18. java runnable执行完_java – 如何停止Runnable计划在一定数量的执行后重复执行
  19. C++连接MySQL
  20. Android内存泄漏情况总结

热门文章

  1. 模拟ic学习笔记(拉扎维)--第二节单级放大器
  2. Michael.W谈密码学-密码学相关基础知识 第一期
  3. Cell子刊:建立因果关系-合成群落在植物菌群研究中的机会
  4. 各种语系的简称(判断浏览器是中文版还是英文版)
  5. 如何在不重装win10系统的情况下将intel主板的RAID设置改为ACHI设置
  6. TLS1.3中文版上(RFC8446)(注:本文有错误但无法修改,正确的见后来文章)
  7. (二)基于阿里云的MQTT远程控制(购买阿里云,在云端安装MQTT,测试MQTT远程通信)
  8. OSPF网络类型_亮仔_新浪博客
  9. Pytorch中autograd.Variable.backward的grad_varables参数个人理解浅见
  10. 元宇宙 Metaverse | Vol.1 术语解释