简要
mysq事务是自动提交的, 例如insert, update语句等
如下:
想要手动设置mysql事务就需要使用如下语句:
-- 关闭自动提交 set autocommit = 0;
autocommit默认值为1, 也就是默认开启自动事务
手动事务使用案例
创建表格
create database if not exists db_transacton; user db_transaction; -- 创建用户表 create table userinfo( id int primary key, name varchar(20), money double );
插入数据:
insert into userinfo values(1,'zhangsan',1000); insert into userinfo values(2,'lisi',1000);
设置手动提交事务:
set autocommit = 0;
在设置手动事务之前可以先查看autocommit的状态:
select @@autocommit;
-- 结果如下:
结果为1相当于开启了自动提交.
模拟账户转账:
begin; -- 首先要开启事务 update userinfo set money = money - 200 where id = 1; -- id == 1代表zhangsan update userinfo set money = money + 200 where id = 2; -- id == 2代表lisi -- 以下两个操作只能选择一个, 要么提交, 要么回滚 -- 执行完毕之后, 提交事务 commit; -- 回滚事务 rollback
提交事务之后. 那么就相当于zhangsan向lisi转账成功, 回滚操作就相当于 提交的事务出现了问题,被重置, zhangshan和lisi都回到了交易之前的状态.
事务的特性
- 原子性: 也就是事务开启之后, 之后的所有操作要么完成要么不完成, 就例如转账的时候, 涉及到一个人的账户减少, 另外一个人的账户增加, 那么这两个操作, 要么全部完成, 要么全部失败, 全部失败也就是执行了回滚操作, 让一个行为执行, 另外一个行为无法执行的情况重置到最开始的情况, 也就是两个行为都没发生的情况. 要么就两个行为都成功, 然后提交事务
- 一致性:这里的一致性可以理解为事务操作之后数据的正确性, 就例如一个人向另外一个人转账, 不可能是转账的那个人转出去500, 收账的人到账600吧? 这不符合数据库的正确性, 所以事务操作应该保证在执行事务的前后, 系统数据的正确性
- 隔离性: 这个事物在操作的过程中, 有可能收到其他事务的干扰, 例如有一个人向收账人转账, 收账人又对其账户进行取款, 那么转账这个行为就是取款这个操作看不见的. 我有1000大洋, 我向别人转账的时候, 分两步, 一步是我的扣200, 另外一步是别人的账户加200, 提交事务后那我的账户就是800,但是这个时候如果另外一个给我转账的事务也在进行, 给我转了500块, 但是给我转账的事务是先提交的, 这个时候我的账户就是1500, 然后再提交我给别人转账的事务, 那么就将我的账户余额修改为了800, 那么我不亏大发了. 所以应该设置隔离, 让这两个事务尽量互不干扰.
- 持久性: 事务一旦提交, 其结果就是数据库被修改, 数据就会在本地数据库进行存储或者修改, 本地磁盘的操作是永久的. 除非下次继续修改此磁盘.
事务的隔离级别
Isolate, 顾名思义就是将事务与另外一个事物隔离开, 为什么要隔离开呢? 如果一个事物正在操作的数据也被另外一个事务修改了, 最后执行结果可能无法达到预期, 如果没有隔离这两个事务, 那么后面还会导致很多问题出现.
这张图, 越往下面, 也就是越靠近序列化, 那么他的隔离级别就越高, 反之就越低, mysql的隔离级别默认是可重复度,
下面我们探究一个这四个事务隔离级别的作用:
- 读未提交( Read uncommitted )
一个事务可以读取另一个未提交事务的数据,最低级别,任何情况都无法保证,会造成脏读问题.
- 读已提交(Read committed)
一个事务要等另一个事务提交后才能读取数据,可避免脏读的发生,会造成不可重复读
- 可重复读(Repeatable read)
就是在开始读取数据(事务开启)时,不再允许修改操作,可避免脏读、不可重复读的发生但是会造成幻读。- 串行(Serializable)
是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用
下面来分析一下什么叫做脏读, 不可重复读, 幻读!!
脏读
脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的,值得注意的是,脏读一般是针对于update操作的.
一个事务正在访问数据, 并且对数据做出了修改, 但是这种修改并没有提交到数据库中去, 也就是虽然修改了数据库的值, 但是并未提交事务, 没有提交事务就代表这个事物随时可能因为出现问题而回滚, 此外另外一个事务也访问这个数据, 然后使用了这个数据, 但是这个数据并未随着事务提交,而事后这个事务因为某些原因写入了错误的值而回滚, 这个时候另外一个事物读取到了这个错误的数据, 也就是脏数据, 依据这个脏数据做出的行为是不正确的. 他很有可能破坏事物的一致性. 那么这个事务读取这个错误的数据的行为就叫做脏读.
不可重复读
不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。
在一个事务内, 多次访问同一个数据, 但是同时另外一个事物也在访问同一数据并且要修改这个数据, 而且这个修改操作是穿插在这个事务多次访问之间的, 由于别的事务的修改, 那么会让第一个事务多次读取可能会存在读到的数据不一样的情况, 这样就发生了一个事务多次读取同一个数据, 但是读取到的结果是不一样的情况, 因此称为不可重复读.
幻读
指当事务不是独立执行时发生的一种现象.
例如, 事务T1对一个表中的数据进行了修改, 这个修改操作设计表中的全部数据行, 同时第二个事务T2也修改这个表中的数据, 这种修改时向表中插入一行新数据, 那么以后就会发生: 操作事务T1的用户发现表中还存在没有修改的数据行, 就好像发生了幻觉一样.
解决 幻读, 一般的方法是增加范围锁rangeS, 锁定检索范围为只读, 这样就避免了幻读.
查看事务隔离级别
show variables like '%isolation%'
其中Variable_name = transaction_isolation 的value值为 Repeatable-read, 也就是可重复读.
设置隔离级别
-- 设置读未提交 set session transaction isolation level read uncommitted; -- 设置读已提交 set session transaction isolation level read committed; -- 设置可重复读 set session transaction isolation level repeatable read; -- 设置串行化 set session transaction isolation level serializable;