转自 https://blog.csdn.net/zht741322694/article/details/78676964

一、spring支持的事务声明方式
1.  编程式事务  当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务。

2.  声明式事务  当系统对于事务的控制粒度较粗时,应该选择申明式事务,通过<tx>标签和<aop>切面形式在xml中进行配置。

3.  无论你选择上述何种事务方式去实现事务控制,spring都提供基于门面设计模式的事务管理器供选择,如下是spring事务中支持的事务管理器

事务管理器实现(org.springframework.*)

使用时机

jdbc.datasource.DataSourceTransactionManager

使用jdbc的抽象以及ibatis支持

orm.hibernate.HibernateTransactionManager

使用hibernate支持(默认3.0以下版本)

orm.hibernate3.HibernateTransactionManager

使用hibernate3支持

transaction.jta.JtaTransactionManager

使用分布式事务(分布式数据库支持)

orm.jpa.JpaTransactionManager

使用jpa做为持久化工具

orm.toplink.TopLinkTransactionManager

使用TopLink持久化工具

orm.jdo.JdoTransactionManager

使用Jdo持久化工具

jms.connection.JmsTransactionManager

使用JMS 1.1+

jms.connection.JmsTransactionManager102

使用JMS 1.0.2

transaction.jta.OC4JJtaTransactionManager

使用oracle的OC4J JEE容器

transaction.jta.WebLogicJtaTransactionManager

在weblogic中使用分布式数据库

jca.cci.connection.CciLocalTransactionManager

使用jrping对J2EE Connector Architecture (JCA)和Common Client Interface (CCI)的支持

配置示例如下:

<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<propertyname="dataSource" ref="dataSource"/>  //引入数据源

</bean>

二、spring支持7种事务传播行为

传播行为

含义

propagation_required(xml文件中为required)

表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)

propagation_supports(xml文件中为supports)

表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行

propagation_mandatory(xml文件中为mandatory)

表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常

propagation_nested(xml文件中为nested)

表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation_required的一样

propagation_never(xml文件中为never)

表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常

propagation_requires_new(xml文件中为requires_new)

表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

propagation_not_supported(xml文件中为not_supported)

表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行

三、spring中的事务隔离级别

隔离级别

含义

isolation_default

使用数据库默认的事务隔离级别

isolation_read_uncommitted

允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读

isolation_read_committed

允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生

isolation_repeatable_read

对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改。可防止脏读和不可重复读,但幻读仍有可能发生

isolation_serializable

完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。

脏读、不可重复读、幻象读概念说明:
a.脏读:指当一个事务正字访问数据,并且对数据进行了修改,而这种数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。
b.不可重复读:指在一个事务内,多次读同一数据。在这个事务还没有执行结束,另外一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,由于第二个事务的修改第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事物内两次连续读到的数据是不一样的,这种情况被称为是不可重复读。
c.幻象读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中)

四、spring事务只读属性
   spring事务只读的含义是指,如果后端数据库发现当前事务为只读事务,那么就会进行一系列的优化措施。它是在后端数据库进行实施的,因此,只有对于那些有可能启动一个新事务的传播行为(REQUIRED,REQUIRES_NEW,NESTED)的方法来说,才有意义。(测试表明,当使用JDBC事务管理器并设置当前事务为只读时,并不能发生预期的效果,即能执行删除,更新,插入操作)

五、spring的事务超时
   有的时候为了系统中关键部分的性能问题,它的事务执行时间应该尽可能的短。因此可以给这些事务设置超时时间,以秒为单位。我们知道事务的开始往往都会发生数据库的表锁或者被数据库优化为行锁,如果允许时间过长,那么这些数据会一直被锁定,影响系统的并发性。

因为超时时钟是在事务开始的时候启动,因此只有对于那些有可能启动新事物的传播行为(REQUIRED,REQUIRES_NEW,NESTED)的方法来说,事务超时才有意义。

六、事务回滚规则
   spring中可以指定当方法执行并抛出异常的时候,哪些异常回滚事务,哪些异常不回滚事务。默认情况下,只在方法抛出运行时异常的时候才回滚(runtime exception)。而在出现受阻异常(checked exception)时不回滚事务。当然可以采用申明的方式指定哪些受阻异常像运行时异常那样指定事务回滚。

