Mysql-事务

发布于:2025-08-06 ⋅ 阅读:(13) ⋅ 点赞:(0)


一、事务是什么?

事务是一种机制,包含了一组SQL语句。要么同时执行,要么同时不执行

事务是一个整体

如:事务中有10个SQL语句,1234成功5失败 -> 回滚

什么情况下使用事务 -> 如银行转账
A 1000 -> B 1000
1. A - 100
2. B + 100

事务格式

Begin;
SQL 语句
SQL 语句
SQL 语句
commit;

二、事务的特性(ACID)

A - Atomicity 原子性
事务是一个不可再分割的工作单元,要么都发生,要么都不发生

C - Consistency 一致性
事务开始之前和结束之后,数据库的完整性约束没有被破坏。
转账、购物(售出,库存)

I - Isolation 隔离性
多个事务并发执行时,一个事务的执行不能被其他事务干扰。

D - Durability 持久性
事务执行完成之后(commit),数据写入磁盘,不能被回滚。


三、事务的开启

1. Autocommit

设置是否自动提交
ON : 自动提交 -> 直接将数据写入数据库,相当于每次sql执行完都会自动commit
OFF: 禁止自动提交 -> 每一次写操作都需要commit/rollback操作数据才会写入数据库

每一个SQL都会当成一个事务

查看autocommit

root@(none) 10: 57>show variables like 'autocommit';
±--------------±------+
| Variable_name | Value |
±--------------±------+
| autocommit | ON |
±--------------±------+
1 row in set (0.01 sec)

设置禁止自动提交
Autocommit=0/off

commit => 将数据写入磁盘(commit前,数据在内存)
未使用commit退出后数据丢失

设置自动提交
Autocommit=1/on

执行SQL语句时,默认会将SQL当作一个事务执行,所以autocommit=1时,会自动commit操作


2. 开启事务

如果事务中有多个SQL语句,手动开启事务

  • 开启事务
    begin/start transaction
  • 执行SQL
    SQL 语句
    SQL 语句
  • 提交事务
    commit
  • 设置回滚点
    savepoint name
  • 回滚
    rollback [name]

准备工作

CREATE TABLE info(
id INT(10) PRIMARY KEY,
name VARCHAR(40),
money DOUBLE
);

INSERT INTO info VALUES (1,‘A’,1000);
INSERT INTO info VALUES (2,‘B’,1000);
SELECT * FROM info;

测试回滚

root@test 11: 15>begin ;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 16>update info set money=money+100 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@test 11: 16>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1100 |
|  2 | B    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)

(回滚时会彻底撤销当前事务中所有未提交的修改,并终止事务)
root@test 11: 16>rollback;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 17>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1000 |
|  2 | B    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)

提交测试

root@test 11: 19>begin;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 20>update info set money=money+100 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@test 11: 20>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1100 |
|  2 | B    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)

root@test 11: 20>commit;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 20>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1100 |
|  2 | B    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)

设置回滚点

root@test 11: 20>begin;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 22>update info set money=money+100 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@test 11: 22>savepoint s1;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 22>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1200 |
|  2 | B    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)

root@test 11: 22>update info set money=money+100 where id=2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@test 11: 22>savepoint s2;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 23>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1200 |
|  2 | B    |  1100 |
+----+------+-------+
2 rows in set (0.00 sec)

root@test 11: 23>insert into info values(3, 'C', 1000);
Query OK, 1 row affected (0.00 sec)

root@test 11: 23>savepoint s3;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 23>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1200 |
|  2 | B    |  1100 |
|  3 | C    |  1000 |
+----+------+-------+
3 rows in set (0.00 sec)

root@test 11: 23>rollback to s2;
Query OK, 0 rows affected (0.00 sec)

root@test 11: 24>SELECT * FROM info;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | A    |  1200 |
|  2 | B    |  1100 |
+----+------+-------+
2 rows in set (0.00 sec)

rollback => 回滚+事务结束
rollback to point => 回滚


四、事务并发存在的问题

多个事务同时并发执行时,可能会引发一系列数据一致性问题

  1. 脏读:读到了未提交的数据(更新数据时)
  2. 不可重复读:前后多次读取同一个数据内容不一致(更新数据时)
  3. 幻读:前后多次读取数据,数量的总量不一致(插入/删除数据时)
  4. 丢失更新: 多个事务同时更新同一个数据时,后提交的事务覆盖先提交的事务

五、隔离级别

  1. 读未提交(read uncommitted): 读取尚未提交的数据
    不解决以上任何问题
    安全性最差,性能最好
  2. 读已提交(read committed): 读取已经提交的数据,可以解决脏读
    只能读到已经提交的数据,未提交的不能读取
    Oracle数据中默认的级别
    安全性较差,性能较好
  3. 可重复读 (Repeatable read): 可以解决脏读、不可重复读
    一个事务执行的过程中,多次读取同一个数据,会得到相同的结果
    Mysql默认的隔离级别
    安全性好,性能中等
  4. 串行化(Serializable): 完全避免所有的问题
    事务被一个一个串行执行
    安全性最好,性能差
脏读 不可重复读 幻读 丢失更新
read uncommitted yes yes yes yes
read committed no yes yes yes
Repeatable read no no no yes
Serializable no no no no

1.查询隔离级别

查询全局事务隔离级别

select @@global.transaction_isolation;
±-------------------------------+
| @@global.transaction_isolation |
±-------------------------------+
| REPEATABLE-READ |
±-------------------------------+

show global variables like "%isolation%";
±----------------------±----------------+
| Variable_name | Value |
±----------------------±----------------+
| transaction_isolation | REPEATABLE-READ |
±----------------------±----------------+

查询当前会话(Session)的事务隔离级别

select @@session.transaction_isolation;
±--------------------------------+
| @@session.transaction_isolation |
±--------------------------------+
| REPEATABLE-READ |
±--------------------------------+

show session variables like '%isolation';
±----------------------±----------------+
| Variable_name | Value |
±----------------------±----------------+
| transaction_isolation | REPEATABLE-READ |
±----------------------±----------------+


2.设置隔离级别

全局隔离级别仅影响新创建的会话,已存在的会话不受影响

set global transaction isolation level read uncommitted;
select @@global.transaction_isolation;
±-------------------------------+
| @@global.transaction_isolation |
±-------------------------------+
| READ-UNCOMMITTED |
±-------------------------------+

root@(none) 10: 32>set session transaction isolation level reaad uncommitted;
Query OK, 0 rows affected (0.00 sec)
root@(none) 10: 33>select @@session.transaction_isolation;
±--------------------------------+
| @@session.transaction_isolation |
±--------------------------------+
| READ-UNCOMMITTED |
±--------------------------------+


总结

事务通过ACID 特性(原子性、一致性、隔离性、持久性),从根本上保证了数据库操作的可靠性、一致性和并发安全性,是处理关键业务(如金融交易、订单管理、数据同步等)不可或缺的机制


网站公告

今日签到

点亮在社区的每一天
去签到