大家都知晓的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)
相关推荐
7. **案例分析**:"SPRING事务管理案例分析.docx"很可能包含了具体的项目实例,详细讲解了如何在Spring项目中配置和使用事务管理,以及如何解决实践中遇到的问题。而"studyspring"可能是源代码目录,包含了实现这些...
这个名为"Spring事务小demo"的项目提供了一个实践示例,帮助开发者了解Spring事务处理的基本概念和用法。 首先,Spring事务管理是Spring框架的核心特性之一,它允许我们以声明式或编程式的方式管理事务。声明式事务...
本文将深入探讨在Spring框架中如何管理事务,以“Spring 事务简单完整例子”为出发点,结合标签“spring,事务,jdbc事务”,我们将详细解释Spring事务管理的原理和实践。 首先,Spring提供了两种事务管理方式:编程...
在Spring框架中,事务管理是核心特性之一,它允许开发者以声明式或编程式的方式处理事务。...通过学习和实践这个示例,你将能够掌握在多层方法调用中如何优雅地管理和协调事务,提高代码的可靠性和可维护性。
Spring事务机制是Java开发中非常重要的一个概念,它在企业级应用中扮演着核心角色,确保数据的一致性和完整性。Spring提供了多种事务管理方式,包括编程式事务管理和声明式事务管理。在这篇DEMO中,我们将重点探讨...
总结来说,"Spring事务传播Demo"是一个用于学习和演示Spring事务管理和传播行为的实例,通过分析和实践这个Demo,开发者可以更好地理解和掌握Spring在处理事务时的复杂情况,提升在实际项目中的应用能力。...
本篇文章将详细解析Spring中的六种事务配置方法,帮助开发者深入理解并掌握Spring事务的运用。 1. **基于XML的事务配置** Spring支持通过XML配置来管理事务,这是最基础的配置方式。在`spring`的配置文件中,我们...
本DEMO主要探讨的是Spring事务的传播行为和隔离级别,这些概念对于理解和优化数据库操作至关重要。让我们深入理解这些概念及其实际应用。 首先,我们来谈谈事务的传播行为。在Spring中,当一个方法被另一个具有事务...
在本文中,我们将深入探讨Spring框架中的事务管理。Spring是一个广泛应用的Java企业级应用开发框架,它提供...如果你想要深入了解,可以参考提供的博客链接或其他相关资料,进一步学习Spring事务管理的细节和最佳实践。
通过运行这些例子,你将对Spring事务管理有更深入的理解,知道何时选择编程式还是声明式事务,以及如何有效地处理事务异常。 总之,Spring的事务管理是其强大功能的一部分,无论是编程式还是声明式,都能帮助开发者...
- 对于一般的业务逻辑来说,将事务管理器的`order`值设置得稍微高一点(例如200),而自定义切面的`order`值设置得较低(例如1),通常是一个比较合理的实践。 - 在进行切面编程时,建议仔细考虑每个切面的功能...
### AOP与Spring事务处理详解 #### 一、引言:为什么使用框架和设计模式? 在软件开发领域,设计模式和框架是两个重要的概念。设计模式作为一种指导思想,能够帮助开发者更好地解决常见的软件设计问题,确保系统...
在IT领域,Spring框架是Java开发中的核心工具之一,它为构建高质量的、可维护的、松耦合的应用程序...在实践中,你可能会遇到的问题包括事务传播行为、异常回滚规则、事务隔离级别等,这些都是进一步学习和研究的方向。
PlatformTransactionManager接口是Spring事务管理的核心,它负责事务的创建、提交和回滚。这个接口定义了以下三个基本操作: - `getTransaction(TransactionDefinition definition)`:根据传入的...
在Spring框架中,事务管理是核心功能之一,它允许开发者以声明式或编程式的方式处理应用程序的事务。...通过理解并实践这些配置,你可以更好地掌握Spring基于XML的事务管理机制,并将其应用到实际开发中。
在Java企业级应用开发中,Spring和Hibernate是两个非常重要的框架。Spring是一个全面的后端应用...这个实例将帮助开发者更好地理解和实践Spring与Hibernate的集成,以及如何有效地管理事务,确保应用程序的数据一致性。
在Spring框架中,事务管理是核心功能之一,它确保了数据操作的一致性和完整性。本教程将深入探讨如何在Spring中实现自定义事务管理器...这将加深你对Spring事务管理的理解,帮助你在实际项目中更加熟练地运用这些技术。
Spring事务管理就是围绕这些特性来确保数据的一致性。 四、事务的传播行为 在Spring中,我们可以配置事务的传播行为,比如REQUIRED(默认,如果当前存在事务,则加入当前事务,否则新建一个事务)、PROPAGATION_...