Spring支持两种事务方式:

  • 编程式事务:使用的是TransactionTemplate(或者org.springframework.transaction.PlatformTransactionManager接口)
  • 声明式事务:使用Transactional注解或者xml配置,建立在AOP之上的。本质就是对方法前后进行拦截,然后在目标方法开始之前创建或者添加一个事物,在执行完目标方法之后根据执行情况提交或者回滚事物

使用@Transactional注解时需要记住两个点:

        第一点:@Transactional 只能应用到 public 方法才有效

只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是因为在使用 Spring AOP 代理时,Spring 在调用TransactionInterceptor 在目标方法执行前后进行拦截之前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 通过这个类获取@Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法

protected TransactionAttribute computeTransactionAttribute(Method method,Class<?> targetClass) {
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null;}

      第二点:避免 Spring 的 AOP 的自调用问题

      在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚

原因:调用的是原生方法,并不是代理对象的方法

   @Service
public class DemoService {
private void method1() {
insertOrder();
}
//当method2()被method1调用时,@Transactional失效
@Transactional
public void method2() {
//so some thing
}}

当然上面两个问题也是能解决的,使用 AspectJ 取代 Spring AOP 代理

1.认识@Transactional 注解的属性

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default ""; //当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器 @AliasFor("value")
String transactionManager() default ""; //当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器 Propagation propagation() default Propagation.REQUIRED; //事务的传播行为 Isolation isolation() default Isolation.DEFAULT; //事务的隔离级别 int timeout() default -1; //事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务 boolean readOnly() default false; //指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true Class<? extends Throwable>[] rollbackFor() default {}; //用于指定能够触发事务回滚的异常类型,可以指定多个异常类型 String[] rollbackForClassName() default {}; //类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组,和rollbackFor对应 Class<? extends Throwable>[] noRollbackFor() default {}; //抛出指定的异常类型,不回滚事务,也可以指定多个异常类型 String[] noRollbackForClassName() default {}; //类名数组,必须继承自Throwable 导致事务不回滚的异常类名字数组,和noRollbackFor对应
}

2.propagation 属性,isolation 属性

事务的传播行为(TransactionDefinition定义):

Propagation.REQUIRED                    如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。

Propagation.REQUIRES_NEW         重新创建一个新的事务,如果当前存在事务,暂停当前的事务。

Propagation.SUPPORTS                   如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。

//下面使用场景较少

Propagation.MANDATORY                如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。

Propagation.NOT_SUPPORTED       以非事务的方式运行,如果当前存在事务,暂停当前的事务。

Propagation.NEVER                          以非事务的方式运行,如果当前存在事务,则抛出异常。

Propagation.NESTED                        如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED

事务的隔离级别(TransactionDefinition定义):

ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是ISOLATION_READ_COMMITTED。

ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。

ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。

ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。

ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

Spring定义的TransactionDefinition接口:

 3.场景Demo测试

    实体类Company

@Data
@Builder
public class Company {
private String companyId;//公司编码
private String companyName;//公司名称
private String memo;//备注
}

测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class MytransactionApplicationTests {
@Autowired
private OneCompanyServiceImpl oneCompanyservice;
@Autowired
private TwoCompanyServiceImpl twoCompanyservice;
@Test
//测试Propagation.REQUIRED
public void test1() {
Company company = Company.builder().companyId("123").companyName("阿里巴巴").memo("杭州").build();
oneCompanyservice.multiInsert1(company);
}
@Test
//测试Propagation.REQUIRES_NEW
public void test2() {
Company company = Company.builder().companyId("123").companyName("腾讯").memo("深圳").build();
oneCompanyservice.multiInsert2(company);
}
}

    当前 oneCompanyService调用另一个employeeService

     1.测试 Propagation.REQUIRED

@Override
@Transactional(value="mybatisTransactionManagerOne",rollbackFor = Exception.class)
public void multiInsert1(Company company) {
     oneComPanyDao.insert(company);
     Employee employee = Employee.builder().employeeId("123").employeeName("马云").memo("我对钱不感兴趣").build();
     employeeService.insert(employee);//@Transactional的Propagation为默认REQUIRED,加入当前事务
}

