Spring 事务管理之事务传播行为

打印当前事务名的方式:后来发现只要是加了事务注解,它都会有返回值。其实有些传播行为如

System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());

 

实验准备

分别有UserService 和 CuserService 两个service,他们之内都有实现各自的insert方法。且在UserService 接口里有调用CuserService 的接口。我们通过在方法上加上@Transactional注解并指定特定的propagation属性,设置不同的事务传播行为。观察运行结果,验证结论~

创建Users和Cuser实体类

package com.springboot.study.demo1.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 *@description: User 实体类
 *@author: yinkai
 *@create: 2020/2/25 9:21
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Users {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

package com.springboot.study.demo1.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 *@description: Cuser 实体类
 *@author: yinkai
 *@create: 2020/2/25 9:21
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Cuser {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

创建 CuserService 和UsersService接口:

package com.springboot.study.demo1.service;
import com.springboot.study.demo1.entity.Cuser;
/**
 * @author ceshi
 * @Title:
 * @Package
 * @Description:
 * @date 2020/3/217:11
 */
public interface CuserService {

     void InsertCuser(Cuser cuser);
}


package com.springboot.study.demo1.service;
import com.springboot.study.demo1.entity.Cuser;
import com.springboot.study.demo1.entity.User;
import com.springboot.study.demo1.entity.Users;

/**

/**
 *@program: springboot_study
 *@description:
 *@author: yinkai
 *@create: 2020-03-02 15:30
 */
public interface UsersService {
    void InsertUsers(Users users);


}

创建CuserServiceImpl和UsersServiceImpl实现类

  • 分别实现InsertUsers () 和 InsertCuser()方法 ; 一个功能为添加User,一个功能为添加Cuser
  • InsertUsers ()方法内部调用了InsertCuser()方法,制造事务冲突环境
package com.springboot.study.demo1.service.impl;
import com.springboot.study.demo1.entity.Cuser;
import com.springboot.study.demo1.entity.Users;
import com.springboot.study.demo1.service.CuserService;
import com.springboot.study.demo1.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.List;
import java.util.Map;
/**
 *@program: springboot_study
 *@description:
 *@author: yinkai
 *@create: 2020-03-02 15:31
 */
@Service
public class UsersServiceImpl implements UsersService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private CuserService cuserService;

    @Transactional(propagation= Propagation.NOT_SUPPORTED)
    @Override
    public void InsertUsers(Users users) {
        jdbcTemplate.update("INSERT INTO users(id,name, age, email) VALUES (?, ?, ?, ?);",users.getId(), users.getName(), users.getAge(), users.getEmail());
        //调用service中另一个方法
        Cuser cuser = new Cuser(users.getId(), users.getName(), users.getAge(), users.getEmail());
        //打印事务名
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID( );");
        System.out.println(maps + TransactionSynchronizationManager.getCurrentTransactionName());
        cuserService.InsertCuser(cuser);
    }
}

package com.springboot.study.demo1.service.impl;
import com.springboot.study.demo1.entity.Cuser;
import com.springboot.study.demo1.service.CuserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.List;
import java.util.Map;
/**
 * @program: springboot_study
 * @description:
 * @author: yinkai
 * @create: 2020-03-02 17:12
 */
@Service
public class CuserServiceImpl implements CuserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void InsertCuser(Cuser cuser) {
        jdbcTemplate.update("INSERT INTO cuser(id,name, age, email) VALUES (?, ?, ?, ?);", cuser.getId(), cuser.getName(), cuser.getAge(), cuser.getEmail());
        //打印事务名
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID( );");
        System.out.println(maps + TransactionSynchronizationManager.getCurrentTransactionName());
    }
}

创建测试的controller

package com.springboot.study.demo1.controller;
import com.springboot.study.demo1.entity.Users;
import com.springboot.study.demo1.service.UsersService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

/**
 *@program: springboot_study
 *@description:
 *@author: yinkai
 *@create: 2020-03-01 13:00
 */
@RestController
@RequestMapping("/test")
public class TestController {
    @Resource
    private UsersService usersService;
    @RequestMapping("/test")
    public void test(){
        Users users = new Users(100L,"hello",22,"hello@qq.com");
        usersService.InsertUsers(users);
    }
}

项目启动后访问 http://localhost:8080/test/test/test即可根据控制台输出判断事务的传播

首先讲的是spring的默认传播行为REQUIRED

