springboot 事务自调用失效
自调用失效
自调用失效:同一个类中,一个方法调用另一个方法,被调用方法上的事务不生效
失效原因:spring事务底层使用动态代理,若同一个类中的方法吊用另一个方法,则不存在对象之间的代理关系,被调用方法的事务失效
解决方法
接口:HelloService,
接口实现类:HelloServiceImpl
方法:fun、fun2,fun2调用fun
# 新建类实现fun调用fun2
新建类HelloServiceImpl2,方法fun2在HelloServiceImpl2中
在类中注入HelloServiceImpl对象实例,方法fun在HelloServiceImpl中,
在HelloServiceImpl2的fun2中,调用HelloServiceImpl的fun方法
# application.getBean
在fun2中使用application.getBean(HelloService.class)获取对象helloService,
然后使用helloService.fun实现方法调用
# AopUtils.currentProxy()
@EnableAspectJAutoProxy(exposeProxy = true),将exposeProxy = true
在fun2中使用((HelloService)AopContext.currentProxy()).fun()实现方法调用
自调用失效示例
***********
pojo 层
Person
@Getter
@Setter
@ApiModel(value = "Person对象", description = "")
public class Person extends Model<Person> {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
@Override
public Serializable pkVal() {
return this.id;
}
}
***********
config 层
DataConfig
@Configuration
@MapperScan("com.example.demo.dao")
public class DataConfig {
@Bean
public MybatisPlusInterceptor initMybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor =new OptimisticLockerInnerInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
return mybatisPlusInterceptor;
}
}
***********
service 层
PersonService
public interface PersonService extends IService<Person> {
void savePerson(Person person);
void savePersonList(List<Person> personList);
}
***********
service.impl 层
PersonServiceImpl
@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements PersonService {
@Resource
private PersonMapper personMapper;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void savePerson(Person person) {
personMapper.insert(person);
System.out.println(person.toString());
}
@Override
public void savePersonList(List<Person> personList) {
for (Person person : personList){
savePerson(person);
}
}
}
***********
controller 层
PersonController
@RestController
@RequestMapping("/person")
public class PersonController {
@Resource
private PersonService personService;
@RequestMapping("/hello")
public String hello(){
for (int i=0;i<1;i++){
Person person = new Person();
person.setName("瓜田李下 "+i);
person.setAge(10+i);
try {
personService.savePerson(person);
}catch (Exception e){
System.out.println(e.getMessage());
}
}
return "hello";
}
@RequestMapping("/hello2")
public String hello2(){
List<Person> personList = new ArrayList<>();
for (int i=0;i<1;i++){
Person person = new Person();
person.setName("瓜田李下 "+i);
person.setAge(10+i);
personList.add(person);
}
try {
personService.savePersonList(personList);
}catch (Exception e){
System.out.println(e.getMessage());
}
return "success";
}
}
***********
使用测试
localhost:8080/person/hello,控制台输出:
# 创建事务
2022-04-29 18:38:46.696 DEBUG 1203 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [com.example.demo.service.impl.PersonServiceImpl.savePerson]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
# 获取数据库连接
2022-04-29 18:38:46.794 DEBUG 1203 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [com.mysql.cj.jdbc.ConnectionImpl@11f05516] for JDBC transaction
# 切换到手动提交
2022-04-29 18:38:46.795 DEBUG 1203 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@11f05516] to manual commit
com.example.demo.pojo.Person@3f707b76
# 初始化事务提交
2022-04-29 18:38:46.849 DEBUG 1203 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
# 事务提交
2022-04-29 18:38:46.849 DEBUG 1203 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Committing JDBC transaction on Connection [com.mysql.cj.jdbc.ConnectionImpl@11f05516]
# 释放事务
2022-04-29 18:38:46.855 DEBUG 1203 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Releasing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@11f05516] after transaction
localhost:8080/person/hello2,控制台输出:
com.example.demo.pojo.Person@72c88c46
没有执行事务操作
applicationContext
HelloServiceImpl:注入ApplicationContext对象
@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements PersonService {
@Resource
private PersonMapper personMapper;
@Resource
private ApplicationContext applicationContext; //注入applicationContext对象
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void savePerson(Person person) {
personMapper.insert(person);
System.out.println(person.toString());
}
@Override
public void savePersonList(List<Person> personList) {
PersonService personService = applicationContext.getBean(PersonService.class);
//获取personService对象
for (Person person : personList){
personService.savePerson(person); //通过personService进行方法调用
}
}
}
localhost:8080/person/hello,控制台输出:
2022-04-29 19:08:22.885 DEBUG 1391 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [com.example.demo.service.impl.PersonServiceImpl.savePerson]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
2022-04-29 19:08:22.985 DEBUG 1391 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238] for JDBC transaction
2022-04-29 19:08:22.987 DEBUG 1391 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238] to manual commit
com.example.demo.pojo.Person@59f295be
2022-04-29 19:08:23.042 DEBUG 1391 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
2022-04-29 19:08:23.042 DEBUG 1391 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Committing JDBC transaction on Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238]
2022-04-29 19:08:23.050 DEBUG 1391 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Releasing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238] after transaction
localhost:8080/person/hello2,控制台输出:
2022-04-29 19:08:28.476 DEBUG 1391 --- [nio-8080-exec-3] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [com.example.demo.service.impl.PersonServiceImpl.savePerson]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
2022-04-29 19:08:28.477 DEBUG 1391 --- [nio-8080-exec-3] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238] for JDBC transaction
2022-04-29 19:08:28.477 DEBUG 1391 --- [nio-8080-exec-3] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238] to manual commit
com.example.demo.pojo.Person@545f5832
2022-04-29 19:08:28.486 DEBUG 1391 --- [nio-8080-exec-3] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
2022-04-29 19:08:28.487 DEBUG 1391 --- [nio-8080-exec-3] o.s.jdbc.support.JdbcTransactionManager : Committing JDBC transaction on Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238]
2022-04-29 19:08:28.493 DEBUG 1391 --- [nio-8080-exec-3] o.s.jdbc.support.JdbcTransactionManager : Releasing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41f1f238] after transaction
此时,savePerson执行了事务操作
AopContext.currentProxy
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
DataConfig
@Configuration
@MapperScan("com.example.demo.dao")
@EnableAspectJAutoProxy(exposeProxy = true) //暴露代理
public class DataConfig {
@Bean
public MybatisPlusInterceptor initMybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor =new OptimisticLockerInnerInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
return mybatisPlusInterceptor;
}
}
PersonServiceImpl:获取代理对象,通过代理对象调用方法
@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements PersonService {
@Resource
private PersonMapper personMapper;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void savePerson(Person person) {
personMapper.insert(person);
System.out.println(person.toString());
}
@Override
public void savePersonList(List<Person> personList) {
for (Person person : personList){
((PersonService)AopContext.currentProxy()).savePerson(person);
}
}
}
localhost:8080/person/hello,控制台输出:
2022-04-29 19:20:56.404 DEBUG 1553 --- [nio-8080-exec-2] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [com.example.demo.service.impl.PersonServiceImpl.savePerson]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
2022-04-29 19:20:56.504 DEBUG 1553 --- [nio-8080-exec-2] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca] for JDBC transaction
2022-04-29 19:20:56.506 DEBUG 1553 --- [nio-8080-exec-2] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca] to manual commit
com.example.demo.pojo.Person@5274eadf
2022-04-29 19:20:56.558 DEBUG 1553 --- [nio-8080-exec-2] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
2022-04-29 19:20:56.558 DEBUG 1553 --- [nio-8080-exec-2] o.s.jdbc.support.JdbcTransactionManager : Committing JDBC transaction on Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca]
2022-04-29 19:20:56.566 DEBUG 1553 --- [nio-8080-exec-2] o.s.jdbc.support.JdbcTransactionManager : Releasing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca] after transaction
localhost:8080/person/hello2,控制台输出:
2022-04-29 19:20:59.104 DEBUG 1553 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [com.example.demo.service.impl.PersonServiceImpl.savePerson]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
2022-04-29 19:20:59.105 DEBUG 1553 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca] for JDBC transaction
2022-04-29 19:20:59.105 DEBUG 1553 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca] to manual commit
com.example.demo.pojo.Person@7dd87670
2022-04-29 19:20:59.115 DEBUG 1553 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
2022-04-29 19:20:59.115 DEBUG 1553 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Committing JDBC transaction on Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca]
2022-04-29 19:20:59.121 DEBUG 1553 --- [nio-8080-exec-1] o.s.jdbc.support.JdbcTransactionManager : Releasing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@79889fca] after transaction
此时,savePerson方法触发了事务操作