Spring整合MyBatis下@Transactional无效解决方案
来源:互联网 发布:电脑版阅读软件 编辑:程序博客网 时间:2024/06/07 02:39
场景复现
Spring + MyBatis 整合,将事务交给 Spring 处理,配置如下:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描mapping.xml文件 --> <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property></bean><bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.sankuai.dao.mapper" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property></bean><bean id="donateTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSource"/> </property></bean><!-- 用注解来实现事务管理 --><tx:annotation-driven transaction-manager="donateTransactionManager" proxy-target-class="true"/>
业务调用过程:
@Overridepublic Object bus() { try { //前置处理 // 事务提交 trans(); // 后置处理 } catch (Exception e) { log.error("error : {}", e); } return rsp;}@Transactionalprivate void trans() { // 多条SQL}
bus调用trans完成事务提交,按道理这样实现没什么毛病,但是问题是事务不起作用,有心的可以先思考一下为什么不起作用。
问题分析
以上配置存在如下问题:
1. @Transactional 只能应用在作用于为public的方法上,其它的无效,也不会抛出异常,由AOP的触发机制决定的;
2. @Transactional 只作用于外部调用的情况下(触发AOP),函数内部调用也无效;
3. SpringMVC扫描时也有可能覆盖(这里没出现,如:applicationContext.xml设置了component-scan,spring-mvc.xml也component-scan了同一个包,也会导致覆盖无效);
解决方案
有如下三种解决方案:
1. 操作MyBatis的sqlSession
sqlSession.rollBack();...sqlSession.commit();
无效,因为整合了spring-mybatis,已将事务交于spring处理,此法不通
2. 直接在bus上@Transactional
简单易用,缺点是将事务拉长,影响巨大,如果方法体中有RPC,那绝对不能用这种方法
3. 使用编程式事务
虽有代码入侵,但也是最折中的方法,实现如下:
1.简单封装事务助手类
import org.springframework.transaction.PlatformTransactionManager;import org.springframework.transaction.TransactionDefinition;import org.springframework.transaction.TransactionStatus;import org.springframework.transaction.support.DefaultTransactionDefinition;/** * @author 黄平财 * @date 2017/11/27 16:46 * @email hpingcai@gmail.com */public class TransactionHelper { public static final String TRANSACTIONAL_BEAN_ID = "transactionManager"; private PlatformTransactionManager transactionManager; // 记录事务状态 private TransactionStatus status; // 可以在外部定义事务规则 private DefaultTransactionDefinition definition; /** * 默认规则创建事务过程 * * @return */ public static TransactionHelper newInstance() { return new TransactionHelper(); } /** * 根据事务规则创建事务 * * @param definition * @return */ public static TransactionHelper newInstance(DefaultTransactionDefinition definition) { return new TransactionHelper(definition); } private TransactionHelper(DefaultTransactionDefinition definition) { this.definition = definition; transactionManager = (PlatformTransactionManager) SpringContextHolder.getBean(TRANSACTIONAL_BEAN_ID); } private TransactionHelper() { this(new DefaultTransactionDefinition()); this.definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); } /** * 开启事务 */ public void begin() { status = transactionManager.getTransaction(definition); } public void rollBack() { transactionManager.rollback(status); finish(); } public void commit() { transactionManager.commit(status); finish(); } private void finish() { definition = null; status = null; transactionManager = null; }}
2.持有SpringContext对象
import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;import javax.annotation.PreDestroy;/** * @author 黄平财 * @date 2017/11/27 17:15 * @email hpingcai@gmail.com */@Componentpublic class SpringContextHolder implements ApplicationContextAware { private static ApplicationContext APPLICATION_CONTEXT; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextHolder.APPLICATION_CONTEXT = applicationContext; } public static Object getBean(String name) { return APPLICATION_CONTEXT.getBean(name); } public static Object getBean(String name, Class clazz) { return APPLICATION_CONTEXT.getBean(name, clazz); } @PreDestroy public void destroy() { SpringContextHolder.APPLICATION_CONTEXT = null; }}
3.使用
private void trans() { TransactionHelper helper = TransactionHelper.newInstance(); try{ helper.begin(); // 多条SQL helper.commit(); }catch (Exception e){ if(null!=helper){ helper.rollBack(); } throw e; }}
结语
当然,这也是我当前能想到的较好的解决方案,代码写的有点简陋,如果有更合适的解决方案,欢迎留言探讨。
引用
静态持有ApplicationContext:https://www.cnblogs.com/wcyBlog/p/4657885.html
阅读全文
0 0
- Spring整合MyBatis下@Transactional无效解决方案
- @Transactional 无效的解决方案
- @Transactional 无效的解决方案
- SSM框架下利用mybatis-spring.jar整合包,以及利用注解@transactional实现事务管理
- Spring 下默认事务机制中@Transactional 无效的原因
- Spring 下默认事务机制中@Transactional 无效的原因
- Spring 下默认事务机制中@Transactional 无效的原因
- Spring @Transactional 配置无效 注意事项
- spring synchronized Transactional 无效解决办法
- spring + mybatis @Transactional @Rollback 单元测试
- spring整合mybatis ORA-00911: 无效字符问题解决方式
- Spring @Transactional事物配置无效原因
- Spring @Transactional注解不回滚不起作用无效
- maven工程下整合spring+mybatis+freemarker
- Maven下Spring-Mybatis注解式整合
- mybatis+spring maven下 整合 完整demo
- Mybatis -- Mybatis整合Spring
- 【Mybatis】Mybatis整合spring
- Android本地存储总结
- IO流(二)
- iOS 多线程小结
- JAVA基础——初识JAVA(一)(第一个java程序)
- Go语言报错cannot define new methods on non-local type
- Spring整合MyBatis下@Transactional无效解决方案
- 两年计划
- 博客正式开通,踏入IT之路。
- Java 十六进制(Hex)与byte数组之间的转换
- SpringBoot(三)
- 游戏简介
- C#通过正规表达式提取html中的Email
- 从面向过程到面向对象的转变----C++
- pyqt5 子线程更新ui