目录
一、事务
事务有ACDI原则
1.原子性(Atomicy)
要么都成功,要么都失败
2. 一致性(Consistency)
事务前后的数据保持一致
3.持久性(Durability) – 事务提交
事务一旦提交不可逆
4.隔离性 (Isolation)
多个人,同时给张三转钱的时候,每一笔转账开启一个事务,多个事务相互隔离就是隔离性
二、隔离性产生的数据问题
多个用户都在操作数据产生的数据问题。
1.脏读 :一个事务读取了了另一个事务没有提交的 数据
1.比如张三和李四同时区银行取相同账号的钱,此时账户上有1000,李四,取钱1000,数据还没有提交成功
2.张三以迅雷不及掩耳之势迅速取钱 1000,此时因为账户的数据还没有来得及修改,于是,张三查询余额的时候还是1000.
2.不可重复读:多次数据读取的结果不同 (这个不一定是错误)
1.你查看 QQ 的信息,第一次刷新,没有人给你发信息,第二次刷新,出现了一条信息,2次查询的结果不一致,因为第一次刷新的对方还没有提交成功,就是不可重复读
3.虚读(幻读):在一个事务内读取到了别人插入的数据,导致前后不一致。
和不可重复读类似,第一次查询余额的时候,是1000 元,然后别人充值了1000 元,你第二次查询的时候就是 2000 元了,
三、事务4个隔离级别
1.四个隔离级别的了解
设置级别 | 脏读 | 不可重复读 | 幻读 |
可读未提交(read-uncommitted) | 会 | 会 | 会 |
只读提交(read-committed) | 会 | 会 | |
可重复读(repeatable-read) | 会 | ||
可序列化(serializable) |
可见,可序列化 serializable,最安全但是速度最慢。
值得一提的是:大多数数据库默认 read-committted 比如SQLServer 和Oracle,MySQL是更高级的 repeatable-read.
2.四个隔离级别详解:
参考博客
2.1.可读未提交 (read-uncommitted)
(1)意义:顾名思义,读取的修改了(update)没有提交(submit)的数据
(2)问题:会产生所有的隔离性数据问题
(3)举例:张三,工资1万元/月,但是,老板给他发工资的时候不小心多输入了一个0,10万/月,此时update的SQL以及执行了,但是还没有submit,张三早上查看自己的工资看到欣喜若狂,但是老板发现自己输入了一个0,连忙回滚(rollback),张三的工资又回到了设置之前,毫不知情的张三却还乐呵呵的清空着他的购物车。这就是脏读
2.2 只读提交(read-committed)
(1)意义:就是只能读取提交后的数据,
(2)问题:解决脏读的问题,但是其他问题依旧存在。
(3)举例:
- 1.解决脏读问题:张三,工资1万元/月,但是,老板给他发工资的时候不小心多输入了一个0,10万/月,此时update的SQL以及执行了,但是还没有submit,张三早上查看自己的工资还是以前的工资,应为老板还没提交submit
- 2.不可重复读取的问题:张三和朋友聚餐,“服务员结账!”张三招了招手,服务员唯唯诺诺过来,张三掏出手机看了看自己的余额,1000元,“扫码”,服务员赶紧立马拿出了收款码,张三对准二维码正扫描着,(同时张三的女朋友用张三的银行卡清空了自己1000元的的购物车,并付款支付成功)张三手机叮一声,扫码成功,一个圈圈转啊转,最后弹出一条提示,“您的余额不足”,张三当时心态爆炸。这就是不可重复读
2.3. 可重复读(repeatable-read)
(1)意义:可以重复读取的数据
(2)问题:在read-committed的基础上解决update,更新数据产生的不可重复读的问题,但是还有插入insert导致的幻读的问题。
(3)举例:
- 1.解决不可重复读的问题: 张三买单时(事务开启,不允许其他事务惊醒update操作),同时张三的女朋友用张三的银行卡清空自己1000元的的购物车,并付款**,无法进行update操作,付款失败**。)张三消费成功。
- 2.幻读的问题:张三女友购物消费1000,然后她去查看自己的消费记录(妻子事务开启,扫描全表)正在查找的时候,张三消费1000元请朋友吃饭,(张三提交消费数据insert)此时妻子打印消费结果的时候发现多了一个1000元的消费,一共消费了2000元,似乎产生的幻觉,这就是幻读,幻读其实并不一定是错误。
2.4.序列化Serializable
(1)意义:参考幻读的问题
(2)问题:解决所有数据读取问题,但是因为速度太低,一般不采用
(3)例子:参考幻读的问题。
3.如何设置事务的隔离级别?
3,1 全局修改
在mysql.ini 配置文件最后加上
#可选的参数有: read-uncommitted ,read-committed ,repeatable-read,serializable
[mysqld]
transaction-isolation = REPEATABLE-READ
3.2 对当前session修改
登录mysql之后,输入
set session transaction isolation level read uncommitted;
四、事务的案例模拟
1.建表
1.数据库 事务银行 tansactionBank
CREATE DATABASE IF NOT EXISTS `transactionBank`CHARACTER SET utf8 COLLATE utf8_general_ci;
2.表 事务银行 tansactionBank01
CREATE TABLE IF NOT EXISTS `tansactionBank01`(
`id` INT NOT NULL AUTO_INCREMENT COMMENT "账号",
`name` VARCHAR(30) NOT NULL COMMENT "名称",
`money` DECIMAL(9,2) NOT NULL DEFAULT 0 COMMENT "账户余额00.00格式默认为0",
PRIMARY KEY (`id`)
)ENGINE = INNODB DEFAULT CHARSET=utf8
3.插入数据:
INSERT INTO `tansactionbank01`
(`name`,`money`)
VALUES
("张三",0),
("李四",1000);
最终效果:
2. 了解事务的基本操作
操作 | 作用 | 解释 |
set autocommit = 0; | 关闭自动提交,mysql默认启动自动提交 | 使用手动事务之前关闭自动提交事务 |
set autocommit = 1; | 启动功自动提交 | 使用手动提交事务之后开启自动提交事务 |
start transaction; | 开启一个(组)事务 | |
commit; | 提交事务 | 持久性,提交之后不能回滚了 |
rollback; | 回滚事务 | 回到最初的起点(有存档的办法可回到存档点但是不常用了解即可.) |
3. 事务实例:使用事务李四给张三转账 500元
-- 1. 关闭自动提交,方便手动提交
SET autocommit = 0;
-- 2.开启一个(组)新的事务
START TRANSACTION;
-- 3.进行事务转账操作
UPDATE `tansactionbank01` SET
`money` = `money`- 500
WHERE `name` = "李四";
UPDATE `tansactionbank01` SET
`money` = `money`+ 500
WHERE `name` = "张三";
-- 4. 回滚
ROLLBACK;
-- 4.2 提交
COMMIT;
-- 4.3 提交后再回滚 (数据已经更改持久性,不能回滚成功)
COMMIT;
ROLLBACK;
-- 5.把自动提交恢复为默认.
SET autocommit = 1;