Spring————事务

一、事务基础概念

事务:执行多条SQL语句,要么全部成功执行,要么全部回滚到初始状态

二、事务的特性(ACID)

  • 原子性:事务是最小的执行单位,不可再分割

  • 一致性:事务前后数据都保持正确状态

  • 隔离性:多个事务之间相互隔离,互不干扰

  • 持久性:事务一旦提交,结果永久保存,不可再回滚

三、事务控制方式

1. MySQL原生事务控制

START TRANSACTION; -- 开启事务,记录undo_log

sql1;

sql2;

COMMIT; -- 提交事务,删除undo_log

-- 或

ROLLBACK;

2. JDBC事务控制

Connection conn = ...;

conn.setAutoCommit(false); // 相当于START TRANSACTION

try {

conn.commit();

} catch (Exception e) {

conn.rollback();

throw e;

}

3. MyBatis事务控制

SqlSession sqlSession = sqlSessionFactory.openSession(false); // 关闭自动提交

try {

sqlSession.commit();

} catch (Exception e) {

sqlSession.rollback();

throw e;

}

四、Spring事务核心API

1. PlatformTransactionManager(平台事务管理器)

作用:Spring事务管理的核心接口,负责开启、提交和回滚事务

主要实现类

  • DataSourceTransactionManager:用于JDBC和MyBatis

  • HibernateTransactionManager:用于Hibernate

  • JpaTransactionManager:用于JPA

  • JtaTransactionManager:用于分布式事务

  • @Bean

    public PlatformTransactionManager transactionManager(DataSource dataSource) {

    return new DataSourceTransactionManager(dataSource);

    }

2. TransactionDefinition(事务定义)

作用:定义事务的属性和规则

主要实现类DefaultTransactionDefinition

核心属性详解

1)隔离级别
  • ISOLATION_DEFAULT:默认值,使用数据库默认的隔离级别

  • ISOLATION_READ_UNCOMMITTED:读未提交(可能出现脏读、不可重复读、幻读)

  • ISOLATION_READ_COMMITTED:读已提交(避免脏读)

  • ISOLATION_REPEATABLE_READ:可重复读(避免脏读、不可重复读)

  • ISOLATION_SERIALIZABLE:串行化(避免脏读、不可重复读、幻读)

隔离级别 脏读 不可重复读 幻读
READ_UNCOMMITTED 可能 可能 可能
READ_COMMITTED 避免 可能 可能
REPEATABLE_READ 避免 避免 可能
SERIALIZABLE 避免 避免 避免
2)传播行为
  • PROPAGATION_REQUIRED默认值,如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务

  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,则以非事务方式执行

  • PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,则抛出异常

  • PROPAGATION_REQUIRES_NEW:创建新事务,如果当前存在事务,则把当前事务挂起

  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则把当前事务挂起

  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常

  • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新的事务

  • @Service

    public class UserService {

    @Transactional(propagation = Propagation.REQUIRED)

    public void methodA() {

    // 如果methodB抛出异常,methodA也会回滚

    methodB();

    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)

    public void methodB() {

    // 独立事务,即使抛出异常也不会影响methodA

    }

    }

3)事务超时
  • 默认值:-1(永不超时)

  • 单位:秒

  • 设置事务执行的超时时间,超过指定时间未完成则自动回滚

4)是否只读
  • false:默认值,可读写,会记录日志(效率较低),适合增删改操作

  • true:只读,不记录日志(效率较高),适合查询操作

5)回滚规则
  • 默认:只在遇到运行时异常(RuntimeException)时回滚

  • 可配置:指定特定异常回滚或不回滚

五、Spring事务管理方式

1. 编程式事务管理

@Service

public class UserService {

@Autowired

private PlatformTransactionManager transactionManager;

public void saveUser() {

// 定义事务属性

DefaultTransactionDefinition def = new DefaultTransactionDefinition();

def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

def.setTimeout(30);

def.setReadOnly(false);

// 开启事务

TransactionStatus status = transactionManager.getTransaction(def);

try {

// 执行业务逻辑

userDao.save(user);

// 提交事务

transactionManager.commit(status);

} catch (Exception e) {

// 回滚事务

transactionManager.rollback(status);

throw e;

}

}

}

2. 声明式事务管理(推荐)

基于XML配置

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

