spring事务

本文详细介绍了Spring中的事务管理,包括事务配置、@Transactional注解详解、不同传播行为的效果及应用场景等,帮助读者深入理解Spring事务的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录


spring事务分为声明式事务和编程式事务,而声明式事务又分为注解和xml,一般开发都有声明式事务注解。

一、事务相关配置

1、配置连接池:

配置连接池文件
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_day02
jdbc.username=root
jdbc.password=123
	<!-- 引入外部属性文件: -->
<bean id="dataSource" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location" value="classpath:jdbc.properties"/>
</bean>
	<!-- 引入外部属性文件: -->
<context:property-placeholder location="classpath:jdbc.properties"/>

	<!-- 配置 JDBC 模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	<property name="dataSource" ref="dataSource"/>
<!-- <property name="location" value="classpath:jdbc.properties"/> -->
</bean>

2、xml配置事务

注意:基于xml实现的声明式事务,必须引入aspectJ的依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.1</version>
</dependency>
<!-- 事务管理器,即spring提供的切面 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 配置事务的增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
			<!--isolation="DEFAULT" 隔离级别
				propagation="REQUIRED" 传播行为
				read-only="false" 只读
				timeout="-1" 过期时间
				rollback-for="" -Exception
				no-rollback-for="" +Exception  -->
		<tx:method name="transfer" propagation="REQUIRED"/>
	</tx:attributes>
</tx:advice>

<aop:config>
	<aop:pointcut expression="execution(*cn.zixue.transaction.demo2.AccountServiceImpl.transfer(..))" id="pointcut1"/>
<!-- 由于spring提供了事务的切面,不需要编写,直接配置应用通知就可以使用 -->        
	<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>

3、注解事务

<!--开启事务的注解驱动 通过注解@Transactional所标识的方法或标识的类中所有的方法(即切点),都会被事务管理器管理事务-->
<!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!-- 事务管理器,spring提供的切面 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>

注解事务类     

 //类级的注解、适用于类中所有的public的方法,要是只在接口上写, 接口的实现类就会继承下来、接口的实现类的具体方法,可以覆盖类声明处的设置
@Transactional  
public class TestServiceBean implements TestService {   
    private TestDao dao;   
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,readOnly=false)
    public void setDao(TestDao dao) {
        this.dao = dao;
    }   
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<Object> getAll() {
        return null;
    }   
}

注解事务

二、@Transactional注解事务详解

1、@Transactional注解中常用参数说明     

参 数 名 称功 能 描 述
readOnly该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class}),默认运行时异常回滚
rollbackForClassName该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称:@Transactional(rollbackForClassName=“RuntimeException”)指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,“Exception”})
noRollbackFor该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=“RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,“Exception”})
propagation该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout该属性用于设置事务的超时秒数,默认值为-1表示永不超时

三、不同传播行为

1、传播方式总结

    /**
     * 事务传播 - Propagation
     *      REQUIRED: 使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的;
     *                如果当前存在事务,则加入这个事务,成为一个整体。
     *                举例:领导没饭吃,我有钱,我会自己买了自己吃;领导有的吃,会分给你一起吃。
     *      SUPPORTS: 如果当前有事务,则使用事务;如果当前没有事务,则不使用事务。
     *                举例:领导没饭吃,我也没饭吃;领导有饭吃,我也有饭吃。
     *      MANDATORY: 该传播属性强制必须存在一个事务,如果不存在,则抛出异常
     *                 举例:领导必须管饭,不管饭没饭吃,我就不乐意了,就不干了(抛出异常)
     *      REQUIRES_NEW: 如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用;
     *                    如果当前没有事务,则同 REQUIRED
     *                    举例:领导有饭吃,我偏不要,我自己买了自己吃
     *      NOT_SUPPORTED: 如果当前有事务,则把事务挂起,自己不适用事务去运行数据库操作
     *                     举例:领导有饭吃,分一点给你,我太忙了,放一边,我不吃
     *      NEVER: 如果当前有事务存在,则抛出异常
     *             举例:领导有饭给你吃,我不想吃,我热爱工作,我抛出异常
     *      NESTED: 如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;
     *              如果当前没有事务,则同 REQUIRED。
     *              但是如果主事务提交,则会携带子事务一起提交。
     *              如果主事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以回滚或不回滚。
     *              举例:领导决策不对,老板怪罪,领导带着小弟一同受罪。小弟出了差错,领导可以推卸责任。
     */

2、传播方式 REQUIRED默认事务

​ 经常用于增删改操作

①、不使用事务

异常之前都直接提交,异常之后都不执行

@Service
public class TestTransServiceImpl implements TestTransService {

    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}