七、单个方法的事务传播机制(注意这里说的是单个方法)
1、整备工作: spring申明式事务配置,将aop,tx命名空间添加到当前的spring配置文件头中,这里不在累述

2、定义一个事务AOP通知(add开头名单方法)

<tx:advice id="txAdvice" transactionManager="transactionManager">

<tx:attributes>

<tx:methodname="add*" propagation="REQUIRED"/>

</tx:attributes>

</tx:advice>

3、定义一个事务切面,即应该在哪些类的哪些方法上面进行事务切入,多个包体可以使用||隔开

<aop:config>

<aop:advisor pointcut="execution(* *..zx.spring.UserService*.*(..))||execution(**..spring.ServiceFacade.*(..))||execution(**..spring.BookService.*(..))"

advice-ref="txAdvice"/>

</aop:config>

4、事务通知中Propagation设置为7中传播行为的情况如下(单方法):

@1、方法的事务传播机制为REQUIRED, REQUIRES_NEW,并且抛出运行时异常时,将回滚事务。当方法抛出受检查的异常时,将不会回滚事务。

@2、方法的事务传播机制为MANDATORY,由于单个方法执行没有指定任何事务传播机制,因此抛出异常。

@3、方法的事务传播机制为NESTED,由于NESTED内嵌事务,如果没有外层事务,则新建一个事务,行为同REQUIRED一样。

@4、方法的事务传播机制为NEVER,由于发生运行时异常,事务本应该回滚,但是事务传播机制为NEVER,因此找不到事务进行回滚。

@5、方法的事务传播机制为NOT_SUPPORTED,单个方法被执行时,不会创建事务。如果当前有事务,将封装事务挂起,知道该方法执行完成再恢复封装事务,继续执行。

@6、方法的事务传播机制为SUPPORTS,单个方法 调用时supports行为同NEVER一样,不会创建事务,只是如果有事务,则会加入到当前事务中去。

八、多个方法间的事务传播机制(注意这里说的是多个方法)
1、整备工作: spring申明式事务配置,将aop,tx命名空间添加到当前的spring配置文件头中,不在累述。

2、定义一个事务AOP通知(add开头名单方法)

<tx:advice id="txAdvice" transactionManager="transactionManager">

<tx:attributes>

<tx:methodname="add*" propagation="REQUIRED"/>

<tx:methodname="update*" propagation="REQUIRED"/>

</tx:attributes>

</tx:advice>

3、定义一个事务切面,即应该在哪些类的哪些方法上面进行事务切入

<aop:config>

<aop:advisor pointcut="execution(**..zx.spring.UserService*.*(..))||execution(**..spring.ServiceFacade.*(..))||execution(**..spring.BookService.*(..))"

advice-ref="txAdvice"/>

</aop:config>

4、事务通知中Propagation设置为7中传播行为的情况如下(多方法间传递):

@1、多个方法的事务传播机制都为REQUIRED,由于REQUIRED方式是如果有一个事务,则加入事务中,如果没有,则新建一个事务,也就是说方法1一开始就会创建一个事务,而方法2发现有事务存在则会加入到事务中,方法2抛出运行时异常,整个事务将会回滚。如果方法2抛出的是可捕获异常,事务将不起作用,方法1执行成功插入,方法2异常中断。或者我们将方法2设置rollback-for属性,那么在指定的异常之内事务都将回滚

@2、方法1的事务传播机制为REQUIRED,方法2的事务传播机制为NEVER,由于方法1会创建一个事务,而方法2是NEVER,不应该在事务中运行,因此导致了冲突会报错。Existingtransaction found for transaction marked with propagation 'never'

@3、方法1的事务传播机制为REQUIRED,方法2的事务传播机制为MANDATORY,执行机制和@1一致。

@4、方法1的事务传播机制为REQUIRED,方法2的事务传播机制为NESTED,内嵌事务,也就是方法1执行体内放入方法2的调用,由于方法2的事务传播机制为NESTED内嵌事务,因此,开始一个新的事务。并且方法2内部抛出RuntimeException,因此内部嵌套事务回滚到外层事务创建的保存点。

