数据库事务是什么,怎么用的

数据库事务(Transaction)是一组不可分割的 SQL 执行单元,要么全部执行成功(提交),要么全部执行失败(回滚),本质是 "原子性的操作集合",用于保证数据一致性。

事务的核心是保证数据一致性 ,通过 ACID 特性实现;基本用法:开启事务 → 执行SQL → 提交/回滚;实际开发中,优先用框架的声明式事务(如 Spring 的@Transactional),减少手动编码;不同数据库的事务隔离级别是关键差异,需结合业务场景选择。

目录

1.事务的核心特性(ACID)

2.事务的使用场景

[3.事务的基本操作(SQL 层面)](#3.事务的基本操作(SQL 层面))

[3.1 开启事务](#3.1 开启事务)

[3.2 执行 SQL(核心业务逻辑)](#3.2 执行 SQL(核心业务逻辑))

[3.3 提交事务(成功时)](#3.3 提交事务(成功时))

[3.4 回滚事务(失败时)](#3.4 回滚事务(失败时))

[3.5 保存点(进阶:部分回滚)](#3.5 保存点(进阶:部分回滚))

4.不同数据库的事务差异(重点)

[5.实际开发中的使用(以 Java 为例)](#5.实际开发中的使用(以 Java 为例))

[5.1 原生 JDBC 实现事务](#5.1 原生 JDBC 实现事务)

[5.2 框架层面(Spring Boot)](#5.2 框架层面(Spring Boot))

6.使用事务的注意事项

1.事务的核心特性(ACID)

事务的可靠性由 ACID 保证,这是数据库设计的基石:

特性 含义 例子(转账:A 转 100 给 B)
原子性(Atomicity) 事务是最小执行单位,不可拆分,要么全成,要么全败。 A 扣 100 和 B 加 100 必须同时成功;若 B 加 100 失败,A 的扣款需回滚。
一致性(Consistency) 事务执行前后,数据总状态保持合法(符合业务规则)。 转账前 A+B 总余额 = 1000,转账后仍 = 1000,不会出现 "只扣不加"。
隔离性(Isolation) 多个事务并发执行时,彼此的操作互不干扰,事务看到的数据是 "隔离" 的。 事务 1(A 转 B)和事务 2(查询 A 余额)并发时,事务 2 看不到事务 1 未提交的中间状态。
持久性(Durability) 事务提交后,修改永久生效,即使数据库崩溃(如断电),数据也不会丢失。 事务提交后,A 的余额 - 100、B 的 + 100 永久保存,重启数据库后仍有效。

2.事务的使用场景

只要涉及 "多步操作需保证一致性" 的场景,都需要事务:

  • 金融转账(核心场景)
  • 订单创建(扣库存 + 生成订单 + 扣余额)
  • 账户注册(创建用户 + 初始化账户 + 发送通知)
  • 数据批量更新(如批量调整价格,需全部成功或全部失败)

3.事务的基本操作(SQL 层面)

事务的生命周期:开启事务 → 执行 SQL → 提交事务(成功)/ 回滚事务(失败)

3.1 开启事务

不同数据库语法略有差异,但核心一致:

sql 复制代码
-- MySQL
START TRANSACTION;  -- 或 BEGIN;

-- PostgreSQL
BEGIN;  -- 或 START TRANSACTION;

-- Oracle
BEGIN;  -- 或 SET TRANSACTION;

3.2 执行 SQL(核心业务逻辑)

执行 1 条或多条 SQL(增删改查,主要是增删改):

sql 复制代码
-- 示例:A(id=1)转100给B(id=2)
UPDATE account SET balance = balance - 100 WHERE id = 1;  -- A扣钱
UPDATE account SET balance = balance + 100 WHERE id = 2;  -- B加钱

3.3 提交事务(成功时)

事务中所有 SQL 执行无误后,提交事务,修改永久生效:

sql 复制代码
COMMIT;

3.4 回滚事务(失败时)

若执行过程中出现错误(如 SQL 语法错、业务逻辑不满足),回滚事务,所有修改撤销:

sql 复制代码
ROLLBACK;

3.5 保存点(进阶:部分回滚)

复杂事务中,可设置 "保存点",仅回滚到指定保存点,而非整个事务:

sql 复制代码
-- 1. 开启事务
START TRANSACTION;

-- 2. 执行第一步SQL
UPDATE account SET balance = balance - 100 WHERE id = 1;  -- A扣钱

-- 3. 设置保存点
SAVEPOINT sp1;

-- 4. 执行第二步SQL(假设此处可能失败)
UPDATE account SET balance = balance + 100 WHERE id = 2;  -- B加钱

-- 5. 若第二步失败,回滚到保存点(仅撤销第二步,第一步仍保留)
ROLLBACK TO sp1;

-- 6. 若后续无错误,提交事务(仅A扣钱生效,需根据业务调整)
COMMIT;

4.不同数据库的事务差异(重点)

之前对话中提到的 PostgreSQL 与 MySQL,在事务上的核心差异的是 默认隔离级别

特性 MySQL(InnoDB 引擎) PostgreSQL
默认隔离级别 Repeatable Read(可重复读) Read Committed(读已提交)
并发性能 略高(可重复读隔离级别下,锁竞争相对少) 略低(读已提交隔离级别下,锁粒度更细)
幻读问题 可重复读级别下,通过 MVCC 避免幻读 读已提交级别下,可能出现幻读
事务块语法 支持 BEGIN/START TRANSACTION + COMMIT/ROLLBACK 支持 BEGIN + COMMIT/ROLLBACK,也支持事务块
保存点支持 支持 支持

5.实际开发中的使用(以 Java 为例)

5.1 原生 JDBC 实现事务

java 复制代码
Connection conn = null;
try {
    // 1. 获取连接(关闭自动提交)
    conn = DriverManager.getConnection(url, user, pwd);
    conn.setAutoCommit(false); // 关键:关闭自动提交,开启手动事务

    // 2. 执行SQL
    String sql1 = "UPDATE account SET balance = balance - 100 WHERE id = 1";
    String sql2 = "UPDATE account SET balance = balance + 100 WHERE id = 2";
    conn.prepareStatement(sql1).executeUpdate();
    conn.prepareStatement(sql2).executeUpdate();

    // 3. 提交事务
    conn.commit();
} catch (Exception e) {
    // 4. 异常回滚
    if (conn != null) conn.rollback();
    e.printStackTrace();
} finally {
    // 5. 释放资源
    if (conn != null) conn.close();
}

5.2 框架层面(Spring Boot)

使用@Transactional注解,声明式事务(推荐):

java 复制代码
@Service
public class TransferService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    // 关键:添加@Transactional注解,Spring自动管理事务
    @Transactional(rollbackFor = Exception.class) // 出现任何异常都回滚
    public void transfer(int fromId, int toId, int amount) {
        // 执行转账逻辑
        jdbcTemplate.update("UPDATE account SET balance = balance - ? WHERE id = ?", amount, fromId);
        jdbcTemplate.update("UPDATE account SET balance = balance + ? WHERE id = ?", amount, toId);
    }
}

6.使用事务的注意事项

  1. 避免长事务:长事务会占用数据库连接,阻塞其他操作,甚至导致锁超时(如转账事务不要包含 "等待用户输入" 的逻辑)。
  2. 事务粒度适中:不要把无关操作放进同一个事务(如 "转账 + 日志记录" 可拆分,日志失败不影响转账),也不要把需要一致性的操作拆成多个事务。
  3. 注意隔离级别:根据业务选择隔离级别(如金融场景用 "可重复读" 保证数据一致性,普通查询场景用 "读已提交" 提升并发)。
  4. 异常必须回滚 :开发中需确保 "任何业务异常都触发回滚",避免出现 "部分提交" 的情况(如 Spring 的@Transactional需指定rollbackFor = Exception.class,默认仅回滚运行时异常)。
  5. 锁冲突处理 :高并发场景下,事务可能因锁等待超时失败,需添加重试机制(如用 Spring 的@Retryable注解)。
相关推荐
q***649743 分钟前
Spring Boot 各种事务操作实战(自动回滚、手动回滚、部分回滚)
java·数据库·spring boot
忘记9261 小时前
mybatis是什么
数据库·oracle·mybatis
q***92511 小时前
Springboot3 Mybatis-plus 3.5.9
数据库·oracle·mybatis
q***47431 小时前
PostgreSQL 中进行数据导入和导出
大数据·数据库·postgresql
傻啦嘿哟2 小时前
物流爬虫实战:某丰快递信息实时追踪技术全解析
java·开发语言·数据库
optimistic_chen2 小时前
【Redis 系列】Redis详解
linux·数据库·redis·缓存·xsheel
想唱rap2 小时前
C++ map和set
linux·运维·服务器·开发语言·c++·算法
熊文豪2 小时前
17年稳定运行:金仓数据库如何成为电力行业的“数字基石“
数据库·kingbasees·金仓数据库·电科金仓·kes
r***11332 小时前
Redis--模糊查询--方法实例
数据库·redis·缓存