Spring 事务深度解析:从 ACID 到分布式事务 Spring 事务是企业级应用中确保数据一致性的核心机制,基于 AOP(面向切面编程) 实现,将事务管理逻辑与业务逻辑解耦。它不仅支持本地事务(单数据库),还通过 JTA 等规范支持分布式事务(跨数据库 / 服务)。从 “事务基础→核心属性→实现原理→实战配置→分布式事务” 五个维度,系统拆解 Spring 事务的工作机制与最佳实践。
事务基础:理解 ACID 与并发问题 事务(Transaction)是数据库操作的最小单元,必须满足 ACID 特性 ,同时需解决并发场景下的脏读、不可重复读、幻读问题。
1. 事务的 ACID 特性 ACID 是事务的四大核心特性,确保数据操作的一致性与可靠性:
特性
英文全称
核心含义
示例场景(转账:A 转 100 给 B)
原子性(Atomicity)
Atomicity
事务中的操作 “要么全成功,要么全失败”,无中间状态
A 扣款 100 成功,但 B 到账 100 失败 → 事务回滚,A 余额恢复
一致性(Consistency)
Consistency
事务执行前后,业务状态需符合预期(数据完整性约束不被破坏)
转账前 A+B 余额 = 2000 → 转账后仍为 2000(不会出现 A 扣了但 B 没到账)
隔离性(Isolation)
Isolation
多个事务并发执行时,彼此隔离,互不干扰(避免并发问题)
事务 1 读取 A 余额时,事务 2 修改 A 余额 → 事务 1 读取的是隔离后的数据
持久性(Durability)
Durability
事务提交后,结果永久保存到数据库(即使数据库崩溃,数据也不丢失)
转账成功后,即使数据库重启,A 扣 100、B 加 100 的结果仍存在
2. 并发事务的三大问题 当多个事务同时操作同一批数据时,若隔离性不足,会引发三类典型问题:
并发问题
具体表现
示例(事务 T1 读取数据,事务 T2 修改数据)
脏读(Dirty Read)
T1 读取 T2 未提交的修改 → T2 回滚后,T1 读取的是 “无效数据”
T2 给 A 加 100(未提交)→ T1 读 A 余额为 1100 → T2 回滚 → T1 基于 1100 做业务,结果错误
不可重复读(Non-Repeatable Read)
T1 多次读取同一数据 → T2 提交修改后,T1 两次读取结果不一致
T1 第一次读 A 余额 1000 → T2 给 A 加 100(提交)→ T1 第二次读 A 余额 1100,结果不同
幻读(Phantom Read)
T1 按条件查询数据 → T2 插入 / 删除符合条件的行 → T1 再次查询,行数变化
T1 查 “余额> 500 的用户”(2 人)→ T2 新增 1 个余额 600 的用户(提交)→ T1 再次查询,结果为 3 人
3. 事务隔离级别:解决并发问题 数据库通过 隔离级别 控制并发事务的干扰程度,Spring 支持数据库的所有隔离级别,并新增 DEFAULT(继承数据库默认级别)。不同级别对并发问题的解决能力不同,性能也不同:
隔离级别
解决脏读
解决不可重复读
解决幻读
性能
数据库默认(常见)
READ_UNCOMMITTED
❌
❌
❌
最高
无
READ_COMMITTED
✅
❌
❌
较高
Oracle、SQL Server
REPEATABLE_READ
✅
✅
❌
中等
MySQL(InnoDB)
SERIALIZABLE
✅
✅
✅
最低
无
DEFAULT (Spring 新增)
继承数据库默认级别
继承数据库默认级别
继承数据库默认级别
取决于数据库
-
注意:隔离级别越高,并发能力越弱(锁机制更严格),需在 “数据一致性” 与 “性能” 间平衡。例如:金融核心业务用 REPEATABLE_READ,非核心查询用 READ_COMMITTED。
Spring 事务核心属性:定制事务行为 Spring 事务通过 TransactionDefinition 接口 定义核心属性,包括传播行为、隔离级别、超时时间、只读属性、回滚规则,这些属性决定了事务的执行逻辑。
1. 事务传播行为(核心) 传播行为定义了 “当一个事务方法调用另一个事务方法时,如何处理事务上下文”,是 Spring 事务最灵活的特性之一,共 7 种:
传播行为常量
核心含义
适用场景
PROPAGATION_REQUIRED
支持当前事务;若当前无事务,新建事务;若有事务,加入当前事务(默认值)
绝大多数业务场景(如转账、下单)
PROPAGATION_SUPPORTS
支持当前事务;若当前无事务,以非事务方式执行
可选事务的查询方法(如 “获取订单详情”,有事务则加入,无则非事务)
PROPAGATION_MANDATORY
支持当前事务;若当前无事务,抛出异常(强制要求事务上下文)
必须在事务中执行的方法(如 “扣减库存”,防止调用者遗漏事务)
PROPAGATION_REQUIRES_NEW
新建事务;若当前有事务,将当前事务挂起(新事务与原事务独立)
独立事务(如 “记录操作日志”,即使主事务回滚,日志仍需提交)
PROPAGATION_NOT_SUPPORTED
以非事务方式执行;若当前有事务,挂起当前事务
无需事务的操作(如 “发送短信通知”,避免事务过长影响性能)
PROPAGATION_NEVER
以非事务方式执行;若当前有事务,抛出异常(禁止事务上下文)
绝对不能在事务中执行的方法(如 “数据备份”,防止锁表)
PROPAGATION_NESTED
若当前有事务,在嵌套事务中执行(嵌套事务可独立回滚);若无事务,新建事务
部分回滚场景(如 “下单”:扣库存失败回滚,但生成订单记录不回滚)
传播行为示例:REQUIRED vs REQUIRES_NEW 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Service public class OrderService { @Autowired private InventoryService inventoryService; @Transactional(propagation = Propagation.REQUIRED) public void createOrder () { System.out.println("生成订单" ); try { inventoryService.deductStock(); } catch (Exception e) { System.out.println("库存扣减失败,订单仍保留" ); } } } @Service public class InventoryService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void deductStock () { System.out.println("扣减库存" ); throw new RuntimeException ("库存不足" ); } }
结果 :deductStock() 回滚(库存不变),createOrder() 继续执行(订单生成成功)。
2. 其他核心属性
属性
作用
配置示例
隔离级别(isolation)
控制并发事务的隔离程度
@Transactional(isolation = Isolation.REPEATABLE_READ)
只读(readOnly)
标记事务仅执行查询操作(数据库优化:避免加写锁)
@Transactional(readOnly = true)(仅查询方法用)
超时时间(timeout)
事务超时时间(秒),超时后自动回滚(防止长事务占用资源)
@Transactional(timeout = 30)(30 秒超时)
回滚规则(rollbackFor)
指定哪些异常触发事务回滚(默认仅回滚运行时异常 ,如 RuntimeException)
@Transactional(rollbackFor = Exception.class)(所有异常回滚)
不回滚规则(noRollbackFor)
指定哪些异常不触发回滚
@Transactional(noRollbackFor = BusinessException.class)(业务异常不回滚)
注意:readOnly=true 不可用于修改操作(如 insert/update/delete),否则可能导致数据不一致(数据库可能忽略写操作或不加锁)。
Spring 事务实现原理:基于 AOP 的动态代理 Spring 事务的底层是 AOP 动态代理 ,通过 PlatformTransactionManager(事务管理器)实现事务的 “开启→提交→回滚” 生命周期管理。
PlatformTransactionManager 是 Spring 事务的顶层接口,定义了事务管理的三大核心操作,不同持久化框架有不同实现:
1 2 3 4 5 6 7 8 9 10 public interface PlatformTransactionManager { TransactionStatus getTransaction (TransactionDefinition definition) throws TransactionException; void commit (TransactionStatus status) throws TransactionException; void rollback (TransactionStatus status) throws TransactionException; }
常用实现类(按持久化框架分类):
实现类
适用框架
核心作用
DataSourceTransactionManager
MyBatis、Spring JDBC
管理 JDBC 连接的事务(基于 Connection)
HibernateTransactionManager
Hibernate
管理 Hibernate Session 的事务
JpaTransactionManager
JPA
管理 JPA EntityManager 的事务
JtaTransactionManager
JTA(分布式事务)
管理跨数据库 / 服务的分布式事务
2. 事务执行流程(AOP 动态代理) Spring 事务通过 AOP 生成代理对象,在目标方法执行前后插入事务管理逻辑,流程如下:
graph TD
A[调用代理对象的事务方法] --> B["获取 TransactionDefinition(隔离级别、传播行为等)"]
B --> C["PlatformTransactionManager.getTransaction():开启/加入事务"]
C --> D["执行目标方法(业务逻辑)"]
D --> E{方法执行结果}
E -->|正常完成| F["PlatformTransactionManager.commit():提交事务"]
E -->|抛出异常| G["PlatformTransactionManager.rollback():回滚事务"]
F --> H[方法执行结束]
G --> H
关键细节:
代理对象生成 :若目标类实现接口,用 JDK 动态代理;否则用 CGLIB 动态代理;
事务上下文传递 :通过 ThreadLocal 存储当前事务状态(TransactionStatus),确保同一线程内的事务方法共享事务上下文;
异常判断 :仅当异常符合 rollbackFor 配置时,才触发回滚(默认仅回滚运行时异常)。
Spring 事务实战:注解与 XML 配置 Spring 事务支持两种配置方式:注解驱动(推荐,Spring Boot 常用) 和 XML 配置(传统方式) ,核心是 “配置事务管理器 + 定义事务属性”。
前置准备:环境与依赖 1. 数据库表与初始数据 1 2 3 4 5 6 7 8 9 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (20 ) NOT NULL , account DOUBLE NOT NULL ) ENGINE= InnoDB DEFAULT CHARSET= utf8; INSERT INTO user (name, account) VALUES ('张三' , 1000 ), ('李四' , 1000 );
2. 依赖配置(Maven) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 4.3.29.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 4.3.29.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-tx</artifactId > <version > 4.3.29.RELEASE</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.48</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-aop</artifactId > <version > 4.3.29.RELEASE</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.7</version > </dependency >
方式一:注解驱动配置(推荐) 通过 @Transactional 注解标记事务方法,配合 tx:annotation-driven 启用自动代理,步骤如下:
1. 配置 Spring 上下文(XML) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?xml version="1.0" encoding="UTF-8" ?> <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" > <context:component-scan base-package ="com.zhanghe.study.spring4.beans.tx" /> <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/spring?useUnicode=true& characterEncoding=utf-8" /> <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 transaction-manager ="transactionManager" /> </beans >
2. 编写事务服务类(@Transactional) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Isolation;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;@Service public class TransferService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional( propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class // 所有异常都回滚(默认仅回滚运行时异常) ) public void transfer () { try { jdbcTemplate.update("UPDATE user SET account = account - 100 WHERE name = '张三'" ); jdbcTemplate.update("UPDATE user SET account = account + 100 WHERE name = '李四'" ); } catch (Exception e) { throw new RuntimeException ("转账失败:" + e.getMessage()); } } @Transactional(readOnly = true) public Double getAccount (String name) { return jdbcTemplate.queryForObject( "SELECT account FROM user WHERE name = ?" , new Object []{name}, Double.class ); } }
3. 测试事务效果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TransactionTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("spring-tx.xml" ); TransferService transferService = context.getBean(TransferService.class); System.out.println("转账前:张三余额=" + transferService.getAccount("张三" ) + ",李四余额=" + transferService.getAccount("李四" )); try { transferService.transfer(); System.out.println("转账成功!" ); } catch (Exception e) { System.out.println("转账失败:" + e.getMessage()); } System.out.println("转账后:张三余额=" + transferService.getAccount("张三" ) + ",李四余额=" + transferService.getAccount("李四" )); } }
测试结果 :
无异常时:张三余额 900,李四余额 1100(事务提交);
有异常时:张三和李四余额仍为 1000(事务回滚)。
方式二:XML 配置(传统方式) 通过 <tx:advice> 定义事务属性,<aop:config> 关联切入点与事务通知,无需注解,步骤如下:
1. XML 配置(核心是事务通知 + AOP 切面) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <?xml version="1.0" encoding="UTF-8" ?> <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" xmlns:aop ="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd" > <context:component-scan base-package ="com.zhanghe.study.spring4.beans.tx" /> <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/spring?useUnicode=true& characterEncoding=utf-8" /> <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:advice id ="txAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="get*" read-only ="true" isolation ="REPEATABLE_READ" /> <tx:method name ="find*" read-only ="true" isolation ="REPEATABLE_READ" /> <tx:method name ="transfer" propagation ="REQUIRED" rollback-for ="Exception" /> <tx:method name ="save*" propagation ="REQUIRED" rollback-for ="Exception" /> <tx:method name ="update*" propagation ="REQUIRED" rollback-for ="Exception" /> <tx:method name ="*" propagation ="REQUIRED" /> </tx:attributes > </tx:advice > <aop:config > <aop:pointcut id ="txPointcut" expression ="execution(* com.zhanghe.study.spring4.beans.tx.TransferService.*(..))" /> <aop:advisor advice-ref ="txAdvice" pointcut-ref ="txPointcut" /> </aop:config > </beans >
2. 服务类(无注解) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Service public class TransferService { @Autowired private JdbcTemplate jdbcTemplate; public void transfer () { } public Double getAccount (String name) { } }
测试效果 :与注解方式完全一致,XML 配置通过 “方法名匹配” 替代了注解,更适合不允许使用注解的传统项目。
分布式事务:跨数据库 / 服务的一致性 当业务涉及 分库分表 或 跨服务调用 时,本地事务无法保证数据一致性,需使用 分布式事务 。Spring 基于 JTA(Java Transaction API)规范支持分布式事务,常用实现有 Atomikos、Bitronix 等。
1. 分布式事务场景
分库场景 :订单数据存在 DB1,库存数据存在 DB2,下单时需同时修改 DB1 和 DB2;
微服务场景 :用户服务(修改用户余额)调用订单服务(创建订单),需保证两个服务的事务同时提交或回滚。
2. Spring 分布式事务实现(Atomikos) Spring Boot 中通过 spring-boot-starter-jta-atomikos 快速集成分布式事务,步骤如下:
1. 依赖配置(Maven) 1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-jta-atomikos</artifactId > <version > 2.7.17</version > </dependency >
2. 配置多数据源(application.yml) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 spring: jta: atomikos: properties: service: com.atomikos.icatch.standalone.UserTransactionServiceFactory max-timeout: 300000 datasource: order: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf-8 username: root password: 123456 unique-resource-name: orderDataSource inventory: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/inventory_db?useUnicode=true&characterEncoding=utf-8 username: root password: 123456 unique-resource-name: inventoryDataSource
3. 配置分布式事务管理器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import com.atomikos.jdbc.AtomikosDataSourceBean;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.transaction.jta.JtaTransactionManager;import javax.sql.DataSource;import java.util.Properties;@Configuration public class DistributedTxConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.order") public DataSource orderDataSource () { AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean (); Properties props = new Properties (); props.setProperty("url" , "jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf-8" ); props.setProperty("user" , "root" ); props.setProperty("password" , "123456" ); dataSource.setXaProperties(props); dataSource.setUniqueResourceName("orderDataSource" ); return dataSource; } @Bean @ConfigurationProperties(prefix = "spring.datasource.inventory") public DataSource inventoryDataSource () { AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean (); Properties props = new Properties (); props.setProperty("url" , "jdbc:mysql://localhost:3306/inventory_db?useUnicode=true&characterEncoding=utf-8" ); props.setProperty("user" , "root" ); props.setProperty("password" , "123456" ); dataSource.setXaProperties(props); dataSource.setUniqueResourceName("inventoryDataSource" ); return dataSource; } @Bean public JtaTransactionManager jtaTransactionManager () { return new JtaTransactionManager (); } @Bean public JdbcTemplate orderJdbcTemplate () { return new JdbcTemplate (orderDataSource()); } @Bean public JdbcTemplate inventoryJdbcTemplate () { return new JdbcTemplate (inventoryDataSource()); } }
4. 分布式事务服务类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Service public class DistributedOrderService { @Autowired private JdbcTemplate orderJdbcTemplate; @Autowired private JdbcTemplate inventoryJdbcTemplate; @Transactional(rollbackFor = Exception.class) public void createOrderWithInventory () { try { orderJdbcTemplate.update("INSERT INTO `order` (order_no, user_id) VALUES ('ORDER001', 1)" ); inventoryJdbcTemplate.update("UPDATE inventory SET stock = stock - 1 WHERE goods_id = 1" ); } catch (Exception e) { throw new RuntimeException ("分布式事务失败:" + e.getMessage()); } } }
效果 :若任一数据源操作失败,两个数据源的事务会同时回滚,确保数据一致性。
3. 分布式事务注意事项
性能问题 :分布式事务需协调多个数据库 / 服务,锁机制更严格,性能远低于本地事务,避免过度使用;
最终一致性 :对于高并发场景,优先采用 “最终一致性” 方案(如 RocketMQ 事务消息、Seata TCC/SAGA 模式),而非强一致性的 JTA 事务;
资源释放 :确保分布式事务超时时间合理,避免长时间占用数据库连接或网络资源。
Spring 事务常见问题与避坑指南
@Transactional 注解不生效 :
原因 1:方法为 private/static/final(动态代理无法代理这些方法);
原因 2:异常被 try-catch 捕获且未重新抛出(Spring 无法感知异常,不触发回滚);
原因 3:未启用 tx:annotation-driven 或 @EnableAspectJAutoProxy;
解决方案:方法用 public 修饰,异常捕获后重新抛出,确保自动代理启用。
事务传播行为选择错误 :
例:子事务用 REQUIRED 时,主事务回滚会导致子事务也回滚(若需子事务独立,用 REQUIRES_NEW);
解决方案:根据业务场景选择传播行为,核心业务用 REQUIRED,独立操作(如日志)用 REQUIRES_NEW。
隔离级别设置过高 :
例:用 SERIALIZABLE 导致并发能力急剧下降(锁表严重);
解决方案:非核心业务用 READ_COMMITTED,核心业务用 REPEATABLE_READ,避免 SERIALIZABLE。
总结:Spring 事务的核心价值 Spring 事务通过 “声明式配置” 与 “AOP 动态代理”,实现了事务管理与业务逻辑的解耦,其核心价值体现在:
简化开发 :无需手动编写 Connection.commit()/rollback(),注解 / XML 配置即可;
灵活定制 :支持 7 种传播行为、5 种隔离级别,满足复杂业务场景;
一致性保障 :本地事务确保单库一致性,分布式事务支持跨库 / 服务一致性;
兼容性强 :适配 MyBatis、Hibernate、JPA 等主流持久化框架