@Service
public class StuServiceImpl implements StuService {

    @Autowired
    private StuMapper stuMapper;
    
    public void saveParent() {//父方法直接调用,直接插入
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    public void saveChildren() {//child1方法没有回滚
        saveChild1();
        int a = 1 / 0;	//异常点 java.lang.ArithmeticException: / by zero
        saveChild2();	//由于前面异常不在往后执行,也不回滚前面代码
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }
    
    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }
}

运行数据库结果:

idnameage
2parent19
3child-111
②、外层使用默认事务

默认事务是会传播,是一个整体事务,子方法出现异常将整体回滚。

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        // int a = 1 / 0; 这里出现异常也一样全部回滚
        stuService.saveChildren();
    }    
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行结果:没有插入任何数据

③、父方法不开启事务,子方法开启事务

只有子级有事务回滚,其他以非事务方式运行。

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();	//以非事务方式运行
        stuService.saveChildren();	//新的整体事务运行
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

	//由于父级没有事务,所以这里创建一个新事务运行
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
11parent19
④、父方法开启事务,同时子方法开启事务

子级加入父级事务,属于同一事务,一起回滚或提交

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
   public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果: 空,没有插入任何数据。

⑤、外层开启默认事务,里层开启默认事务

外层事务和子级事务属于同一事务,所以全部回滚

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
        int a = 1 / 0;
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

	//开启默认事务
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveChildren() {
        saveChild1();
        //int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:空,没有插入任何数据。

3、传播方式 SUPPORTS支持事务

经常用于查询操作

①、外层不开启事务,子级开启支持事务

​ 子级事务与外层保持一致,非事务方式运行。

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
15parent19
16child-111
②、外层开启默认事务,里层开启支持事务

​ 子级事务与外层保持一致,以事务方式运行。

    @Transactional(propagation = Propagation.REQUIRED)
	@Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:空,没有插入任何数据。

4、传播方式 MANDATORY 强制事务

①、外层开启支持事务或者无事务,里层开启强制事务

​ 外层必须开启事务方式,不然抛出异常。

org.springframework.transaction.IllegalTransactionStateException: 
	No existing transaction found for transaction marked with propagation 'mandatory'
	//外层开启支持事务或者无事务
	@Transactional(propagation = Propagation.SUPPORTS)
	@Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.MANDATORY)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
43parent19
②、外层开启默认事务,里层开启强制事务

​ 子级事务与外层保持一致,以事务方式运行。

    @Transactional(propagation = Propagation.REQUIRED)
	@Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.MANDATORY)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:空,没有插入任何数据。

5、传播方式 REQUIRES_NEW新建事务

①、外层不开启事务,里层开启新建事务

外层以非事务方式运行,saveChildren新建一个事务

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
23parent19
②、外层开启默认事务,里层开启新建事务

外层以事务方式运行,saveChildren新建一个事务出现异常,影响外层事务回滚。

	@Transactional(propagation = Propagation.REQUIRED)
	@Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:空,没有插入任何数据。

③、外层开启默认事务,里层开启新建事务

外层事务出现异常不影响里面新建事务提交 ,分别提交

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
        int a = 1 / 0;
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

	//开启新建事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveChildren() {
        saveChild1();
        //int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
28child-111
29child-222

6、传播方式 NOT_SUPPORTED 挂起,以非事务方式运行

①、外层非事务,里面挂起事务

异常之前都直接提交,异常之后都不执行

@Service
public class TestTransServiceImpl implements TestTransService {

    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
        int a = 1 / 0;
    }
}
@Service
public class StuServiceImpl implements StuService {

    @Autowired
    private StuMapper stuMapper;
    
    public void saveParent() {//父方法直接调用,直接插入
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void saveChildren() {//child1方法没有回滚
        saveChild1();
        int a = 1 / 0;	//异常点 java.lang.ArithmeticException: / by zero
        saveChild2();	//由于前面异常不在往后执行,也不回滚前面代码
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }
    
    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }
}

运行数据库结果:

idnameage
33parent19
34child-111
②、外层默认事务,里面挂起事务

外层事务传播,由于里层事务抛出异常回滚外层数据,由于里层挂起所以有提交一条

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
        int a = 1 / 0;
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

	//挂起事务
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
36child-111

7、传播方式 NEVER如果有事务抛出异常,以非事务方式运行

①、外层不开启事务,子级开启NEVER事务

​ 子级事务与外层保持一致,非事务方式运行。

//或者@Transactional(propagation = Propagation.SUPPORTS、Propagation.NOT_SUPPORTED)也一样结果
	@Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.NEVER)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
