[Mysql-事务]

目录

事务是什么:

简单事务实现举例:

事务ACID原则:

事务隔离性

事务的隔离级别:

锁分类:


事务是什么:

        事务(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 称为 回滚日志 ,回滚行记录到某个特定版本,用来保 证事务的原子性、一致性。

事务隔离性

什么是事务的隔离性:为了让不同的事务之间相互不存在干扰,就需要对事务的操作进行隔离, 事务的隔离性也就是将操作同一个数据的事务相互分离,让操作之间分开有序的执行

用什么方式实现事务的隔离性: 通常数据库里都是采用锁的机制,保证事务之间的隔离性

事务并发问题: 在事务并发执行的时候,如果不进行事务隔离,那么就会产生脏写、脏读、 重复读、幻读的问题。

事务的隔离级别:

  1. READ_UNCOMMITTED 读未提交     会产生脏读、 重复读、幻读

  2. READ_COMMITTED 读提交(不可重复读)  会产生重复读、幻读

  3. REPEATABLE_READ 重复读    会产生幻读

  4. 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通过维护数据的多个版本来实现这⼀点,每个事务看 到的数据版本是基于该事务开始时的数据版本。 

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值