注意这个地方,我们抛出的是运行时异常,如果我们抛出受检查的异常,那么spring会默认的忽略此异常。

如果内层事务抛出检查异常,那么外层事务将忽略此异常,但是会产生一个问题。那就是:外层事务使用jdbc的保存点API来实现嵌套事务,

但是数据库不一定支持。我做测试的是oracle数据库,jdbc事务管理器在内层事务抛出检查异常后,将会在内层事务结束后,释放外层事务创建的保存点,这个时候数据库不一定支持。因此可能会抛出如下异常java.sql.SQLException:不支持的特性。

总结: 对于NESTED内层事务而言,内层事务独立于外层事务,可以独立递交或者回滚,如果内层事务抛出的是运行异常,外层事务进行回滚,内层事务也会进行回滚。

@5、方法1的事务传播机制为REQUIRED,方法2的事务传播机制为REQUIRES_NEW。(情况比较复杂)

情况一,方法2不抛出任何异常下:方法1先创建事务,但是方法2也要运行在自己的事务中,因此也会创建一个事务,方法1的事务将会挂起,直到方法2的事务执行完成才会接着事务的提交完成

情况二,方法2抛出运行时异常下: 对于REQUIRES_NEW事务传播机制,如果被调用端(方法2)抛出运行时异常,则被调用端事务回滚,如果调用段代码(方法1)捕获了被调用端抛出的运行时异常,那么调用端事务提交,不回滚。反之,如果调用段代码未捕获被调用端抛出的运行时异常,那么调用端事务回滚,不提交。

@6、方法1的事务传播机制为REQUIRED,方法2的事务传播机制为SUPPORTS,方法1创建一个事务,方法2加入到当前事务中,方法2抛出运行异常将进行事务的回滚,如果方法1不具有事务,由于方法2的特性是事务环境可有可无,方法2也不会运行在事务中,所以也不会进行回滚。如果方法2抛出的是受检查异常,异常将会忽略,事务将会提交,当然还有别的情况没有一一验证

@7、方法1的事务传播机制为REQUIRED,方法2的事务传播机制为NOT_SUPPORTED,由于方法2事务特性,方法1的事务将会被挂起,方法2抛出运行时异常,但是方法2是不在事务环境中运行的,所以回滚不了,而方法1中未捕获此异常,将进行事务回滚,如果方法2抛出的是运行异常,即使方法1没有捕获此异常,也将被忽略,不进行事务的回滚。

PS:以上都是对粗粒度的方法的事务操作,都是在数据无问题,特意抛出异常的情况下来判断事务的特性,并在什么情况下事务将会起作用。而且spring的事务,在服务类内部的方法间调用,有可能存在被调用方法配置的事务不起作用,调用方在加上事务就起作用了。还值得测试深究

九、spring声明式事务配置的几种方式
1、基于@Transactional注解(推荐配置)

<!-- 事务管理器,对mybatis操作数据库进行事务控制,spring使用jdbc的事务控制类  -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSourceSuport"></property>

</bean>

<!—开启spring 事务注解支持  mode="aspectj"表示采用切面    mode="proxy"表示代理模式(默认) -->

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

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

@Transactional可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。 虽然@Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外,@Transactional 注解应该只被应用到public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用@Transactional 注解,这将被忽略,也不会抛出任何异常。默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

2、基于<tx>与<aop>切面的方式进行事务配置

<!-- 事务管理器,对mybatis操作数据库进行事务控制,spring使用jdbc的事务控制类  -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSourceSuport"></property>

</bean>

<!-- spring 事务注解     mode="aspectj"表示采用切面    mode="proxy"表示代理模式(默认) -->

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

<!-- 通知   映射到上面的事务管理器-->

<tx:advice  id="txAdive"transaction-manager="transactionManager">

<tx:attributes>

<!--name什么方法名称开头  传播行为 REQUIRED必须事务   rollback-for什么异常类进行回滚,逗号隔开 -->

