欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

分布式事物 [ 认识事物、肮脏的写作、肮脏的阅读、不可重复的阅读、幻影阅读 ] (I) - 全面详解(学习总结--从开始到深化)

最编程 2024-04-23 14:35:48
...

分布式事物处理_认识本地事物


网络异常,图片无法展示
|


什么是事物


事务就是针对数据库的一组操作,它可以由一条或多条SQL语句组 成,同一个事务的操作具备同步的特点,事务中的语句要么都执 行,要么都不执行。


举个栗子:


你去小卖铺买东西,一手交钱,一手交货就是一个事务的例子,交钱和交货必须全部成功,事务才算成功,任一个活动失败,事务将撤销所有已成功的活动。


什么是本地事物


在计算机系统中,更多的是通过关系型数据库来控制事务,这是利 用数据库本身的事务特性来实现的,因此叫数据库事务,由于应用 主要靠关系数据库来控制事务,而数据库通常和应用在同一个服务器,所以基于关系型数据库的事务又被称为本地事务。

网络异常,图片无法展示
|

网络异常,图片无法展示
|

数据库事务的四大特性ACID


网络异常,图片无法展示
|


总结


数据库事务在实现时会将一次事务涉及的所有操作全部纳入到一个 不可分割的执行单元,该执行单元中的所有操作要么都成功,要么 都失败,只要其中任一操作执行失败,都将导致整个事务的回滚。


关系型数据库事务基础_并发事务带来的问题

网络异常,图片无法展示
|


并发事务带来的问题


数据库一般会并发执行多个事务,而多个事务可能会并发地对相同 的数据进行增加、删除、修改和查询操作,进而导致并发事务问 题。

网络异常,图片无法展示
|


脏写


当两个或两个以上的事务选择数据库中的同一行数据,并基于最初 选定的值更新该行数据时,因为每个事务之间都无法感知彼此的存 在,所以会出现最后的更新操作覆盖之前由其他事务完成的更新操 作的情况。也就是说,对于同一行数据,一个事务对该行数据的更新操作覆盖了其他事务对该行数据的更新操作。

网络异常,图片无法展示
|


解决方案: 让每个事物按照顺序串行的方式执行,按照一定的顺序一次进行写操作。


脏读


一个事务正在对数据库中的一条记录进行修改操作,在这个事务完 成并提交之前,当有另一个事务来读取正在修改的这条数据记录 时,如果没有对这两个事务进行控制,则第二个事务就会读取到没 有被提交的脏数据,并根据这些脏数据做进一步的处理,此时就会 产生未提交的数据依赖关系。我们通常把这种现象称为脏读,也就是一个事务读取了另一个事务未提交的数据。

网络异常,图片无法展示
|


解决方案: 先写后读,也就是写完之后再读。


不可重复读


一个事务读取了某些数据,在一段时间后,这个事务再次读取之前 读过的数据,此时发现读取的数据发生了变化,或者其中的某些记录已经被删除,这种现象就叫作不可重复读。


解决方案: 先读后写,也就是读完之后再写。


幻读


一个事务按照相同的查询条件重新读取之前读过的数据,此时发现 其他事务插入了满足当前事务查询条件的新数据,这种现象叫作幻读。


解决方案: 先读后写,也就是读完之后再写。


关系型数据库事务基础_MySQL事务隔离级别



MySQL中的InnoDB储存引擎提供SQL标准所描述的4种事务隔离级 别,分别为


读未提交 (Read Uncommitted)

读已提交 (ReadCommitted)

可重复读(Repeatable Read)

串行化 (Serializable)。



1、读未提交(Read Uncommitted):事务可以读取未提交的数据,也称作脏读(Dirty Read)。一 般很少使用。

2、读已提交(Read Committed):是大都是 DBMS (如:Oracle, SQLServer)默认事务隔离。执行两次同意的查询却有不同的结果,也叫不可重复读。

3、可重复读(Repeable Read):是 MySQL 默认事务隔离级别。能确保同一事务多次读取同一数据 的结果是一致的。可以解决脏读的问题,但理论上无法解决幻读(Phantom Read)的问题。

4、可串行化(Serializable):是最高的隔离级别。强制事务串行执行,会在读取的每一行数据上加锁,这样虽然能避免幻读的问题,但也可能导致大量的超时和锁争用的问题。很少会应用到这种级别,只有在非常需要确保数据的一致性且可以接受没有并发的应用场景下才会考虑。


MySQL事务隔离级别_模拟异常发生之脏读



前置知识


# 查看 MySQL 版本
select version();
 
# 开启事务
start transaction;
 
# 提交事务
commit;
 
# 回滚事务
rollback;


查看连接的客户端详情


每个 MySQL 命令行窗口就是一个 MySQL 客户端,每个客户端都可 以单独设置(不同的)事务隔离级别,这也是演示 MySQL 并发事务的基础。

show processlist;



新建数据库和测试数据

-- 创建数据库
drop database if exists testdb;
create database testdb;
use testdb;
-- 创建表
create table userinfo(
 id int primary key auto_increment,
 name varchar(250) not null,
 balance decimal(10,2) not null default 0
);
-- 插入测试数据
insert into userinfo(id,name,balance)
values(1,'Java',100),(2,'MySQL',200);


查询事务的隔离级别

select
@@global.transaction_isolation,@@transaction_is
olation;


设置客户端的事务隔离级别


通过以下 SQL 可以设置当前客户端的事务隔离级别:


set session transaction isolation level 事务隔离 级别;


脏读


一个事务读到另外一个事务还没有提交的数据,称之为脏读。脏读 演示的执行流程如下:


脏读演示步骤1


设置窗口 2 的事务隔离级别为读未提交,设置命令如下:

set session transaction isolation level read
uncommitted;



注意: 事务隔离级别读未提交存在脏读的问题。


脏读演示步骤2


窗口2开启事务,查询用户表如下图所示:

start transaction;
select * from userinfo;



注意: 从上述结果可以看出,在窗口 2 中读取到了窗口 1 中事务未提 交的数据,这就是脏读。


脏读演示步骤3


在窗口 1 中开启一个事务,并给 Java 账户加 50 元,但不提交事 务,执行的 SQL 如下:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
 
mysql> update userinfo set balance=balance+50
where name="java";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0



脏读演示步骤4


在窗口 2 中再次查询用户列表,执行结果如下:

上一篇: 采访者Spring 事务有多少种传播行为?

下一篇: 花半秒钟研究事物本质的人和花一辈子研究事物本质的人有什么区别?