目录
事务是什么:
事务(Transaction),就是将一组SQL语句放在同一批次内去执行,如果一个SQL语句出错,则该批次内 的所有SQL都将被取消执行。
简单事务实现举例:
就像现实中两个人转账,转账方的操作成功,但是收钱方并没有收到钱。这个时候我们应该要实现当无论哪一方的操作失败,数据库中的金额都保持不变。
-- 创建一个bank表,字段为姓名和金额。
create table bank(
bid int primary key auto_increment,
bname varchar(10),
bmoney decimal(20,2)
);-- 添加数据
insert into bank(bname,bmoney) values('收钱',5);
insert into bank(bname,bmoney) values('转账',100000000000000);-- 事务的操作
-- 1. 关闭自动提交
set autocommit = 0;
-- 2. 开始事务
start transaction;
-- 3. 一组sql语句
update bank set bmoney = bmoney-1000 where bname='转账';
update bank set bmoney = bmoney+1000 where bname='收钱';-- 4. 结束事务(判断)
-- 提交
commit;
-- 回滚
rollback;
-- 5. 开启自动提交
set autocommit = 1;
事务ACID原则:
原子性、一致性、隔离性、持久性
事务的原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。
REDO LOG 称为 重做日志 ,提供再写入操作,恢复提交事务修改 的页操作,用来保证事务的持久性。
UNDO LOG 称为 回滚日志 ,回滚行记录到某个特定版本,用来保 证事务的原子性、一致性。
事务隔离性
什么是事务的隔离性:为了让不同的事务之间相互不存在干扰,就需要对事务的操作进行隔离, 事务的隔离性也就是将操作同一个数据的事务相互分离,让操作之间分开有序的执行
用什么方式实现事务的隔离性: 通常数据库里都是采用锁的机制,保证事务之间的隔离性
事务并发问题: 在事务并发执行的时候,如果不进行事务隔离,那么就会产生脏写、脏读、 重复读、幻读的问题。
事务的隔离级别:
-
READ_UNCOMMITTED 读未提交 会产生脏读、 重复读、幻读
-
READ_COMMITTED 读提交(不可重复读) 会产生重复读、幻读
-
REPEATABLE_READ 重复读 会产生幻读
-
SERIALIZABLE 串行化
每个隔离级别都针对事务并发问题中的一种或几种进行解决,事务级别越高,解决的 并发事务问题也就越多,同时也意味着加的锁就越多,所以性能也会越差。
mysql默认隔离级别:不可重复读
innodb不会出现幻读问题,通过mvcc机制
锁分类:
基于锁的属性分类:共享锁(读锁、S锁)、排他锁(写锁,X锁)。
基于锁的粒度分类:表锁、行锁(记录锁、间隙锁、临键锁)。
基于锁的状态分类:意向共享锁、意向排它锁。
附一些事务常见面试题:
1. 事务并发会出现的问题:
脏写( Dirty Write ) 对于两个事务 Session A、Session B,如果事务Session A 修改了 另⼀个 未提交 事务Session B 修改过 的数据,那就意味着发⽣了 脏写
脏读( Dirty Read ) 对于两个事务 Session A、Session B,Session A 读取 了已经被 Session B 更新 但还 没有被提 交 的字段。 之后若 Session B 回滚 ,Session A 读取 的内容就是 临时且⽆效 的。 Session A和Session B各开启了⼀个事务,Session B中的事务先将studentno列为1的记录的name 列更新 为'张三',然后Session A中的事务再去查询这条studentno为1的记录,如果读到列name的值为'张 三',⽽ Session B中的事务稍后进⾏了回滚,那么Session A中的事务相当于读到了⼀个不存在的数据,这 种现象 就称之为 脏读 。
不可重复读( Non-Repeatable Read ) 对于两个事务Session A、Session B,Session A 读取 了⼀个字段,然后 Session B 更新 了该字 段。 之后 Session A 再次读取 同⼀个字段, 值就不同 了。那就意味着发⽣了不可重复读。 我们在Session B中提交了⼏个 隐式事务 (注意是隐式事务,意味着语句结束事务就提交了),这 些事务 都修改了studentno列为1的记录的列name的值,每次事务提交之后,如果Session A中的事务都可 以查看 到最新的值,这种现象也被称之为 不可重复读 。
幻读( Phantom ) 对于两个事务Session A、Session B, Session A 从⼀个表中 读取 了⼀个字段, 然后 Session B 在 该表中 插 ⼊ 了⼀些新的⾏。 之后, 如果 Session A 再次读取 同⼀个表, 就会多出⼏⾏。那就意味着发⽣了幻 读。 Session A中的事务先根据条件 studentno > 0这个条件查询表student,得到了name列值为'张 三'的记录; 之后Session B中提交了⼀个 隐式事务 ,该事务向表student中插⼊了⼀条新记录;之后Session A 1. 事务并发会出现的问题 2 中的事务 再根据相同的条件 studentno > 0查询表student,得到的结果集中包含Session B中的事务新插⼊ 的那条记 录,这种现象也被称之为 幻读 。我们把新插⼊的那些记录称之为 幻影记录 。
2. 幻读:
幻读是指在⼀个事务中多次执⾏相同的查询,但是第⼆次查询返回的结果集中包含了第⼀次查询时 不存在的记录。这通常发⽣在其他事务插⼊了新的记录,⽽这些新记录在第⼀个查询之后、第⼆个 查询之前被插⼊到数据库中。
为了避免幻读问题,可以采取以下⼏种⽅法:
1. 使⽤事务隔离级别: 重复读(Repeatable Read): 设置事务隔离级别为重复读可以避免幻读。在这个隔离级 别下,MySQL使⽤间隙锁(Gap Locks)来锁定查询结果集之间的间隙,防⽌其他事务 插⼊新的记录。 串⾏化(Serializable): 设置事务隔离级别为串⾏化可以完全避免并发问题,但可能会降 低性能,因为所有事务都会按顺序执⾏。
2.使用⾏级锁: 在执⾏更新或删除操作时,可以显式加锁来防⽌其他事务插⼊新的记录。
3.间隙锁: InnoDB存储引擎使⽤间隙锁来锁定查询结果集之间的间隙,防⽌其他事务插⼊新 的记录。
4.使⽤悲观锁: 在事务开始时就对需要访问的数据加锁,直到事务结束。这种⽅法可以有效避免幻读,但 也可能导致锁等待和性能下降。
5.使⽤乐观锁: 假设并发冲突较少,事务在提交时才检查是否有冲突。通常通过版本号或时间戳来实现。 虽然这种⽅法不能完全避免幻读,但可以减少锁的使⽤,提⾼并发性能。
6.使⽤事务的SAVEPOINT和ROLLBACK: 在事务中使⽤保存点(SAVEPOINT)和回滚(ROLLBACK)功能,可以在发现幻读后回 滚到保存点,重新执⾏查询。
7. 使⽤数据库约束: 使⽤唯⼀约束或主键约束来防⽌插⼊重复的记录,从⽽避免幻读。
3. MySQL的MVCC:
MySQL的多版本并发控制(MVCC)是⼀种⽤于实现事务隔离的技术,它允许多个事务在同⼀时 刻对同⼀数据进⾏操作⽽不互相阻塞。MVCC通过维护数据的多个版本来实现这⼀点,每个事务看 到的数据版本是基于该事务开始时的数据版本。
标签:事务,隔离,记录,幻读,--,Session,Mysql From: https://blog.csdn.net/2301_78794952/article/details/140791857