Springboot+Mybatis-解决JPA、JDBC冲突导致@Transactional事务不生效不回滚的问题
创始人
2025-05-28 21:51:04

Springboot+Mybatis-解决JPA、JDBC冲突导致@Transactional事务不生效不回滚的问题

环境

  • Springboot 1.5.6
  • Mybatis 3.5.3
  • Mybatis-plus 3.3.1

问题产生原因

通过打印事务管理器,发现Mybatis环境下的事务管理器实例为JpaTransactionManager对象,明显不对。

Mybatis事务中使用Jpa的事务管理导致事务失效回滚失败问题;

ORM事务管理器对应关系:

  • Mybatis -> org.springframework.jdbc.datasource.DataSourceTransactionManager@50061d56
  • JPA -> org.springframework.orm.jpa.JpaTransactionManager@204d101

解决方法

添加个@Bean配置,注册jdbc事务管理器DataSourceTransactionManager,其中dataSource由框架自动注入;

项目中jpa、mybatis混用时,需要在使用@Bean(“xxx”)注解注册对象时,对dataSource、sqlSessionFactory、DataSourceTransactionManager显示配置;

//注册
@Configuration
public class MybatisConfig {@Bean("jdbcTransactionManager")public PlatformTransactionManager txManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
//使用
@Transactional(value = "jdbcTransactionManager",rollbackFor = {Exception.class})
public void TestTran4Salf(){...
}

排查过程

输出SQL执行过程

三种配置方式:

  • yml配置

    配置对象:org.apache.ibatis.session.Configuration
mybatis:configuration:#事务注册日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmybatis-plus:mapper-locations: classpath:/mapper/**/**.xmlconfiguration:#事务注册日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpllogging:level:root: info#事务提交回滚日志org.springframework.jdbc.datasource.DataSourceTransactionManager: debug    
  • 修改SqlSessionFactory属性
@Configuration
public class MybatisConfig {@Autowiredprivate List sqlSessionFactoryList;@PostConstructpublic void addSqlInterceptor() {for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {sqlSessionFactory.getConfiguration().addInterceptor(interceptor);sqlSessionFactory.getConfiguration().setCallSettersOnNulls(true);//返回查询中的null值sqlSessionFactory.getConfiguration().setLogImpl(org.apache.ibatis.logging.stdout.StdOutImpl.class);//输出执行SQL}}
}
  • 自定义ConfigurationCustomizer对象
@Configuration
public class MybatisConfig {@Beanpublic ConfigurationCustomizer configurationCustomizer() {return configuration -> {configuration.setObjectWrapperFactory(new MybatisMapWrapperFactory());configuration.setCallSettersOnNulls(true);//返回查询中的null值configuration.setMapUnderscoreToCamelCase(false);//表字段使用下划线命名configuration.setLogImpl(org.apache.ibatis.logging.stdout.StdOutImpl.class);//输出执行SQL};}
}

是否开启了事务支持

注解@EnableTransactionManagement标记启用事务,没加事务不会起作用,手动调用session对象的rollback()也无效;

@EnableTransactionManagement
@SpringBootApplication()
public class StartApplication {public static void main(String[] args) {SpringApplication.run(StartApplication.class, args);}
}

平台管理器是否正确

注入一个事务管理器实例,打印出来看看实例对象是否匹配当前ORM;

@Autowired
PlatformTransactionManager platformTransactionManager;@Test
public String testTran() {System.out.print(">>>>>事务管理器:"+platformTransactionManager);....
}

将执行的SQL打印到控制台方便查看事务执行过程

打开Mybatis执行SQL日志,方便滚出事务执行情况;
>>>>>事务管理器:org.springframework.jdbc.datasource.DataSourceTransactionManager@2fbbdcaCreating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
JDBC Connection [ProxyConnection[PooledConnection[org.postgresql.jdbc.PgConnection@14fc5be1]]] will be managed by Spring
==>  Executing: select * from mytable; 
<==      Total: 2
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6] from current transaction  --事务
==>  Preparing: insert into mytable(log_id, create_date) VALUES ('1678872584952_1',now()); 
==> Parameters: 
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6] from current transaction  --事务
==>  Preparing: insert into mytable(log_id, create_date) VALUES ('1678872584952_2',now()); 
==> Parameters: 
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6] from current transaction  --事务
==>  Preparing: insert into mytable(log_id, create_date) VALUES ('1678872584952_2',now()); 
==> Parameters: 
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务

引起事务失效的几个坑

坑1:未启用Spring事务托管

启动类上需要显示加入@EnableTransactionManagement注解,否则事务不生效。

坑2:ORM混用导致平台事务管理器有多个

Mybatis和JPA事务管理器对应关系:

  • Mybatis -> org.springframework.jdbc.datasource.DataSourceTransactionManager@50061d56
  • JPA -> org.springframework.orm.jpa.JpaTransactionManager@204d101

坑3:默认业务异常不回滚

@Transactional() 未指定时,只对运行时异常回滚;

@Transactional(rollbackFor = {Exception.class})此时会对所有异常回滚;

坑4:手动捕获了异常没有抛出也会引起事务失效

try {mapper.insert(sql1);mapper.insert(sql2);
}catch (Exception e){e.printStackTrace();throw e;  //注释掉这行将不回滚
}

坑5:@Transaction注解只对方法名为pubic的才生效,其他事物不会生效。

相关内容

热门资讯

于选择的英文作文【推荐6篇】 于选择的英文作文 篇一The Power of ChoiceChoice is a fundamen...
学校生活英语作文 学校生活英语作文(通用22篇)  在平平淡淡的日常中,许多人都有过写作文的经历,对作文都不陌生吧,作...
介绍家乡英语作文(精彩6篇) 介绍家乡英语作文 篇一My HometownI come from a small town cal...
阅读的英语作文Reading... 阅读的英语作文Reading 篇一The Importance of ReadingReading ...
优秀英语作文 优秀英语作文(通用34篇)  在日复一日的学习、工作或生活中,大家都尝试过写作文吧,作文一定要做到主...