<tx:method name="save*" propagation="REQUIRED"rollback-for="java.lang.DaoException"/>

<tx:method name="delete*" propagation="REQUIRED"rollback-for="java.lang.DaoException"/>

<tx:method name="insert*" propagation="REQUIRED"rollback-for="java.lang.DaoException"/>

<tx:method name="update*" propagation="REQUIRED"rollback-for="java.lang.DaoException"/>

<!-- 不是必须的,而且查询类型为事务只读的可以提高数据库性能优化  -->

<tx:method name="find*" propagation="SUPPORTS"read-only="true"/>

<tx:method name="get*" propagation="SUPPORTS"read-only="true"/>

<tx:method name="select*" propagation="SUPPORTS"read-only="true"/>

</tx:attributes>

</tx:advice>

<!-- aop切面并配置切入点入进行事物管理 指向上面的映射 -->

<aop:config>

<aop:pointcut expression="execution(* com.zht.service.serviceImpl.*.*(..))"id="txPointcut"/>

<aop:advisor advice-ref="txAdive" pointcut-ref="txPointcut"/>

</aop:config>

<aop:aspectj-autoproxy proxy-target-class="true"/>

3、基于TransactionProxyFactoryBean (bean工厂代理)--需要显示的为每一个业务类配置,每多一个业务类就要进行添加,这里不在描述。

4、基于TransactionInterceptor(事务拦截器)的方式进行配置。

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

<propertyname="sessionFactory">

<ref bean="sessionFactory"/>

</property>

</bean>

<!--事务拦截器,激活事务管理器所必须的bean -->

<bean id="transactionInterceptor"class="org.springframework.transaction.interceptor.TransactionInterceptor">

<property name="transactionManager">

<ref bean="transactionManager" />

</property>

<!--配置事务属性 -->

<property name="transactionAttributes">

<props>

<prop key="delete*">PROPAGATION_REQUIRED</prop>

<prop key="add*">PROPAGATION_REQUIRED</prop>

<prop key="update*">PROPAGATION_REQUIRED</prop>

<prop key="save*">PROPAGATION_REQUIRED</prop>

<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>

</props>

</property>

</bean>

<!--定义事务处理代理bean,他需要两个属性,一个是指定需要代理的bean,另一个是代理bean所需的事务拦截器 -->

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

<property name="beanNames">

<list>

<value>tempService</value>

</list>

</property>

<propertyname="interceptorNames">

<list>

<value>transactionInterceptor</value>

</list>

</property>

</bean>

<!--业务逻辑层 -->

<bean id="tempService" class="com.cj.transaction.service.TempService"abstract="false"

lazy-init="default"autowire="default" dependency-check="default">

<property name="userDAO">

<ref bean="userDAO" />

</property>

<property name="deptDAO">

<ref bean="deptDAO" />

</property>

</bean>

<bean id="userDAO" class="com.cj.transaction.hibernate.UserDAO">

<property name="sessionFactory">

<ref bean="sessionFactory"/>

</property>

</bean>

<bean id="deptDAO"class="com.cj.transaction.hibernate.DeptDAO">

<property name="sessionFactory">

<ref bean="sessionFactory"/>

</property>

</bean>

如果模块过多话,可以考虑根据bean的名称用自动创建事务代理的方式

<!--自动代理 -->

<bean id="autoproxy"class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

<property name="beanNames">

<list>

<value>*Service</value>

</list>

</property>

<property name="interceptorNames">

<list>

<value>transactionInterceptor</value>

</list>

</property>

</bean>
---------------------
作者:Yeah-小海
来源:CSDN
原文:https://blog.csdn.net/zht741322694/article/details/78676964
版权声明:本文为博主原创文章,转载请附上博文链接!

