打印当前事务名的方式:后来发现只要是加了事务注解,它都会有返回值。其实有些传播行为如
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 | 不加 | 不加 | 两者都以无事务状态执行 |
2 | required | 不加 | InsertUser 将它的事务传播给了InsertCuser |
3 | 不加 | required | InsertUser 无事务,InsertCuser 创建了事务 |
4 | required | required | InsertUser 将事务传播给了InsertCuser |
5 | requires | supports | InsertUser 把事务传播给了InsertCuser |
6 | supports | requires | InsertUser无事务,InsertCuser 创建了事务 |
7 | requires | mandatory | InsertUser将事务传播给了InsertCuser |
8 | mandatory | requires | InsertUser报异常IllegalTransactionStateException |
9 | requires_new | required | InsertUser 把事务传播给了InsertCuser |
10 | required | requires_new | 两者使用各自的事务,互不影响 |
11 | requires | not_supported | InsertUser事务先被挂起,等到InsertCuser 非事务执行完毕后再继续执行 |
12 | not_supported | requires | InsertUser 不会创建事务,InsertCuser 使用自己的事务 |
13 | requires | nerver | InsertCuser 报异常IllegalTransactionStateException |
14 | nerver | requires | InsertUser 无事务,InsertCuser 创建了事务 |
15 | requires | nested | InsertUser 把事务传播给了InsertCuser |
16 | nested | requires | InsertUser 把事务传播给了InsertCuser |