大家都知晓的Spring的事物是基于动态机制的,支持CGLIB和JDK动态代理两种。如下所示:
一.CGLIB方式
CGLIB代理无须必须实现接口。
package com.bijian.study.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.bijian.study.dao.IUserMapper; import com.bijian.study.model.User; @Service("userServiceAOP") public class UserServiceAOP { private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); @Autowired private IUserMapper mapper; @Transactional public int txUpdateUsersWhenException() { // 事务性 return innerMethod(); } private int innerMethod() { User user = new User(1, "Before exception"); int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚 log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId()); User user2 = new User(1, "After exception"); int i = 1 / 0; // 抛出运行时异常,事务回滚 int affectedCount2 = mapper.updateUser(user2); // 未执行 log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId()); if (affectedCount == 1 && affectedCount2 == 1) { return 1; } return 0; } }
调试发现确实是CglibAop代理,此时事务是生效的。
二.JDK动态代理
package com.bijian.study.service; public interface UserService { public int txUpdateUsersWhenException(); }
package com.bijian.study.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.bijian.study.dao.IUserMapper; import com.bijian.study.model.User; @Service("userService") public class UserServiceImpl implements UserService { private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); @Autowired private IUserMapper mapper; @Transactional public int txUpdateUsersWhenException() { // 事务性 return innserMethod(); } private int innserMethod() { User user = new User(1, "Before exception"); int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚 log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId()); User user2 = new User(1, "After exception"); int i = 1 / 0; // 抛出运行时异常,事务回滚 int affectedCount2 = mapper.updateUser(user2); // 未执行 log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId()); if (affectedCount == 1 && affectedCount2 == 1) { return 1; } return 0; } }
调试发现确实是JDK动态代理,此时事务是生效的。
三.测试代码
package com.bijian.study.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.bijian.study.service.UserService; import com.bijian.study.service.UserServiceAOP; public class SpringIntegrationTest { private static ApplicationContext ctx; static { ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); } @Test public void txUpdateUsersExceptionTest() { UserService userService = (UserService) ctx.getBean("userService"); userService.txUpdateUsersWhenException(); } @Test public void txUpdateUsersExceptionAOPTest() { UserServiceAOP userServiceAOP = (UserServiceAOP) ctx.getBean("userServiceAOP"); userServiceAOP.txUpdateUsersWhenException(); } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 数据库配置文件 --> <context:property-placeholder location="classpath:/database.properties" /> <!-- 数据源配置 --> <!--本示例采用DBCP连接池,应预先把DBCP的jar包复制到工程的lib目录下。 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" p:driverClassName="${driverClassName}" p:url="${url}" p:username="${user_name}" p:password="${password}" /> <!-- sqlSessionFactory对象 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--dataSource属性指定要用到的连接池 --> <property name="dataSource" ref="dataSource" /> <!--configLocation属性指定mybatis的核心配置文件 --> <property name="configLocation" value="classpath:Configuration.xml" /> <!-- 可以在Configuration.xml或此处配置映射文件,但其中不能有相同id的parameterMap, resultMap或sql等 --> <property name="mapperLocations" value="classpath*:com/bijian/study/model/*.xml" /> </bean> <!-- 扫描指定包以获取映射器 --> <bean id="mapperConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.bijian.study.dao" /> </bean> <!-- 事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 事务注解驱动,标注@Transactional的类和方法将具有事务性 --> <tx:annotation-driven transaction-manager="txManager" /> <bean id="userService" class="com.bijian.study.service.UserServiceImpl" /> <bean id="userServiceAOP" class="com.bijian.study.service.UserServiceAOP" /> <bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <constructor-arg type="org.springframework.transaction.PlatformTransactionManager" ref="txManager" /> </bean> </beans>
database.properties
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://192.168.235.1:3306/hbatis?characterEncoding=utf8 user_name=bijian password=123456
四.将@Transactional放到非外部直接调用的方法上
将@Transactional放到非外部直接调用的方法上,调试发现无代理,事务失效。
1.修改CGLIB方式的服务方法
package com.bijian.study.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.bijian.study.dao.IUserMapper; import com.bijian.study.model.User; @Service("userServiceAOP") public class UserServiceAOP { private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); @Autowired private IUserMapper mapper; public int txUpdateUsersWhenException() { // 事务性 return innerMethod(); } @Transactional private int innerMethod() { User user = new User(1, "Before exception"); int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚 log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId()); User user2 = new User(1, "After exception"); int i = 1 / 0; // 抛出运行时异常,事务回滚 int affectedCount2 = mapper.updateUser(user2); // 未执行 log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId()); if (affectedCount == 1 && affectedCount2 == 1) { return 1; } return 0; } }
@Transactional方法不是服务类的入口方法,无CGLIB代理,事务失效。
2.修改JDK动态代理方式的服务方法
package com.bijian.study.service; public interface UserService { public int txUpdateUsersWhenException(); }
package com.bijian.study.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.bijian.study.dao.IUserMapper; import com.bijian.study.model.User; @Service("userService") public class UserServiceImpl implements UserService { private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); @Autowired private IUserMapper mapper; public int txUpdateUsersWhenException() { // 事务性 return innserMethod(); } @Transactional private int innserMethod() { User user = new User(1, "Before exception"); int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚 log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId()); User user2 = new User(1, "After exception"); int i = 1 / 0; // 抛出运行时异常,事务回滚 int affectedCount2 = mapper.updateUser(user2); // 未执行 log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId()); if (affectedCount == 1 && affectedCount2 == 1) { return 1; } return 0; } }
@Transactional方法不是服务类的入口方法,无JDK动态代理,事务失效。
测试前数据库中user表数据如下:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.00 sec)
测试方法的innserMethod中虽然抛出异常,但事务并没有回滚,测试后数据库中user表数据如下:
mysql> select * from user; +----+------+------+------------------+ | id | name | age | address | +----+------+------+------------------+ | 1 | NULL | 0 | Before exception | +----+------+------+------------------+ 1 row in set (0.00 sec)
相关推荐
1-1 导学-分布式事务实践 第2章 事务原则与实现 介绍了事务的四大原则,并通过实例介绍数据库实现事务的方法,以及使用JDBC实现事务的方法。 2-1 事务原则与实现:事务 2-2 事务原则与实现:SQL事务 2-3 事务原则与...
spring cloud最佳实践项目实例,使用了spring cloud全家桶,TCC事务管理,EDA事务最终一致性等技术的下单示例
此外,Spring事务管理器支持多种类型的事务策略,包括不同的传播行为和隔离级别,允许开发者根据具体业务场景选择最合适的事务管理策略。深入理解Spring声明式事务的工作原理,不仅能帮助开发者更高效地使用Spring...
Spring提供了两种使用JDBC API的最佳实践,一种是以JdbcTemplate为核心的基于Template的JDBC的使用方式,另一种则是在JdbcTemplate基础之上的构建的基于操作对象的JDBC的使用方式。
本文系统的介绍了Spring中的四种声明式事务的配置。可应用于实践项目中。
基于微服务架构的分布式系统...本课程从本地事务出发,介绍了分布式系统和Spring cloud框架及其使用,以及分布式事务的几种实现模式。课程中还提供了大量的实例,让同学们在实战过程中,掌握分布式事务实现方式与思路。
一阶段 1、Spring概述 2、一切从bean开始 3、俯瞰Spring架构设计 4、Spring源码下载 二阶段 1、什么是IOC/DI 2、SpringIOC体系结构 3、源码分析-IOC容器的初始化 ...Spring事务源码解析 需要其他源码请私信我
Spring专家力作 理论与实践完美结合 问题描述→解决方案→实现方法 第一部分 核心概念 第1章 控制反转和容器 1.1 使用容器管理组件 1.1.1 问题描述 1.1.2 解决方案 1.1.3 实现方法 ...
1,spring是一个开源的免费的框架(容器)。 2,spring是一个轻量级的,非入侵式的框架。...4,支持事务的处理,对框架整合的支持。 总结:spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
包括忘却的Spring高级话题,Spring最佳实践 对Spring2.5内置的各种XML Schema支持进行了全方位阐述。包括基于XML Schema的权威配置指南 全书理论与实践并重,通过大量的实例帮助读者尽快掌握Spring2,5的各种基本...
Spring 2.5是迄今为止完美的Java EE架构级框架,全面深入、多维度演绎Spring 2.5的各个方面,本书蕴含作者多年Java EE研发实践及经验。 凝聚Java魅力,成就开发专家 看清Java万花的本质,从复杂的表象中寻找...
Spring专家力作 理论与实践完美结合 问题描述→解决方案→实现方法 第一部分 核心概念 第1章 控制反转和容器 1.1 使用容器管理组件 1.1.1 问题描述 1.1.2 解决方案 1.1.3 实现方法 ...
分布式事务框架Fescar在SpringCloud环境下的应用实践-fescar-demo
NULL 博文链接:https://sjsky.iteye.com/blog/1112012
Spring专家力作 理论与实践完美结合 问题描述→解决方案→实现方法 第一部分 核心概念 第1章 控制反转和容器 1.1 使用容器管理组件 1.1.1 问题描述 1.1.2 解决方案 1.1.3 实现方法 1.2...
Spring教程合集.zip ...在Spring中配置Hibernate事务 Struts+Spring+Hibernate开发实例 Struts+Hibernate+Spring练习 Struts+Spring+Hibernate快速入门 sping mvc 理解AOP,IOC,Spring Spring Framework最佳实践
此外,还包括了Spring事务管理和Spring Boot框架的介绍,帮助学习者了解如何在Spring应用程序中实现事务管理和利用Spring Boot简化项目开发。通过这组练习题,学习者可以全面掌握Spring框架的核心知识和常用技术,为...
14.5.1.理解Spring.NET声明式事务管理的实现 14.5.2.第一个例子 14.5.3.Transaction特性的设置 14.5.4.通过AutoProxyCreator使用声明式事务 14.5.5.通过TransactionProxyFactoryObject使用声明式事务 14.5.6. 通过...