数据库
数据库事务基础
数据库用于持久化保存系统中的数据,而事务用于保证一组数据库操作能够正确、完整地执行。可以简单理解为:数据库负责保存数据,事务负责保证数据操作的一致性和完整性。

一、什么是数据库
数据库是用于存储和管理数据的软件系统。
例如在一个医疗系统中,可能需要保存:
- 患者基本信息
- 筛查记录
- 检查结果
- 用户账号
- 操作日志
常见的关系型数据库包括:
- MySQL
- PostgreSQL
- Oracle
- SQL Server
在 Java 后端开发中,MySQL 是比较常见的数据库之一。
二、什么是事务
事务可以理解为:将多个数据库操作作为一个整体执行,要么全部成功,要么全部失败。
例如银行转账
张三向李四转账 100 元,需要执行两条 SQL:
UPDATE account
SET balance = balance - 100
WHERE id = 1;
UPDATE account
SET balance = balance + 100
WHERE id = 2;
分别表示:
正常情况下,两条 SQL 都应该执行成功。
如果第一条 SQL 执行成功,而第二条 SQL 执行失败,就会出现:
这就导致了数据错误。
因此,需要使用事务把这两个操作作为一个整体执行。
事务成功时:
如果中间发生错误:
这就是事务最核心的作用:
防止一个业务只执行了一部分。
三、事务的基本操作
数据库事务中最常见的三个操作是:
3.1 开启事务
START TRANSACTION;
表示开始一个事务。
3.2 提交事务
COMMIT;
表示事务中的所有操作执行成功,将修改正式保存到数据库。
3.3 回滚事务
ROLLBACK;
表示事务执行失败,撤销当前事务中已经执行的修改。
可以简单记:
例如:
START TRANSACTION;
UPDATE account
SET balance = balance - 100
WHERE id = 1;
UPDATE account
SET balance = balance + 100
WHERE id = 2;
COMMIT;
如果中间发生错误,则执行:
ROLLBACK;
撤销当前事务中的修改。
四、事务的 ACID 特性
数据库事务通常具有四个重要特性,简称 ACID。
分别是:
- Atomicity:原子性
- Consistency:一致性
- Isolation:隔离性
- Durability:持久性
1. 原子性 Atomicity
原子性表示:
一个事务中的操作要么全部成功,要么全部失败。
例如转账操作中:
这两个操作必须作为一个整体。
不能出现:
2. 一致性 Consistency
一致性表示:
事务执行前后,数据库中的数据都应该符合业务规则。
例如转账前:
张三向李四转账 100 元后:
虽然两个人的余额发生了变化,但是总金额仍然保持正确。
3. 隔离性 Isolation
隔离性表示:
多个事务同时执行时,事务之间应该尽量避免相互产生错误影响。
例如:
如果两个事务同时操作同一条数据,就可能产生并发问题。
事务隔离进一步会涉及:
- 脏读
- 不可重复读
- 幻读
- 事务隔离级别
这些都是后续学习事务时的重要内容。
4. 持久性 Durability
持久性表示:
一个事务一旦提交成功,修改的数据就应该被永久保存。
也就是说,当执行:
COMMIT;
之后,即使数据库随后:
- 重启
- 服务器异常
- 程序崩溃
已经成功提交的数据也应该被保存下来。
五、为什么需要事务
在实际软件开发中,一个业务操作通常不只是执行一条 SQL。
例如在医疗系统中,新建一条筛查记录可能需要:
假设执行到第三步时发生异常:
如果没有事务,数据库中就会出现一部分数据已经保存、另一部分数据没有保存的情况。
这会导致业务数据不完整。
使用事务后:
如果任意一步失败:
因此,事务非常适合处理:
一个业务需要同时修改多条数据,并且这些修改必须保持一致的场景。
六、Java 中的事务
在 Java 的 Spring Boot 项目中,一般不会直接在业务代码中手动编写:
START TRANSACTION;
COMMIT;
ROLLBACK;
Spring 提供了 @Transactional 注解来帮助我们管理事务。
例如:
@Service
public class TransferService {
@Transactional
public void transfer() {
accountMapper.subtract(1, 100);
accountMapper.add(2, 100);
}
}
这里:
@Transactional
表示 transfer() 方法中的数据库操作需要作为一个事务执行。
Spring 会帮你管理:
所以在 Java 项目中看到:
@Transactional
可以先简单理解为:
这个方法中的数据库操作需要作为一个整体执行。
七、@Transactional 需要注意什么
虽然 @Transactional 使用起来比较简单,但它并不是加上注解就一定能正确回滚。
例如:
@Transactional
public void transfer() {
accountMapper.subtract(1, 100);
int number = 10 / 0;
accountMapper.add(2, 100);
}
执行到:
int number = 10 / 0;
时会发生异常。
此时 Spring 会回滚事务,前面已经执行的扣款操作也会被撤销。
最终数据不会停留在:
这种错误状态。
不过 Spring 事务还有很多需要进一步学习的内容,例如:
- 哪些异常会触发回滚
rollbackFor- 方法内部调用导致事务失效
private方法上的事务问题- 事务传播行为
- 事务隔离级别
这些可以在后续学习 @Transactional 时再深入了解。
八、事务和普通 SQL 的区别
没有事务时,多条 SQL 基本可以理解为:
前面的修改可能已经保存,无法自动撤销。
使用事务后:
事务把原本独立的多条 SQL 组合成了一个完整的业务单元。