Mysql事务机制
事务机制解决问题:
- 避免写入直接操作数据文件,直接操作数据文件是很危险的事,可以在确认无误后同步进总库.
- MySQL有5种日志文件,其中只有redo日志和undo日志与事物有关(5种日志文件后续再说)
- 默认情况下,MySQL执行每条SQL语句都会自动开启和提交事务
- 为了让多条SQL语句纳入一个事务下,可以手动管理事务
事务四种属性: 原子性 一致性 隔离性 持久性
原子性
事务是一个或者多个SQL语句组成的整体,要么全部执行成功,要么全都执行失败 ,事务执行之后,不允许停留在中间某个状态.比如:把10部门中MANGER员工调往20部门,其他岗位员工调往30部门,然后删除10部门. 涉及到事务:开启事务 UPDATE语句 DELETE语句 提交事务
比如下边三行代码, 第一行开启一个事务, 第二行代表sql语句,第三行代表要么commit提交后叠加覆盖原始数据库,要么rollback取消这一过程所有操作.
START TRANSACTION;
SQL语句
[COMMIT | ROLLBACK];
备注:COMMIT:持久化提交 ; ROLLBACK:回滚
举个例子:
START TRANSACTION; -- 启动事务机制
delete from t_emp; -- 增删改查过程
delete from t_dept; -- 增删改查过程
SELECT * FROM t_emp; -- 增删改查过程
SELECT * FROM t_dept; -- 增删改查过程
-- COMMIT; -- 提交同步(给注释掉了)
ROLLBACK ; -- 回滚不同步
事务一致性
不管在任何给定的时间\并发事务有多少, 事务必须保证运行结果的一致性,不允许数据歧义.比如银行转账,100个人互相乱七八糟的转账,但最后总额肯定是固定的.原来总值100万,经过一顿互相转账后,总额一定还是100万,不能因为几重了多钱,也不能因为bug少钱.
隔离性
- 隔离性要求事务不受其他并发事务的影响, 如果同在给定的时间内,该事物是数据库唯一运行的事务
- 默认情况下A事务,只能看到日志中该事物的相关数据
- 默认情况下A事务,只能看到该事物的相关数据
- 除了默认情况下,想看别的事务内容? 请继续往下看到隔离级别部分.
持久性
- 事务一旦提交,结果便是永久性的,即便发生宕机,仍然可以依靠事务日志完成数据的持久化
事务的四个隔离级别
刚才的隔离性上边说,默认情况下只看自己的,那么想看别人的或者想看曾经自己的,或者设定一些事务之间的sql执行顺序.那么就需要调整隔离级别了.首先看一张表:
买票案例–利用未提交事务read uncommitted
A去刷12306软件买票, 看到还剩一个座位,拍了下来,正在付款, 此时B也看到了.也拍了下来,然后吧唧把钱付了.A则付款失败了,返回一看刚才的未售出状态边已售出了…这不耽误事么,半路杀出个程咬金.
- READ UNCOMMITTED 代表可以读取其他事务未提交的数据
还是这个案例,如果B拍了正在付款,A看到的时候应该显示已售出,就避免了竹篮子打水一场空, 淘宝下单同样的场景.
怎么用? 事务前加上 :SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SQL语言的话可以如下案例,注意读里面注释
-- 案例一个
-- 事务A:开启事务,把所有工资设置为1,但是没提交(没commit) ,此时查出来都是1元;
START TRANSACTION; -- 启动事务机制
UPDATE t_emp SET sal=1;
SELECT sal FROM t_emp;
-- 此时开启案例B,也来读sal
SELECT empno , ename, sal FROM t_emp;
-- 读出来的还是原来的工资数据.
-- 如果想要B读取出A设置后的东西,则改成下边代码
-- B的结果:读取A未提交的
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT empno , ename, sal FROM t_emp;
转账支出案例-- 利用committed
Scott账务余额5000,B先支出100, 此时A开启进入系统,此时scott余额4900. 紧接着此时A转账1000,此时应该scott余额5900. 如果转账同时B又退回100,此时账户应该6000元.
但是如果不允许A读取B的操作未提交的,就没读到支出又退回的100.A读到5900块,少了100. 这样不对.大公司账面复杂,这一天得差飞了.
READ COMMITTED 代表只能读取其他事务提交的数据
承接上边的代码部分案例,请阅读备注
– 还是上边案例,若A没有提交commit 则B读不到的话,则用这句话:注意是committed
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT empno , ename, sal FROM t_emp;
下单后,提交订单前,商家提价了,按下单价支付案例–利用repeatable read
举例场景 : A下单时候350 ,但没付款. 正在犹豫时B商家把商品价格改高了到400. 过一会后A去付款还应该是付款350才对.
所以这个repeatable read 能读取当时执行时读到数据库的数据,不受后续数据库变化影响.
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
序列化事务–依次执行,未到执行时挂着
这个将把一切并发禁用, 让事务逐一执行, 这会降低数据库操作并发能力
开头设置这句:SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM table1;
-- 若别的事务正在运行,这条将一直不出结果等待中
举例:
A创建事务,修改了工资,但没commit提交确认,总库没改呢.此时B查东西将被挂起. 若A执行了commit或者rollback,则B进程结束.
A执行,但没commit
B 序列化设置的事务将挂着
若A 提交或者回滚不提交