@Transactional(propagation= Propagation.REQUIRED)
一种优先按照调用者事务来,如果调用者没事务则直接创建一个

开始测试

1、两种方法都不加事务

    @Override
    public void InsertUsers(Users users) 
      
    @Override
    public void InsertCuser(Cuser cuser) 
   

这个是意料之中,不加事务注解当然不会开启事务

2、InsertUser 加上required,InsertCuser 不加事务

    @Transactional(propagation= Propagation.REQUIRED)
    @Override
    public void InsertUsers(Users users) 
      
    @Override
    public void InsertCuser(Cuser cuser) 
   

InsertUser 将事务传播给InsertCuser ,两者使用InsertUser 上的同一事务;想象一下,调用关系 A-->B-->C--->D-->.... 若只有A上加了required事务注解,那么BCD...都会纳入A的事务中

3、InsertUser不加事务,InsertCuser 加上 required

    @Override
    public void InsertUsers(Users users) 

    @Transactional(propagation= Propagation.REQUIRED)
    @Override
    public void InsertCuser(Cuser cuser) 

InsertUser没有使用事务,InsertCuser 使用自己的事务

4、InsertUser 和 InsertCuser 都加上 required

   @Transactional(propagation= Propagation.REQUIRED)
   @Override
    public void InsertUsers(Users users) 

    @Transactional(propagation= Propagation.REQUIRED)
    @Override
    public void InsertCuser(Cuser cuser) 

 

InsertUser 将事务传播给InsertCuser ,两者使用InsertUser 上的同一事务;

5、InsertUser 使用 required,InsertCuser 使用 supports

InsertUser 将事务传播给InsertCuser ,两者使用InsertUser 上的同一事务;

6、InsertUser 使用 supports ,InsertCuser 使用 required

InsertUser 没有创建事务,InsertCuser 使用自己的事务

7、InsertUser 使用required,InsertCuser 使用 requires_new

 

InsertUser和 InsertCuser 各自创建了事务,互不影响

8、InsertUser 使用requires_new,InsertCuser 使用required

InsertUser 将事务传播给InsertCuser ,两者使用InsertUser 上的同一事务;

9、InsertUser 使用 required,InsertCuser 使用 mandatory

InsertUser 将事务传播给InsertCuser ,两者使用InsertUser 上的同一事务;

10、InsertUser 使用 mandatory ,InsertCuser 使用 requires

报异常

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

11、InsertUser 使用 requires,InsertCuser 使用 not_supported

InsertUser事务先被挂起,等到InsertCuser 非事务执行完毕后再继续执行

12、InsertUser 使用not_supported ,InsertCuser 使用 requires

InsertUser 不会创建事务,InsertCuser 使用自己的事务

13、InsertUser 使用 requires,InsertCuser 使用 never

报异常

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

14、InsertUser 使用 never,InsertCuser 使用 requires

InsertUser 不使用事务,InsertCuser 使用自己的事务

15、InsertUser 使用 requires,InsertCuser 使用 nested

InsertUser 将事务传播给InsertCuser ,两者使用InsertUser 上的同一事务

16、InsertUser 使用 nested,InsertCuser 使用 requires

InsertUser 将事务传播给InsertCuser ,两者使用InsertUser 上的同一事务

大总结

实验      InsertUser 调用者  InsertCuser 被调用者  结果

1不加不加两者都以无事务状态执行
2required不加InsertUser 将它的事务传播给了InsertCuser
3不加requiredInsertUser 无事务,InsertCuser 创建了事务
4requiredrequiredInsertUser 将事务传播给了InsertCuser
5requiressupportsInsertUser 把事务传播给了InsertCuser
6supportsrequiresInsertUser无事务,InsertCuser 创建了事务
7requiresmandatoryInsertUser将事务传播给了InsertCuser
8mandatoryrequiresInsertUser报异常IllegalTransactionStateException
9requires_newrequiredInsertUser 把事务传播给了InsertCuser
10requiredrequires_new两者使用各自的事务,互不影响
11requiresnot_supportedInsertUser事务先被挂起,等到InsertCuser 非事务执行完毕后再继续执行
12not_supportedrequiresInsertUser 不会创建事务,InsertCuser 使用自己的事务
13requiresnerverInsertCuser 报异常IllegalTransactionStateException
14nerverrequiresInsertUser 无事务,InsertCuser 创建了事务
15requiresnestedInsertUser 把事务传播给了InsertCuser
16nestedrequiresInsertUser 把事务传播给了InsertCuser

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值