spring事务隔离级别、传播机制以及简单配置的更多相关文章

  1. Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现分布式事务管理

    原创说明:本文为本人原创作品,绝非他处转载,转账请注明出处 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). ...

  2. 事务,Oracle,MySQL及Spring事务隔离级别

    一.什么是事务: 事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败. 二.事务特性(4种): 原子性 (atomicity):强调事务的不可分割:一致性 (consiste ...

  3. Spring事务隔离级别和传播特性

    相信每个人都被问过无数次Spring声明式事务的隔离级别和传播机制吧!今天我也来说说这两个东西. 加入一个小插曲, 一天电话里有人问我声明式事务隔离级别有哪几种, 我就回答了7种, 他问我Spring ...

  4. Spring事务隔离级别和传播特性(转)

    相信每个人都被问过无数次Spring声明式事务的隔离级别和传播机制吧!今天我也来说说这两个东西. 加入一个小插曲,一天电话里有人问我声明式事务隔离级别有哪几种,我就回答了7种,他问我Spring的版本 ...

  5. 浅谈Spring事务隔离级别

    一.Propagation (事务的传播属性) Propagation : key属性确定代理应该给哪个方法增加事务行为.这样的属性最重要的部份是传播行为.有以下选项可供使用:PROPAGATION_ ...

  6. MySQL事务及事务隔离级别 锁机制

    什么是事务? 当多个用户访问同一份数据时,一个用户在更改数据的过程中可能有其他用户同时发起更改请求,为保证数据库记录的更新从一个一致性状态更改为另一个一致性状态,这样的操作过程就是事务.事务具有的AC ...

  7. spring事务隔离级别以及脏读 不可重复读 幻影读

    隔离级别 声明式事务的第二个方面是隔离级别.隔离级别定义一个事务可能受其他并发事务活动活动影响的程度.另一种考虑一个事务的隔离级别的方式,是把它想象为那个事务对于事物处理数据的自私程度. 在一个典型的 ...

  8. spring 事务隔离级别导致的bug

    事情是这样的,ios进货单有一个数量加一手,减一手的功能,每加减一次就会异步调用后台的接口,后台判断sku如果不存在就插入,存在就更新.   问题描述: 当ios发了多次请求后, 在第二次请求的时候, ...

  9. Spring事务隔离级别和传播性

    事务的隔离级别也分为四种: read uncommited(读未提交). read commited(读提交). read repeatable(读重复). serializable(序列化), 这四 ...

随机推荐

  1. epoll linux和协程gevent的区别

    epoll linux  底层是libevent.so模块实现的 gevent也是IO多路复用,底层是libevent.so模块实现的是更上层的封装 Twsited异步网络框架.代码量非常大.在开源p ...

  2. JAVA判断是否是微信内置浏览器,是否是在微信内打开

    /** * 通过请求头判断是否是微信内置浏览器,是否是在微信内打开 * @param request * @return */ @RequestMapping(value = "/hello ...

  3. win10+vs2015编译nanogui

    !!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!! 作者:mohist 说明: A.OS : win10 1909 ,没有配置OpenGL开发环境的 经历. B. ...

  4. C printf 字符串格式化

    %a 浮点数.十六进制数字和p-记数法(C99) %A 浮点数.十六进制数字和p-记法(C99) %c 一个字符 %d 有符号十进制整数 %e 浮点数.e-记数法 %E 浮点数.E-记数法 %f 浮点 ...

  5. 【LeetCode】861. Score After Flipping Matrix 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. codeforce -602B Approximating a Constant Range(暴力)

    B. Approximating a Constant Range time limit per test 2 seconds memory limit per test 256 megabytes ...

  7. 一个简单的js时钟

    演示地址 代码 <html> <head> <title> Nonove js clock 时钟 </title> <script type=&q ...

  8. Order Statistic

    目录 The Order Statistic 引理1 的一些基本性质 顺序统计量的分布 顺序统计量的条件分布 特殊分布的特殊性质 Order Statistic The Order Statistic ...

  9. Dimension reduction in principal component analysis for trees

    目录 问题 重要的定义 距离 支撑树 交树 序 tree-line path 重要的性质 其它 Alfaro C A, Aydin B, Valencia C E, et al. Dimension ...

  10. 贪心学院计算机视觉CV训练营

    贪心学院计算机视觉CV训练营 任务 Notes 其他 任务1:机器学习.深度学习简介 Note1 任务2:深度学习的发展历史 Note2 任务3:现代深度学习的典型例子 Note3 任务4:深度学习在 ...