快捷搜索:

数据库事务和隔离级别 mysql

事务概述

事务是一个或一组sql语句组成的一个执行单元,这个执行单元要么全部执行成功,要么全部执行失败。用于保证数据的完整性。

如账户转账,张三给李四转500,对应的sql语句应该是update张三的余额-500,并且update李四的余额+500,如果先更新完张三的数据,然后出现了异常,导致李四的余额修改不了,那么就出现数据上的问题了,应该使用事务来解决这一问题,当中间出现异常后回滚,让张三的update失效;如果没有出现异常就提交事务。

通过SHOW ENGINES;查看mysql中支持的存储引擎,注意只有innodb支持事务

事务的创建分为:

    隐式事务:事务没有明显的开启和结束的标记,如insert、update、delete语句执行时在默认情况下就是一个事务,因为默认是自动提交事务的,所有执行完后就立马自动提交事务了 显式事务:事务具有明显的开启和结束的标记,前提是需要先设置自动提交事务为禁用,手动的提交事务或回滚事务

设置方法为:

select @@autocommit;   #如果为1自动提交事务,为0需要手动提交事务
set autocommit=0;    #设置不自动提交事务

该设置只是针对当前会话有效,不是针对全局的。

使用事务的步骤:

    步骤一:开启事务

set autocommit=0;

start transaction; 开启事务,可选的,不写也可以,因为关闭了自动提交事务后,默认就开启了事务

    步骤二:编写事务中的sql语句 步骤三:结束事务

commit;提交事务、rollback;回滚事务

事务的四大特性

事务的ACID属性为:

    原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 一致性(Consistency):事务完成后,必须使所有的数据都保持一致状态,如转账的例子中双方的余额总和总是相同且正确的。 隔离性(lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

并发事务问题

对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:

问题 描述 脏读 一个事务读到另外一个事务还没有提交的数据。 不可重复读 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。 幻读 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了"幻影”。
    脏读

如下图,当事务二修改了id为1的数据后,事务一查询id为1的数据,查询的结果是修改后的数据,此时事务二可能会回滚事务,导致事务一查询的数据是一个脏数据,没有的数据。

    不可重复读

如下图,事务一中,两次查询相同id的结果是不同的,叫做不可重复读,侧重于在同一个事务中

    幻读

如下图,当事务一第一次查询到没有id为1的数据时,准备插入前,事务二恰好插入了id为1的数据,且提交了事务,因为id是主键所以事务一会插入失败,此时因为解决了不可重复读的问题,事务一再次查询id为1的数据,还是查不到,然后就是插不进去,导致幻读。

事务的隔离级别

用于解决并发事务问题的。数据库提供的四种隔离级别:

隔离级别 描述 READ UNCOMMITTED (读未提交数据) 允许事务读取未被其他事务提交的变更,约束最小,速度最快 READ COMMITTED (读已提交数据) 只允许事务读取被其他事务提交的变更,可以避免脏读 REPEATABLE READ (可重复读) 确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读、不可重复读 SERIALIZABLE(串行化) 确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,并发问题都能解决,性能低下

mysql默认是REPEATABLE READ,可以通过下面的命令查询当前的隔离级别

select @@transaction_isolation

通过下面的命令改变隔离级别,Session是会话级别的改变,Global是全局改变

set [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE]

演示:

用两个命令行打开不同的会话

1.演示在read uncommitted下的读脏数据,如下

2.演示read committed

如上发现read committed解决了读脏数据,但是在第3、4步的查询发现,在同一个事务中连续两次查询的同一列数据居然不相同了,出现不可重复读的问题。

3.演示repeatable read

不可重复读解决了,但是幻读还存在,如下

4.演示serializable,解决幻读问题

该隔离级别性能比较低,但是涉及到了很多数据库锁的概念,可以深入了解一下

总结

隔离级别 脏读 不可重复读 幻读 Read Committed √ √ √ Read Uncommitted × √ √ Repeatable Read × × √ Serializable × × ×

注意:事务隔离级别越高,数据越安全,但是性能越低。

经验分享 程序员 职场和发展