47parent19
48child-111
②、外层开启默认事务,子级开启NEVER事务

​ 强制不能有事务,不然抛出异常

org.springframework.transaction.IllegalTransactionStateException: 
	Existing transaction found for transaction marked with propagation 'never'
    @Transactional(propagation = Propagation.REQUIRED) //或者Propagation.REQUIRES_NEW 一样结果
	@Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.NEVER)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果: 空,没有插入任何数据。

8、传播方式 NESTED嵌套事务

①、外层开启默认事务,子级开启NESTED事务

​ 属于嵌套事务,外层事务出现异常,子事务也将回滚

    @Transactional(propagation = Propagation.REQUIRED)
	@Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
        int a = 1 / 0;
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.NESTED)
    public void saveChildren() {
        saveChild1();
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:空,没有插入任何数据。

②、外层开启默认事务,子级开启NESTED事务
子事务发生异常,如果不try catch,将影响外层事务;将全部回滚
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
   public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.NESTED)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:空,没有插入任何数据。

子事务发生异常,如果不ry catch,将不影响外层事务;将造常往下执行
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        try {
            stuService.saveChildren();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("继续往下执行中。。。。");
    }
   public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.NESTED)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

java.lang.ArithmeticException: / by zero
	at com.xiao.service.impl.StuServiceImpl.saveChildren(StuServiceImpl.java:65)
    
继续往下执行中。。。。
idnameage
59parent19
③、父方法不开启事务,子方法开启事务

只有子级有事务回滚,其他以非事务方式运行。

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();	//以非事务方式运行
        stuService.saveChildren();	//新的整体事务运行
    }
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

	//由于父级没有事务,所以这里创建一个新事务运行 像是REQUIRED
    @Transactional(propagation = Propagation.NESTED)
    public void saveChildren() {
        saveChild1();
        int a = 1 / 0; //异常点 java.lang.ArithmeticException: / by zero
        saveChild2();
    }

    public void saveChild1() {
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2() {
        Stu stu2 = new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }

运行数据库结果:

idnameage
61parent19

四、事务属性

1、事务特性 ACID

  • ​ 原子性 (Atomicity): 强调事务的不可分割,要么一起成功,要么一起失败

  • ​ 一致性 (Consistency) :事务的执行的前后数据的完整性保持一致.(总量保持不变)

  • ​ 隔离性 (Isolation) : 一个事务执行的过程中,不应该受到其他事务的干扰

  • ​ 持久性(Durability) :事务一旦结束,数据就持久到数据库

2、不同隔离级别引发的问题

  • ​ 脏读 :一个事务读到了另一个事务的未提交的数据

  • ​ 不可重复读 :一个事务中 两次读取的数据的内容不一致,另一个事务unpdate并提交导致的

  • ​ 虚幻读 :一个事务中 两次读取的数据的数量不一致,insert、delete的数据导致多次查询结果不一致.

3、设置事务隔离级别解决的问题

  • ​ 读写提交 :脏读,不可重复读,虚读都有可能发生

  • ​ 读已提交 :避免脏读。但是不可重复读和虚读有可能发生

  • ​ 可重复读 :避免脏读和不可重复读.但是虚读有可能发生。当使用可重复读隔离级别时,在事务执行期间会锁定该事务以任何方式引用的所有行。因此,如果在同一个事务中发出同一个SELECT语句两次或更多次,那么产生的结果数据集总是相同的。因此,使用可重复读隔离级别的事务可以多次检索同一行集,并对它们执行任意操作,直到提交或回滚操作终止该事务。

  • ​ 串行化 :避免以上所有读问题.。在事务A执行期间,禁止其它事务对这个表进行添加、更新、删除操作。

隔离级别脏读不可重复读虚读
读未提交×××
读已提交××
可重复读×
串行化

4、数据库默认的隔离级别

Mysql 默认:可重复读
Oracle 默认:读已提交

五、为何spring可以支持事务

①事务底层并不是spring支持的,而是有各个数据库支持的,数据库通过连接可以开启事务、提交事务、回滚事务。
②数据库中的事务提交和回滚是区分连接的。
③而spring管理者连接来控制事务开启和回滚,来控制事务;
④对于多个请求经过tomcat会从tomcat连接池中获取一个线程去请求controller层,所以存在线程安全问题,里面通过使用ThreadLock保证每个线程使用的连接是本线程的,而不会导致回滚或提交到其他请求的SQL。
在这里插入图片描述

3、事务定义信息     

  • 隔离级别
  • 传播行为: PPROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
  • 超时信息 //timeout=30,默认是30秒
  • 是否只读 //readOnly
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值