目录
设计实现
工作原理
简单示例
隔离级别
事务传播机制
Spring框架提供了强大的事务管理支持,它允许开发者以声明性或编程性的方式来管理事务,从而保证数据的一致性和完整性。Spring事务管理的主要特点包括:
-
声明式事务管理: Spring支持使用注解或XML配置的方式来声明事务,使开发者可以在方法级别或类级别上定义事务的边界。
-
编程式事务管理: 如果需要更细粒度的控制,Spring也提供了编程式事务管理的方式,通过编写Java代码来控制事务的开始、提交、回滚等操作。
-
多数据源支持: Spring事务管理支持多个数据源之间的事务协调,例如,一个事务涉及多个数据库的操作。
-
分布式事务: Spring提供了对JTA(Java Transaction API)的支持,可以实现分布式事务,跨多个资源管理器(例如,多个数据库或消息队列)的事务一致性。
-
灵活的事务管理器: Spring支持多种事务管理器,包括JDBC事务管理器、Hibernate事务管理器、JTA事务管理器等,开发者可以根据需要选择合适的事务管理器。
-
嵌套事务: Spring允许嵌套事务,一个事务方法可以调用另一个事务方法,内层方法可以选择独立提交或回滚,而不会影响外层事务。
-
事务传播行为: Spring提供了不同的事务传播行为,如REQUIRED、REQUIRES_NEW、NESTED等,用于控制方法之间事务的关系。
设计实现
Spring事务管理的设计和实现原理基于AOP(面向切面编程)和反射技术。Spring框架通过AOP在运行时动态生成代理,实现事务管理的横切关注点,从而将事务管理从业务逻辑中解耦。
-
AOP代理: Spring使用AOP代理技术来包装业务对象,以添加事务管理逻辑。这些代理对象在运行时拦截方法调用,并在方法执行前后执行额外的操作,如事务的开启、提交、回滚等。
-
切面(Aspect): 事务管理被抽象为一个切面,它包含了事务管理的逻辑。切面定义了在哪些地方执行事务管理操作,通常包括在方法执行前开启事务,在方法执行后提交事务,发生异常时回滚事务等。
-
Advice: Advice是切面中的方法,它定义了在何时、何地执行事务管理操作。Spring框架中主要有以下几种类型的Advice:
-
Before
:在方法执行前执行,用于开启事务。 -
After
:在方法执行后执行,用于提交事务。 -
AfterReturning
:在方法执行后执行,只有在方法成功执行后才会提交事务。 -
AfterThrowing
:在方法抛出异常后执行,用于回滚事务。
-
-
切点(Pointcut): 切点是切面中定义的,用于定义在哪些方法上应用Advice。Spring提供了通配符表达式或自定义表达式来选择匹配的方法。
-
事务管理器(Transaction Manager): 事务管理器负责实际的事务管理操作,包括事务的开启、提交、回滚、事务的隔离级别、超时等。Spring支持多种事务管理器,如
DataSourceTransactionManager
、HibernateTransactionManager
、JtaTransactionManager
等,可以根据需要进行配置。 -
代理工厂(Proxy Factory): Spring框架使用代理工厂来创建代理对象,这些代理对象包含了事务管理的逻辑。Spring支持JDK动态代理和CGLIB代理,可以根据业务对象的类型和方法来选择合适的代理方式。
-
事务传播行为(Propagation): Spring允许定义事务传播行为,控制多个事务方法之间的事务关系。常见的传播行为包括REQUIRED、REQUIRES_NEW、NESTED等。
-
隔离级别(Isolation): 隔离级别定义了多个事务之间的隔离程度,包括READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE等级别。
-
只读标志(ReadOnly): 只读标志指示事务是否只读,只读事务可以提高性能,因为不需要锁定数据。
工作原理
-
当业务方法被调用时,AOP代理会拦截方法执行。
-
根据方法上的
@Transactional
注解或XML配置,决定是否需要开启新的事务。 -
如果需要开启事务,事务管理器会开启一个新事务,并将事务与当前线程绑定。
-
业务方法执行过程中,Advice会执行相应的事务管理操作,如提交或回滚。
-
最终,事务管理器根据事务的状态,决定是提交还是回滚事务。
-
事务在方法结束后被销毁,同时清理与当前线程的关联。
简单示例
主要涉及到了2个注解:
@EnableTransactionManagement:开启spring事务管理功能
@Transaction:将其加在需要spring管理事务的类、方法、接口上,只会对public方法有效。
-
首先,确保您的项目中包含了Spring的相关依赖,包括
spring-core
和spring-tx
。 -
创建一个Spring配置文件,例如
applicationContext.xml
,并在其中配置数据源和事务管理器。以下是一个示例配置:<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mydb" /> <property name="username" value="root" /> <property name="password" value="123456" /> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启注解驱动的事务管理 --> <tx:annotation-driven /> </beans>
-
创建一个数据访问对象(DAO)来执行数据库操作。以下是一个示例的
UserDAO
类:@Repository public class UserDAO { @Autowired private JdbcTemplate jdbcTemplate; public void createUser(String username, String password) { String sql = "INSERT INTO users (username, password) VALUES (?, ?)"; jdbcTemplate.update(sql, username, password); } }
-
创建一个服务类,用于调用DAO并管理事务。以下是一个示例的
UserService
类:@Service public class UserService { @Autowired private UserDAO userDAO; @Transactional public void createUserWithTransaction(String username, String password) { userDAO.createUser(username, password); } }
-
创建一个Spring Boot应用或Web应用,并将配置文件和服务类集成到应用中。编写入口执行:
public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = context.getBean(UserService.class); userService.createUserWithTransaction("zhangsan", "123456"); } }
在此示例中,当
createUserWithTransaction
方法被调用时,Spring将自动管理事务的开启、提交和回滚。
隔离级别
隔离级别定义了多个事务并发执行时的数据隔离程度,通常包括以下几个级别,从低到高:
-
READ UNCOMMITTED(读未提交): 允许一个事务读取另一个事务未提交的修改。这个隔离级别允许最低的隔离程度,可能导致脏读、不可重复读和幻读问题。
-
READ COMMITTED(读已提交): 允许一个事务读取另一个事务已经提交的修改。这个级别避免了脏读问题,但仍可能发生不可重复读和幻读。
-
REPEATABLE READ(可重复读): 保证在同一个事务中多次读取相同数据时,结果是一致的。这个级别避免了脏读和不可重复读,但仍可能发生幻读。
-
SERIALIZABLE(串行化): 提供最高的隔离级别,确保每个事务都完全独立执行,不会发生任何并发问题。这个级别避免了脏读、不可重复读和幻读。
Spring中可使用@Transactional
注解的isolation
属性来指定隔离级别。例如:
@Transactional(isolation = Isolation.READ_COMMITTED)
事务传播机制
事务传播机制定义了当一个事务方法被另一个事务方法调用时,应该如何处理事务的行为。常见的事务传播行为包括:
-
REQUIRED(默认): 如果当前没有事务,新建一个事务;如果当前已经存在一个事务,加入该事务。
-
REQUIRES_NEW: 总是开启一个新的事务,挂起当前事务(如果存在)。
-
SUPPORTS: 如果当前存在一个事务,就加入这个事务;如果没有事务,就以非事务方式执行。
-
NOT_SUPPORTED: 以非事务方式执行,如果当前存在一个事务,就将其挂起。
-
NEVER: 以非事务方式执行,如果当前存在一个事务,就抛出异常。
-
MANDATORY: 必须在一个事务内执行,如果当前没有事务,就抛出异常。
-
NESTED: 如果当前存在一个事务,就开启一个嵌套事务;如果当前没有事务,就行为类似于REQUIRED。
Spring中可使用@Transactional
注解的propagation
属性来指定事务传播行为。例如:
@Transactional(propagation = Propagation.REQUIRED)
组合使用隔离级别和事务传播机制可以根据具体的应用需求来管理事务,确保数据的一致性和完整性,同时提高性能和并发能力。事务的隔离级别和传播机制的选择需要根据具体的业务场景和需求来确定。