<!-- 2. 配置事务通知 -->

<tx:advice id="txAdvice" transaction-manager="transactionManager">

<tx:attributes>

<!-- 查询方法:只读事务 -->

<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>

<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>

<tx:method name="select*" read-only="true" propagation="SUPPORTS"/>

<!-- 增删改方法:读写事务 -->

<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>

<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>

<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>

<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>

<!-- 其他方法使用默认事务 -->

<tx:method name="*" propagation="REQUIRED"/>

</tx:attributes>

</tx:advice>

<!-- 3. 配置AOP -->

<aop:config>

<aop:pointcut id="servicePointcut"

expression="execution(* com.example.service.*.*(..))"/>

<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>

</aop:config>

基于注解配置

@Configuration

@EnableTransactionManagement // 开启事务支持

public class AppConfig {

// 配置数据源

@Bean

public DataSource dataSource() {

return new DriverManagerDataSource(...);

}

// 配置事务管理器

@Bean

public PlatformTransactionManager transactionManager(DataSource dataSource) {

return new DataSourceTransactionManager(dataSource);

}

}

@Service

public class UserServiceImpl implements UserService {

@Autowired

private UserDao userDao;

// 在方法上使用@Transactional注解

@Override

@Transactional(

propagation = Propagation.REQUIRED,

isolation = Isolation.READ_COMMITTED,

timeout = 30,

readOnly = false,

rollbackFor = {RuntimeException.class, Exception.class},

noRollbackFor = {NullPointerException.class}

)

public void saveUser(User user) {

userDao.save(user);

}

// 只读查询

@Override

@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)

public User getUserById(Long id) {

return userDao.findById(id);

}

}

六、事务嵌套与传播行为示例

@Service

public class OrderService {

@Autowired

private OrderDao orderDao;

@Autowired

private AccountService accountService;

// 外层事务

@Transactional(propagation = Propagation.REQUIRED)

public void createOrder(Order order) {

// 1. 保存订单

orderDao.save(order);

try {

// 2. 扣减库存(新事务)

accountService.deductStock(order.getProductId(), order.getQuantity());

} catch (Exception e) {

// 库存不足异常,不影响订单创建

System.out.println("库存不足,但订单已创建");

}

// 3. 记录日志

logService.logOperation("创建订单:" + order.getId());

}

}

@Service

public class AccountService {

// 内层事务:独立事务

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void deductStock(Long productId, Integer quantity) {

// 如果库存不足会抛出异常,但不会影响外层事务

int result = productDao.updateStock(productId, -quantity);

if (result == 0) {

throw new RuntimeException("库存不足");

}

}

}

七、事务使用注意事项

  1. 事务方法必须是public的,private/protected方法上的@Transactional注解无效

  2. 自调用问题:同一个类中的方法互相调用,@Transactional注解可能失效

  3. 异常捕获处理:在方法内捕获异常可能导致事务不回滚

  4. 选择合适的隔离级别:根据业务需求选择,级别越高性能越差

  5. 事务粒度的控制:避免在事务中执行耗时操作

  6. 连接池配置:确保连接池大小合理

八、常见问题与解决方案

问题1:事务不生效

原因

  • 方法不是public

  • 异常被捕获未抛出

  • 数据库引擎不支持事务(如MyISAM)

  • 自调用问题

相关推荐
西门吹-禅2 小时前
【sap fiori cds up error】
java·服务器·sap cap cds
敲代码的嘎仔2 小时前
Java后端面试——SSM框架面试题
java·面试·职场和发展·mybatis·ssm·springboot·八股
NGC_66112 小时前
Spring与SpringBoot
spring
大傻^3 小时前
Spring AI Alibaba RAG实战:基于向量存储的检索增强生成
java·人工智能·spring
大傻^3 小时前
Spring AI Alibaba 快速入门:基于通义千问的AI应用开发环境搭建
java·人工智能·后端·spring·springai·springaialibaba
伯恩bourne3 小时前
Google Guava:Java 核心工具库的卓越之选
java·开发语言·guava
qq_170264753 小时前
unity出安卓年龄分级的arr包问题
android·unity·游戏引擎
小王不爱笑1323 小时前
Spring 基础核心
java
心勤则明3 小时前
用 Spring AI Alibaba 打造智能查询增强引擎
java·人工智能·spring