一、事务基础概念
事务:执行多条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("库存不足");
}
}
}
七、事务使用注意事项
-
事务方法必须是public的,private/protected方法上的@Transactional注解无效
-
自调用问题:同一个类中的方法互相调用,@Transactional注解可能失效
-
异常捕获处理:在方法内捕获异常可能导致事务不回滚
-
选择合适的隔离级别:根据业务需求选择,级别越高性能越差
-
事务粒度的控制:避免在事务中执行耗时操作
-
连接池配置:确保连接池大小合理
八、常见问题与解决方案
问题1:事务不生效
原因:
-
方法不是public
-
异常被捕获未抛出
-
数据库引擎不支持事务(如MyISAM)
-
自调用问题