1.springboot中的事务事务事务是如何实现的?懂吗?
2.Springboot之分布式事务框架Seata实现原理源码分析
3.SpringBoot事物Transaction实战讲解教程
4.springâAOPä¸äºå¡
5.Spring Boot业务代码中使用@Transactional事务失效踩坑点总结
6.万字详谈SpringBoot多数据源以及事务处理
springboot中的事务是如何实现的?懂吗?
在 Spring Boot 中,事务的源码源码实现主要依赖于 @Transactional 注解。此注解在项目代码中广泛使用,事务事务尤其是源码源码 @Transactional(readOnly = true),被许多开发者认为能提高性能。事务事务本文将深入探讨 @Transactional(readOnly = true) 的源码源码spring shiro源码工作原理,以及是事务事务否在服务层的只读方法中总是应使用此注解。同时,源码源码我们还将分析在使用 JPA 时,事务事务@Transactional(readOnly = true) 的源码源码应用与可能带来的权衡。
在实现过程中,事务事务当我们使用 @Transactional(readOnly = true) 时,源码源码事务管理器接收到此提示,事务事务可以优化查询过程。源码源码以 JpaTransactionManager 为例,事务事务它在内部委托给 JpaDialect 来具体执行事务的开始。在 HibernateJpaDialect 类中,我们看到在处理 readOnly = true 选项时,JpaDialect 禁止了刷新操作。同时,将 session.setDefaultReadOnly(true) 语句用于设置会话的只读属性,进一步确保了在只读模式下,实体不会进行脏检查,也不会维护持久状态的快照,且只读实体的更改不被持久化。
当我们讨论是否在服务层的只读方法中使用 @Transactional(readOnly = true) 时,需要考虑其潜在优势与潜在风险。使用此注解确实带来了诸多益处,比如避免了不必要的直播平台源码 开源事务提交,提高了查询性能。然而,如果服务层的方法包含大量逻辑处理,将其标记为只读则可能引发问题,例如数据库死锁、性能下降和数据库连接耗尽。
通过实际测试,我们发现在服务层方法中使用 @Transactional(readOnly = true),直到方法执行结束才释放数据库连接;而在存储库层方法中,查询结果到达后即释放连接。这表明,长时间执行的服务层方法可能因持有数据库连接过久而影响性能和资源管理。
综上所述,@Transactional(readOnly = true) 在适当的应用场景中能够带来显著性能提升,但需注意其在服务层中的使用可能带来的潜在风险。当服务层方法仅包含只读查询时,使用此注解是合理的;然而,当方法包含大量逻辑处理时,开发者应谨慎考虑,权衡性能与资源管理的需求。
Springboot之分布式事务框架Seata实现原理源码分析
在Springboot 2.2. + Seata 1.3.0环境中,Seata通过GlobalTransactionScanner实现全局事务管理。首先,它会扫描带有@GlobalTransactional注解的方法类,作为BeanPostProcessor处理器,通过InstantiationAwareBeanPostProcessor的postProcessAfterInitialization方法中的wrapIfNecessary方法进行全局事务拦截。
GlobalTransactionScanner判断类方法是否有@GlobalTransactional注解,如果没有则直接返回,onvif test tool 源码否则创建GlobalTransactionalInterceptor。拦截器负责全局事务的执行,包括事务开始、执行本地业务、提交和回滚等步骤。例如,事务开始时,Seata通过SPI技术将xid绑定到当前线程,执行过程中会记录undo log以实现回滚。
Seata自动配置会创建代理数据源(DataSourceProxy),在数据源方法调用时进行代理处理。当调用带有全局事务的方法时,如RestTemplate和Feign,拦截器会传递XID到请求头中,确保跨服务的事务一致性。参与者(被调用服务)通过SeataHandlerInterceptor拦截器获取并绑定XID,然后通过ConnectionProxy代理进行数据库操作,其中ConnectionContext用于判断是否为全局事务。
总结来说,Seata的核心机制是通过代理、拦截器和XID的传递,确保分布式环境下的事务处理协调和一致性。
SpringBoot事物Transaction实战讲解教程
本篇文章主要介绍的是SpringBoot中事物Transaction的使用教程。在进行SpringBoot开发时,事务管理对于保证数据的一致性和完整性至关重要。以下将从事务管理方式、提交方式、隔离级别、fiddler抓取网页源码事务传播行为、回滚规则、常用配置、注意事项等方面进行详细讲解。
在Spring中,事务管理有两种方式:编程式事务管理和声明式事务管理。编程式事务管理需要手动设置事务的开始、提交、回滚等,而声明式事务管理则通过注解实现事务的声明。
默认情况下,数据库处于自动提交模式。每条SQL语句处于一个单独的事务中,若执行成功则隐式提交,若执行失败则隐式回滚。为了正常的事务管理,需关闭数据库自动提交模式。Spring会将底层连接的自动提交特性设置为false,等价于JDBC的connection.setAutoCommit(false);,执行完毕后进行提交connection.commit();
事务隔离级别是指并发事务之间的隔离程度,TransactionDefinition接口定义了五种隔离级别常量,分别为读未提交(READ_UNCOMMITTED)、读已提交(READ_COMMITTED)、可重复读(REPEATABLE_READ)、序列化(SERIALIZABLE)和未提交读(READ_COMMITTED)。
事务传播行为决定了在开始当前事务之前,事务上下文已存在时,事务性方法的坚果手机海报源码执行行为。TransactionDefinition中定义了多个传播行为常量,如PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_SUPPORTS等。
事务回滚规则由spring事务管理器决定,通常在当前事务上下文抛出异常时回滚事务。默认情况下,只有运行时unchecked异常才会导致事务回滚,抛出checked异常则不会。可以明确配置哪些异常抛出时回滚事务,包括checked异常。
SpringBoot中常用事务配置包括@Transactional注解,用于标记方法为事务方法。注解参数如readOnly、rollbackFor、noRollbackFor、propagation等,用于控制事务的特性。
开发时,需要确保环境满足要求:使用JDK1.8和SpringBoot1.5..RELEASE。相关依赖和配置如Maven pom.xml文件、application.properties文件。
在使用@Transactional注解时,需在service层的公共方法上添加该注解。使用示例展示事务的配置和测试。通过Postman进行API测试,验证事务是否成功执行。
本文还介绍了事务的几种使用示例,包括手动回滚、使用其他方法进行事务控制、结合DataSourceTransactionManager和TransactionDefinition类进行手动控制事务。同时提供了SpringBoot项目工程的地址供参考。
springâAOPä¸äºå¡
title: springââAOPä¸äºå¡.mddate: -- ::
categories: [Spring]
tags: [AOP,äºå¡]
toc: true
å ååºæºç ä¸æ¯è¾éç¹çå 个类ï¼
1ã<aop:before method="before" pointcut-ref="myMethods"/>å è£ æä¸ä¸ªadvisor
2ãAspectJAwareAdvisorAutoProxyCreatorï¼å½å®ä¾åææbeané½ä¼æ§è¡å°AspectJAwareAdvisorAutoProxyCreatorç±»
å®ä¼æ£æµbeanæ¯å¦advisor以åadviceåå¨ï¼å¦ææ就说æè¿ä¸ªbeanæåé¢ï¼æåé¢é£ä¹å°±ä¼çæ代ç
3ãjdkç代çï¼beanéé¢çææadvisorå å ¥å°proxyFactoryã
4ãjdkDynamicProxy invokeï¼æ¿å°beanéé¢çææInterceptorï¼ä¼å¾ªç¯proxyFactoryéé¢çææadvisor
éé¢æadviceï¼éé¢çadviceæ两ç§ç±»åï¼è¦ä¹æ¯adviceï¼è¦ä¹æ¯MethodInterceptorç±»åç
5ãå½ä»£ç对象è°ç¨æ¹å¼ï¼æ¯ä¸ä¸ªMethodInterceptorç±»åçç±»çé¾å¼è°ç¨è¿ç¨ï¼ç´å°å®¹å¨ç大å°åç´¢å¼ä¸è´çæ¶åè°ç¨JoinPointç®æ æ¹æ³
beforeï¼this.advice.before(),invocation.processd();
è£ é åæ°ï¼åé¢éé¢beforeæ¹æ³çmethod对象ï¼method.getParamterTypes()[0]
æç»ä¼æadviceå°è£ æMethodInterceptorç±»åç对象
ç¨åºæ§è¡çæ个ç¹å®ä½ç½®ï¼å¦ç±»å¼å§åå§ååãç±»åå§ååãç±»æ个æ¹æ³è°ç¨åãè°ç¨åãæ¹æ³æåºå¼å¸¸åãä¸ä¸ªç±»æä¸æ®µç¨åºä»£ç æ¥æä¸äºå ·æè¾¹çæ§è´¨çç¹å®ç¹ï¼è¿äºç¹ä¸çç¹å®ç¹å°±ç§°ä¸ºâè¿æ¥ç¹âãSpringä» æ¯ææ¹æ³çè¿æ¥ç¹ï¼å³ä» è½å¨æ¹æ³è°ç¨åãæ¹æ³è°ç¨åãæ¹æ³æåºå¼å¸¸æ¶ä»¥åæ¹æ³è°ç¨ååè¿äºç¨åºæ§è¡ç¹ç»å ¥å¢å¼ºãè¿æ¥ç¹ç±ä¸¤ä¸ªä¿¡æ¯ç¡®å®ï¼ç¬¬ä¸æ¯ç¨æ¹æ³è¡¨ç¤ºçç¨åºæ§è¡ç¹ï¼ç¬¬äºæ¯ç¨ç¸å¯¹ç¹è¡¨ç¤ºçæ¹ä½ã
æ¯ä¸ªç¨åºç±»é½æ¥æå¤ä¸ªè¿æ¥ç¹ï¼å¦ä¸ä¸ªæ¥æ两个æ¹æ³çç±»ï¼è¿ä¸¤ä¸ªæ¹æ³é½æ¯è¿æ¥ç¹ï¼å³è¿æ¥ç¹æ¯ç¨åºç±»ä¸å®¢è§åå¨çäºç©ãAOPéè¿âåç¹âå®ä½ç¹å®çè¿æ¥ç¹ãè¿æ¥ç¹ç¸å½äºæ°æ®åºä¸çè®°å½ï¼èåç¹ç¸å½äºæ¥è¯¢æ¡ä»¶ãåç¹åè¿æ¥ç¹ä¸æ¯ä¸å¯¹ä¸çå ³ç³»ï¼ä¸ä¸ªåç¹å¯ä»¥å¹é å¤ä¸ªè¿æ¥ç¹ãå¨Springä¸ï¼åç¹éè¿org.springframework.aop.Pointcutæ¥å£è¿è¡æè¿°ï¼å®ä½¿ç¨ç±»åæ¹æ³ä½ä¸ºè¿æ¥ç¹çæ¥è¯¢æ¡ä»¶ï¼Spring AOPçè§å解æå¼æè´è´£åç¹æ设å®çæ¥è¯¢æ¡ä»¶ï¼æ¾å°å¯¹åºçè¿æ¥ç¹ãå ¶å®ç¡®åå°è¯´ï¼ä¸è½ç§°ä¹ä¸ºæ¥è¯¢è¿æ¥ç¹ï¼å 为è¿æ¥ç¹æ¯æ¹æ³æ§è¡åãæ§è¡åçå æ¬æ¹ä½ä¿¡æ¯çå ·ä½ç¨åºæ§è¡ç¹ï¼èåç¹åªå®ä½å°æ个æ¹æ³ä¸ï¼æ以å¦æå¸æå®ä½å°å ·ä½è¿æ¥ç¹ä¸ï¼è¿éè¦æä¾æ¹ä½ä¿¡æ¯ã
å¢å¼ºæ¯ç»å ¥å°ç®æ ç±»è¿æ¥ç¹ä¸çä¸æ®µç¨åºä»£ç ï¼å¨Springä¸ï¼å¢å¼ºé¤ç¨äºæè¿°ä¸æ®µç¨åºä»£ç å¤ï¼è¿æ¥æå¦ä¸ä¸ªåè¿æ¥ç¹ç¸å ³çä¿¡æ¯ï¼è¿ä¾¿æ¯æ§è¡ç¹çæ¹ä½ãç»åæ§è¡ç¹æ¹ä½ä¿¡æ¯ååç¹ä¿¡æ¯ï¼æ们就å¯ä»¥æ¾å°ç¹å®çè¿æ¥ç¹ã
å¢å¼ºé»è¾çç»å ¥ç®æ ç±»ãå¦æ没æAOPï¼ç®æ ä¸å¡ç±»éè¦èªå·±å®ç°ææé»è¾ï¼èå¨AOPç帮å©ä¸ï¼ç®æ ä¸å¡ç±»åªå®ç°é£äºé横åé»è¾çç¨åºé»è¾ï¼èæ§è½çè§åäºå¡ç®¡ççè¿äºæ¨ªåé»è¾åå¯ä»¥ä½¿ç¨AOPå¨æç»å ¥å°ç¹å®çè¿æ¥ç¹ä¸ã
å¼ä»æ¯ä¸ç§ç¹æ®çå¢å¼ºï¼å®ä¸ºç±»æ·»å ä¸äºå±æ§åæ¹æ³ãè¿æ ·ï¼å³ä½¿ä¸ä¸ªä¸å¡ç±»åæ¬æ²¡æå®ç°æ个æ¥å£ï¼éè¿AOPçå¼ä»åè½ï¼æ们å¯ä»¥å¨æå°ä¸ºè¯¥ä¸å¡ç±»æ·»å æ¥å£çå®ç°é»è¾ï¼è®©ä¸å¡ç±»æ为è¿ä¸ªæ¥å£çå®ç°ç±»ã
ç»å ¥æ¯å°å¢å¼ºæ·»å 对ç®æ ç±»å ·ä½è¿æ¥ç¹ä¸çè¿ç¨ãAOPåä¸å°ç»å¸æºï¼å°ç®æ ç±»ãå¢å¼ºæå¼ä»éè¿AOPè¿å°ç»å¸æºå¤©è¡£æ ç¼å°ç¼ç»å°ä¸èµ·ãæ ¹æ®ä¸åçå®ç°ææ¯ï¼AOPæä¸ç§ç»å ¥çæ¹å¼ï¼
aãç¼è¯æç»å ¥ï¼è¿è¦æ±ä½¿ç¨ç¹æ®çJavaç¼è¯å¨ã
bãç±»è£ è½½æç»å ¥ï¼è¿è¦æ±ä½¿ç¨ç¹æ®çç±»è£ è½½å¨ã
cãå¨æ代çç»å ¥ï¼å¨è¿è¡æ为ç®æ 类添å å¢å¼ºçæåç±»çæ¹å¼ã
Springéç¨å¨æ代çç»å ¥ï¼èAspectJéç¨ç¼è¯æç»å ¥åç±»è£ è½½æç»å ¥ã
ä¸ä¸ªç±»è¢«AOPç»å ¥å¢å¼ºåï¼å°±äº§åºäºä¸ä¸ªç»æç±»ï¼å®æ¯èåäºåç±»åå¢å¼ºé»è¾ç代çç±»ãæ ¹æ®ä¸åç代çæ¹å¼ï¼ä»£çç±»æ¢å¯è½æ¯ååç±»å ·æç¸åæ¥å£çç±»ï¼ä¹å¯è½å°±æ¯åç±»çåç±»ï¼æ以æ们å¯ä»¥éç¨è°ç¨åç±»ç¸åçæ¹å¼è°ç¨ä»£çç±»ã
åé¢ç±åç¹åå¢å¼ºï¼å¼ä»ï¼ç»æï¼å®æ¢å æ¬äºæ¨ªåé»è¾çå®ä¹ï¼ä¹å æ¬äºè¿æ¥ç¹çå®ä¹ï¼Spring AOPå°±æ¯è´è´£å®æ½åé¢çæ¡æ¶ï¼å®å°åé¢æå®ä¹ç横åé»è¾ç»å ¥å°åé¢ææå®çè¿æ¥ç¹ä¸ã
advisorï¼ pointCut advice
ä¸ç±»åè½çå¢å¼º
aroundæ¹æ³éé¢ä»£ç åé¢
äºå¡åé¢
ç¼ååé¢
æ¥å¿åé¢
äºå¡ï¼Transactionï¼ï¼ä¸è¬æ¯æè¦åçææåçäºæ ãå¨è®¡ç®æºæ¯è¯ä¸æ¯æ访é®å¹¶å¯è½æ´æ°æ°æ®åºä¸åç§æ°æ®é¡¹çä¸ä¸ªç¨åºæ§è¡åå (unit)ãæ¯æ°æ®åºæä½çæå°å·¥ä½åå ï¼æ¯ä½ä¸ºå个é»è¾å·¥ä½åå æ§è¡çä¸ç³»åæä½ï¼è¿äºæä½ä½ä¸ºä¸ä¸ªæ´ä½ä¸èµ·åç³»ç»æ交ï¼è¦ä¹é½æ§è¡ãè¦ä¹é½ä¸æ§è¡ï¼äºå¡æ¯ä¸ç»ä¸å¯ååå²çæä½éåï¼å·¥ä½é»è¾åå ï¼ã
大è´æµç¨å½¢å¦
æ°æ®åºäºå¡æ¥æå 大ç¹æ§ï¼
äºå¡çå大ç¹æ§ï¼
äºå¡æ¯æ°æ®åºçé»è¾å·¥ä½åä½ï¼äºå¡ä¸å å«çåæä½è¦ä¹é½åï¼è¦ä¹é½ä¸å
äº å¡æ§è¡çç»æå¿ é¡»æ¯ä½¿æ°æ®åºä»ä¸ä¸ªä¸è´æ§ç¶æåå°å¦ä¸ä¸ªä¸è´æ§ç¶æãå æ¤å½æ°æ®åºåªå å«æåäºå¡æ交çç»ææ¶ï¼å°±è¯´æ°æ®åºå¤äºä¸è´æ§ç¶æãå¦ææ°æ®åºç³»ç» è¿è¡ä¸åçæ éï¼æäºäºå¡å°æªå®æ就被迫ä¸æï¼è¿äºæªå®æäºå¡å¯¹æ°æ®åºæåçä¿®æ¹æä¸é¨åå·²åå ¥ç©çæ°æ®åºï¼è¿æ¶æ°æ®åºå°±å¤äºä¸ç§ä¸æ£ç¡®çç¶æï¼æè è¯´æ¯ ä¸ä¸è´çç¶æã
ä¸ä¸ªäºå¡çæ§è¡ä¸è½å ¶å®äºå¡å¹²æ°ãå³ä¸ä¸ªäºå¡å é¨çæä½å使ç¨çæ°æ®å¯¹å ¶å®å¹¶åäºå¡æ¯é离çï¼å¹¶åæ§è¡çå个äºå¡ä¹é´ä¸è½äºç¸å¹²æ°ã
ä¹ç§°æ°¸ä¹ æ§ï¼æä¸ä¸ªäºå¡ä¸æ¦æ交ï¼å®å¯¹æ°æ®åºä¸çæ°æ®çæ¹åå°±åºè¯¥æ¯æ°¸ä¹ æ§çãæ¥ä¸æ¥çå ¶å®æä½ææ éä¸åºè¯¥å¯¹å ¶æ§è¡ç»ææä»»ä½å½±åã
个人ç解ï¼äºå¡å¨Springä¸æ¯åå©AOPææ¯æ¥å®ç°çï¼å¯ä»¥ä½ä¸ºAOPä¸çä¸ä¸ªäºå¡åé¢ãspringæºç 对äºå¡çå¤çé»è¾ï¼èªå·±ç 究å§ï¼
ORMæ¡æ¶ä¸ä»¥Mybatis为ä¾ï¼äºå¡å¤çå°±æ¯ç¨å°äºä¸ä¸ªç±»Transactionï¼é¨åæºç å¦ä¸
å¯ä»¥çåºTransaction管ççå°±æ¯ä¸ä¸ªconnectionï¼èconnectionæ们å¾æ¸ æ¥æ¯ä¸ç¨æ·ä¼è¯æé©çã
é£ä¹å ³ç³»å°±æ¯Transaction 管çConnection ï¼èconnectionä¸ ç¨æ·sessionä¸å¯¹ä¸åå¨ã
å¨springBootä¸ï¼åªéè¦å å ¥POMå°±å¯ä»¥äºï¼é å注解使ç¨å³å¯ã
æ¥ä¸æ¥å°±æ¯äºå¡çæ§å¶äºã
é¦å äºå¡æå å¤§ä¼ æå±æ§ï¼
å ¶ä¸æ常è§çï¼ç¨å¾æå¤å°± PROPAGATION_REQUIREDãPROPAGATION_REQUIRES_NEWã PROPAGATION_NESTED è¿ä¸ç§ãäºå¡çä¼ æå±æ§æ¯ spring ç¹æçï¼æ¯ spring ç¨æ¥æ§å¶æ¹æ³äºå¡çä¸ç§æ段ï¼è¯´ç´ç½ç¹å°±æ¯ç¨æ¥æ§å¶æ¹æ³æ¯å¦ä½¿ç¨åä¸äºå¡çä¸ç§å±æ§ï¼ä»¥åæç §ä»ä¹è§ååæ»çä¸ç§æ段ã
ä¸é¢ç¨ä»£ç æ¼ç¤ºè¿ä¸ç§å±æ§çæºå¶ï¼
äºå¡çé»è®¤å±æ§å°±æ¯requiredï¼éè¿Transactional.javaä¸çPropagation propagation() default Propagation.REQUIRED; å¯ä»¥çåºã
è¿ç§æ åµå°±æ¯äºå¡1ï¼äºå¡2 é½å å ¥å°äºäºå¡0ä¸ãä¸ç®¡æ¯1ï¼2åªä¸ªäºå¡æåºå¼å¸¸ï¼äºå¡0é½ä¼åæ»ãæ°æ®æ·»å ä¼å¤±è´¥ã
è¿ç§æ åµå°±æ¯ï¼
äºå¡0ï¼requiredï¼ {
äºå¡1 ï¼REQUIRES_NEWï¼
äºå¡2
}
æ¤æ¶ã
æ åµaï¼
1ãå¦æåªæ¯äºå¡2åºç°äºå¼å¸¸ï¼é£ä¹äºå¡1ä¼æ交ï¼äºå¡2å å ¥å°äºå¡0ä¸ä¼åæ»ã
2ãå¦æåªæ¯äºå¡1åºç°äºå¼å¸¸ï¼é£ä¹äºå¡1ä¼åæ»ï¼åä¸å±äºå¡0æå¼å¸¸ï¼äºå¡2ä¼å å ¥å°äºå¡0ä¸ï¼è¿æ¶é½ä¼åæ»ã
æ åµbï¼
å¦æäºå¡1ï¼äºå¡2é½æ¯REQUIRES_NEWä¼ æå±æ§ãé£ä¹ç»æå°±æ¯ï¼
1ãå¦æäºå¡1ï¼æåºäºå¼å¸¸ï¼é£ä¹äºå¡2æ¯ä¸ä¼æ§è¡çï¼é£ä¹äºå¡0å¿ ç¶åæ»ã
2ãå¦æäºå¡2ï¼æåºå¼å¸¸ï¼é£ä¹äºå¡1ä¼æ交ï¼è¡¨ä¸ä¼ææ°æ®ãäºå¡2æå¼å¸¸åæ»å¹¶æåºï¼äºå¡0åæ»ã
NESTEDå±æ§å ¶å®å°±æ¯å建äºåæ»ç¹ï¼æå¼å¸¸æ¶ï¼ä¼åæ»å°æå®çåæ»ç¹ã
å¨è¿éè¿ä»£ç æµè¯ï¼åºç°ä¸ç§æ åµæ¯ï¼æ 论äºå¡1ï¼äºå¡2åªä¸ªæå¼å¸¸ï¼æ°æ®é½ä¸ä¼æå ¥æåï¼åå æ¯ï¼ä¸è®ºæ¯äºå¡1è¿æ¯äºå¡2é½ä¼åäºå¡0æåºå¼å¸¸ï¼äºå¡0æè·å°å¼å¸¸åï¼æ§è¡rollback()æ¹æ³ï¼è¿å°±æä½æäºï¼äºå¡çå ¨é¨åæ»ã
å¦ææ³è¦äºå¡1åäºå¡2 æ³è¦æ ¹æ®èªå·±çåæ»ç¹åæ»ï¼é£ä¹äºå¡0å¿ é¡»èªå·±å¤çå¼å¸¸ï¼ä¸è®©springæè·å°è¿ä¸ªå¼å¸¸ï¼é£ä¹å°±æ»¡è¶³äºãæ代ç æ¹æè¿ç§ï¼
Jack大佬æä¾äºï¼ä¼ªä»£ç åææ³ã
æç §Springæºç çäºå¡å¤çé»è¾ï¼ä¼ªä»£ç 大è´ä¸ºï¼
Spring Boot业务代码中使用@Transactional事务失效踩坑点总结
在Spring Boot项目中,事务管理是确保数据一致性的关键工具。通常,我们通过在方法上添加@Transactional注解来实现声明式事务控制。然而,实际应用中,事务的正确使用和管理可能会遇到一些陷阱,这些陷阱可能导致数据不一致或系统性能问题。下面总结了一些常见的事务失效场景、原因以及修正方法,旨在帮助开发者避免这些坑点。 在项目开发中,当涉及多个数据库操作时,使用@Transactional确保操作的一致性和原子性至关重要。然而,很多开发者仅将关注点放在了标记方法为@Transactional上,忽略了更深层次的事务控制细节。实际上,正确理解并应用@Transactional注解的属性,可以有效避免在复杂业务逻辑中出现的事务失效问题。 首先,需要明确的是,@Transactional注解不仅可应用于方法上,还适用于类级别,表示该类的公共方法都将遵循相同的事务属性配置。注解内部的几个关键属性包括:propagation:决定事务的传播行为,如何处理嵌套事务。
isolation:事务的隔离级别,用于解决并发操作的冲突问题。
timeout:事务的超时时间,超过后将自动回滚。
readOnly:指示事务是否为只读,允许忽略事务控制。
rollbackFor和noRollbackFor:定义触发回滚和不回滚异常类型。
接下来,让我们深入分析一些常见的@Transactional失效场景及其修正方法:场景1:方法间的相互调用导致事务失效
在类内部方法相互调用时,若未通过代理机制调用,则@Transactional注解可能无法生效。这是因为Spring通过AOP技术实现事务管理,必须通过代理对象调用方法才能实现事务控制。 修正方法:确保所有方法调用都通过代理对象进行,避免直接使用this调用。场景2:异常被捕获导致事务回滚失效
当方法内部捕获异常后,异常没有向外抛出,导致@Transactional注解无法检测到异常并触发回滚。 修正方法:尽量在局部范围内处理异常,避免过早捕获并处理异常,确保异常能够正常传播并触发回滚。场景3:rollbackFor属性设置不当
若未正确配置rollbackFor,导致触发的异常类型不符合回滚条件,事务可能无法正常回滚。 修正方法:明确设置rollbackFor属性,指定需要回滚的异常类型。场景4:非public方法使用@Transactional
使用@Transactional注解的方法必须是public可见,private方法不可见于代理类,因此无法被事务管理。 修正方法:将方法声明为public,确保其可见于代理对象。场景5:propagation属性设置错误
正确的传播属性设置可以确保事务在遇到异常时能够正确回滚,避免影响整个操作。 修正方法:检查propagation属性设置,确保其符合业务需求。场景6:长事务导致资源耗尽
长时间运行的事务可能导致数据库连接池资源耗尽,影响系统性能。 修正方法:合理拆分事务,避免长时间操作占用连接资源。 总结而言,正确理解并合理应用@Transactional注解,结合事务管理的最佳实践,可以有效避免在项目开发过程中遇到的事务失效问题,确保系统的数据一致性,提升性能和稳定性。万字详谈SpringBoot多数据源以及事务处理
在高并发环境下,单数据库难以承载大量数据访问,多数据库读写分离与不同存储的微服务项目需求促使多数据源解决方案的实现。主要有两种实现思路:配置多个SqlSessionFactory或使用Spring提供的AbstractRoutingDataSource的DynamicDataSource实现动态数据源切换。实现方案基于Spring Boot 2.7.8,使用Mysql数据库和Mybatis ORM框架,Maven依赖确保项目结构清晰。
通过配置不同的SqlSessionFactory实现多数据源,每个数据库的Mapper层和Dao层分别建立文件夹,分包放置,形成项目结构。使用Yaml文件指定不同库的Mapper层对应不同的SqlSessionFactory。此方法分层明确,代码清晰,每个配置类实现事务管理,无需额外关注。
另一种方案采用Spring AOP+自定义注解,利用AbstractRoutingDataSource的继承结构实现数据源动态切换。通过创建Map存储数据源,根据不同Service方法调用选择对应数据源,实现不同数据库表的事务处理。
在多数据源切换中,事务问题常出现,尤其是当不同数据源的表在同一事务中被操作时。为解决这个问题,需自定义MultiDataSourceTransaction,动态获取不同Connection,避免从缓存中获取,确保跨数据源事务的一致性。
Mybatis自动装配过程中,通过SqlSessionFactoryBean创建SqlSessionFactory,SpringManagedTransactionFactory作为Mybatis与Spring的桥梁,管理事务。MapperFactoryBean通过代理生成代理对象,调用SqlSessionFactory创建SqlSession执行数据库操作。
通过TransactionSynchronizationManager绑定Connection到当前线程,确保MyBatis执行SQL语句使用的Connection与Spring事务管理的Connection一致,实现事务管理。每次切换数据源时,动态获取最新Connection并记录在Map中,回滚时回滚Map中的Connection,最终将自定义的Transaction委托给Spring管理。
引入ImportBeanDefinitionRegistrar接口可实现动态注册数据源到Spring容器,无需手动增加Bean。通过定义该接口的实现类,自定义扫描并注册逻辑,解放开发人员的手动工作。将EnableDynamicDataSource置于SpringBoot启动项之上,完成动态数据源的集成。
实现方案总结,多数据源与事务处理的解决方案在高并发项目中尤为重要。采用多种策略实现数据源切换与事务管理,确保项目性能与稳定性。通过Spring AOP、抽象类继承与自定义注册逻辑,减少开发工作量,提高代码可维护性。最终实现多数据源高效、稳定的运行环境。