@Override
@Transactional(value="mybatisTransactionManagerOne",rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void insert(Employee employee) {
    employeeDao.insert(employee);
    int flag = 1/0;
}

结果:company和employee都没有插入数据库

   

 2.测试 Propagation.REQUIRES_NEW


@Override
@Transactional(value="mybatisTransactionManagerOne",rollbackFor = Exception.class)
public void multiInsert2(Company company) {
       oneComPanyDao.insert(company);
       Employee employee = Employee.builder().employeeId("456").employeeName("马化腾").memo("我只是住的房子大一点").build();
       employeeService.insertOther(employee);// @Transactional的Propagation设置为REQUIRES_NEW,另启事务
       int flag = 1/0;//这里发生异常insertOther事务已经提交,不会回滚,insert方法回滚
}

@Override
@Transactional(value="mybatisTransactionManagerOne",rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void insertOther(Employee employee) {
    employeeDao.insert(employee);
}

结果:company没有插入数据库,employee插入数据库

      还有其他种Propagation行为,平时使用场景也比较少,不赘述

@Transactional之Spring事务深入理解的更多相关文章

  1. spring事务概念理解

    1.数据并发问题 脏读 A事务读取B事务尚未提交的更新数据,并在此数据的基础上操作.如果B事务回滚,则A事务读取的数据就是错误的.即读取了脏数据或者错误数据. 不可重复组 A事务先后读取了B事务提交[ ...

  2. spring事务的理解

    特性 一致性:业务处理要么都成功,要么都失败,不能部分成功不分失败 原子性:业务操作是由多个动作完成,这些动作不可分割,要么都执行,要么都不执行 隔离性:事务间之间要做隔离,不要互相影响 持久性:操作 ...

  3. myBatis 切换数据源(spring事务)理解

    1. mybatis (SqlSessionTemplate)的动态代理 a) sqlSession的结构 b)SqlSession 结构 public class SqlSessionTemplat ...

  4. spring事务再次理解

    2.2.3 只读 事务的第三个特性是它是否为只读事务.如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化.通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认 ...

  5. spring事务详细理解

    数据并发的问题 一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库.数据库中的相同数据可能同时被多个事务访问,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性.这些 ...

  6. Spring学习笔记(四)-- Spring事务全面分析

    通过本系列的文章对Spring的介绍,我们对Spring的使用和两个核心功能IOC.AOP已经有了初步的了解,结合我个人工作的情况,因为项目是金融系 统.那对事务的控制是不可缺少的.而且是很严格的控制 ...

  7. 就这?一篇文章让你读懂 Spring 事务

    什么是事务 ▲ 百度百科 概括来讲,事务是一个由有限操作集合组成的逻辑单元.事务操作包含两个目的,数据一致以及操作隔离.数据一致是指事务提交时保证事务内的所有操作都成功完成,并且更改永久生效:事务回滚 ...

  8. 深入理解 Spring 事务原理

    本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供 ...

  9. 深入理解 Spring 事务原理【转】

    本文转自码农网 – 吴极心原创  连接地址:http://www.codeceo.com/article/spring-transactions.html 一.事务的基本原理 Spring事务的本质其 ...

随机推荐

  1. Java_util_02_Java判断字符串是中文还是英文

    做微信开发,使用百度翻译API时,需要指定译文的语种.这就需要我们判断待翻译内容是中文还是英文,若是中文,则翻译成英文,若是英文则翻译成中文. 方法一:字符与字节的长度 依据:一个中文占两个字节,一个 ...

  2. 自定义ajax小工具以及使用

    function createXMLHttpRequest(){ try{ return new XMLHttpRequest(); }catch(e){ try{ return new Active ...

  3. BEC listen and translation exercise 41

    Its advantages are that it can be used for outside activities So my recommendation I'm afraid would ...

  4. java事务(一)——事务特性

    事务 什么是事务?事务通俗的讲就是要做的事,在计算机术语中一般指访问或更新数据库中数据的一个工作单元.说起事务,那么就要提到事务的ACID特性,即原子性(atomicity).一致性(consiste ...

  5. JavaWEB - 静态include指令、动态Include指令

    (一)使用静态include指令 <%@ page language="java" contentType="text/html; charset=gb2312&q ...

  6. Android 中对于图片的内存优化方法

    Android 中对于图片的内存优化方法,需要的朋友可以参考一下     1. 对图片本身进行操作 尽量不要使用 setImageBitmap.setImageResource. BitmapFact ...

  7. 优秀开源项目之一:视频监控系统iSpy

    iSpy是一个开源的视频监控软件,目前已经支持中文.自己用了一下,感觉还是很好用的.翻译了一下它的介绍. iSpy将PC变成一个完整的安全和监控系统 iSpy使用您的摄像头和麦克风来检测和记录声音或运 ...

  8. oubango中视频JitterBuffer的优化

       

  9. freeMaker的工具类

    package com.ek.util; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import jav ...

  10. Java中“分号”引起的陷阱

    对于这类问题而言,难度不大,多半是由于我们有误操作引起的.但在查找问题所在的时候我们有可能需要花费一番功夫了. 实例一: package com.yonyou.test; /** * 测试类 * @a ...