事务是作为单个逻辑工作单元执行的一系列操作。这些操作要么全部,要么没有,是一个不可分割的工作单元。
例如,购买东西支付的过程中会有一系列操作,如查询余额、加减、更新余额。这些操作必须是同时的。否则,显示你支付成功,但是系统没有收到钱
在MySQL中,事务支持是在引擎层实现的,MyISAM引擎不支持事务
要成为事务,逻辑工作单元必须满足关系数据库管理系统中的四个特征。
即所谓的ACID:原子性、一致性、隔离性、持久性。
原子性:事务的所有操作要么完成要么未完成,不会在中间阶段结束。
一致性:在事务之前和之后,数据库的完整性限制不会被打破。
隔离性:当多个事务同时访问数据库中的同一数据时,将显示关系。
持久性:事务完成后,事务所做的更改将持久保存,不会丢失。
begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
BEGIN; -- 开启事务START TRANSACTION; -- 开启事务INSERT INTO tb_type_details VALUES ( '1','保洁','保洁岗位','清洁作业','清洁下水道');COMMIT; -- 提交事务ROLLBACK; -- 回滚事务
set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。
set autocommit=0 -- 关闭自动提交INSERT INTO tb_type_details VALUES ( '1','保洁','保洁岗位','清洁作业','清洁下水道');COMMIT; -- 提交事务ROLLBACK; -- 回滚事务
当在数据库上同时执行多个事务(可以理解为多任务、并发场景)时,可能会发生脏读、不可重复读和幻读。
为了解决这些问题,MySQL 引入了“隔离级别”的概念。
隔离级别越高,效率就越低,很多时候,我们必须在两者之间找到平衡。SQL标准的事务隔离级别包括:读(取)未提交(read uncommitted)、读(取)已提交(read committed)、可重复读取(repeatable read)和串行化(serializable )。
读未提交(RU,Read Uncommitted),它可以读取事务的中间过程。它违反了ACID特性,并且存在脏读取的问题。因此基本上不被使用,可以被忽略。
读已提交(RC,Read Committed),这意味着,如果已经提交了其他事务,我们可以看到这也是最常用的级别。然而,由于一些历史原因,RC可能在生产环境中使用不多。
可重复读(RR,Repeatable Read)是目前使用最广泛的级别。它的特点是间隙锁定,这仍然是默认级别。在这个级别,死锁、低并发和其他问题经常发生。
串行化(serializable ),不是多版本实现,而是单版本实现,因为它的所有实现都是通过锁实现的。基本上不被使用,可以被忽略。
脏读:事务A读取事务B更新的数据,然后B回滚,因此A读取的数据是脏的(实际上不应该存在的数据)
不可重复读:事务A多次读取相同的数据。事务B在事务A多次读取的过程中更新并提交数据,导致事务A多次捕获同一数据时结果不一致。
一个事务读取到其他事务已提交的数据导致前后两次读取数据不一样的情况
不可重复读和幻读很容易混淆,不可重复读侧重于修改,而幻读侧重于添加或删除。要解决不可重复读取的问题,只需要锁-,符合条件的行,而要解决幻读问题需要锁表。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
SELECT @@transaction_isolation; -- 查看mysql事务隔离级别SELECT @@tx_isolation; -- 查看mysql事务隔离级别
将事务隔离级别修改为读未提交,可以看到,事务还没有提交,这时候去查询这条数据,发现数据已经可见了。
START TRANSACTION; -- 事务A
INSERT INTO tb_type_details VALUES ( '1','保洁','保洁岗位','清洁作业','清洁下水道');
select * from tb_type_details where id= 1;
COMMIT; -- 提交事务
一个事务读取到其他事务已提交的数据导致前后两次读取数据不一样的情况。
BEGIN; -- 开启事务
select * from tb_type_details where id= 1;
UPDATE tb_type_details set type_details='地面清洁' where id= 1;
COMMIT; select * from tb_type_details where id= 1;