ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

数据库事务的操作

2019-09-20 09:39:12  阅读:232  来源: 互联网

标签:product 数据库 事务 productCount 操作 where select productId


数据库事务的操作

1.1 查看事务隔离级别

SHOW VARIABLES LIKE 'tx_isolation';

查看全局的事务隔离级别

SHOW GLOBAL VARIABLES LIKE 'tx_isolation';

使用系统变量查询

SELECT @@global.tx_isolation; SELECT @@session.tx_isolation; SELECT @@tx_isolation;

1.2 设置Mysql的事务隔离级别

# GLOBAL:设置全局的事务隔离级别 SESSION:设置当前session的事务隔离级别,如果语句没有指定GLOBAL或SESSION,默认值为SESSION
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
  {
       REPEATABLE READ
     | READ COMMITTED
     | READ UNCOMMITTED
     | SERIALIZABLE
   }

使用系统变量设置事务隔离级别

SET GLOBAL tx_isolation='REPEATABLE-READ'; SET SESSION tx_isolation='SERIALIZABLE';

2 案例分析

作为演示:product表

带着上面的我们来看一下,事务在没有隔离性的情况下,会引发哪些问题?

同时打开两个窗口模拟2个用户并发访问数据库(注:此处需要使用InnoDB引擎)

2.1 事务隔离级别设置为read uncommitted

	查询事务隔离级别 

SELECT @@tx_isolation;

	设置隔离级别为读未提交

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

注意:需要同时修改两个窗口的事务隔离级别

时间轴 事务A 事务B
T1 start transaction;
T2 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);
T3 start transaction;
T4 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);
T5 update product set productCount = 99 where productId = 1;
T6 select p.productName,p.productCount from product p where p.productId=1;(productCount =99);
T7 ROLLBACK;
T8 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);

T1—— A用户开启事务,start transaction; T2—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T3——B用户开启事务,start transaction; T4——B用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T5—— B用户购买了一台小米手机,update product set productCount = 99 where productId = 1; 此时只修改数据并未提交事务。 T6—— A用户刷新页面,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为99。 T7—— B用户购买失败,回滚事务。 T8—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。

小结:

事务A读取了未提交的数据,事务B的回滚,导致了事务A的数据不一致,导致了事务A的脏读!

要避免这种问题的出现,那么就引出了读已提交。

2.2 事务隔离级别设置为read committed

	查询事务隔离级别 

SELECT @@tx_isolation;

	设置隔离级别为读未提交

SET SESSION  TRANSACTION ISOLATION LEVEL READ COMMITTED;

注意:需要同时修改两个窗口的事务隔离级别

时间轴 事务A 事务B
T1 start transaction;
T2 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);
T3 start transaction;
T4 select p.productName,p.productCount from product p where p.productId=1;(productCount =100) ;
T5 update product set productCount = 99 where productId = 1 ;
T6 select p.productName,p.productCount from product p where p.productId=1;(productCount =100) ;
T7 commit;
T8 select p.productName,p.productCount from product p where p.productId=1;(productCount =99) ;

T1—— A用户开启事务,start transaction; T2—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T3——B用户开启事务,start transaction; T4——B用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T5—— B用户购买了一台小米手机,update product set productCount = 99 where productId = 1; 此时只修改数据并未提交事务。 T6—— A用户刷新页面,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T7—— B用户提交事务,购买成功。 T8—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为99。

小结:

可以看到避免了脏读现象,但是却出现了,一个事务还没有结束,就发生了不可重复读问题(也就是说,这种隔离界别只能读到其他事务已经提交的事务),即事务A来说 productCount从 100->100->99。但这个过程中事务并未提交结束。

2.3 事务隔离级别设置为Repeatable Read(mysql默认级别)

	查询事务隔离级别 

SELECT @@tx_isolation;

	设置隔离级别为读未提交

SET SESSION  TRANSACTION ISOLATION LEVEL REPEATABLE READ;

注意:需要同时修改两个窗口的事务隔离级别

时间轴 事务A 事务B
T1 start transaction;
T2 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);
T3 start transaction;
T4 select p.productName,p.productCount from product p where p.productId=1;(productCount =100) ;
T5 update product set productCount = 99 where productId = 1 ;
T6 select p.productName,p.productCount from product p where p.productId=1;(productCount =100) ;
T7 commit;
T8 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);

T1—— A用户开启事务,start transaction; T2—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T3——B用户开启事务,start transaction; T4——B用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T5—— B用户购买了一台小米手机,update product set productCount = 99 where productId = 1; 此时只修改数据并未提交事务。 T6—— A用户刷新页面,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。 T7—— B用户提交事务,购买成功。 T8—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。

小结:

可以看到可重复读隔离级别避免了脏读,不可重复读的问题,但是出现了幻读现象。事务A查询到的小米数量等于100,但是事务B修改了数量为99,但是事务A读取到的值还是100。当事务A去减1等于99时,是错误的,此时应该是99-1=98才对。接下来我们再提高一个事务隔离级别。

2.4 事务隔离级别设置为Serializable

	查询事务隔离级别 

SELECT @@tx_isolation;

	设置隔离级别为读未提交

SET SESSION  TRANSACTION ISOLATION LEVEL REPEATABLE READ;

注意:需要同时修改两个窗口的事务隔离级别

时间轴 事务A 事务B
T1 start transaction;
T2 start transaction;
T3 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);
T4 update product set productCount = 99 where productId = 1;(等待中…)

T1—— A用户开启事务,start transaction; T2——B用户开启事务,start transaction; T3——A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。T4——B用户要购买一部手机,这时候数据库就卡在了这里,然后过大概1分钟之后就会报错。

小结:

在我们Serializable隔离级别中,我们可以看到事务B去做修改动作时卡住了,不能向下执行。这是因为:给事务A的select操作上了锁,所以事务B去修改值的话,就会被卡住。只有当事务A操作执行完毕,才会执行事务B的操作。这样就避免了上述三个问题了。

总结一下:

不可重复读是由于数据修改引起的,幻读是由数据插入或者删除引起的。 

问题本身

  • 回到问题的本身,其实我们并不需要将事务提到这么高。

  • 问题的本身就是,当我们读完了的时候,就要在上面加锁。我们不希望别人能够去读它。因为别人读到了count,就会修改count的值,并写进去。所以我们在select 操作的时候,加上for update。这时候就会把这行操作给锁掉了。那么另外一个人也进行相同的操作,也表示select 出来的count需要进行update,需要锁住。

    select p.productName,p.productCount from product p where p.productId=1 for update;

PS: 在实际开发过程中,这样的加锁行为,是非常的耗系统性能的。

标签:product,数据库,事务,productCount,操作,where,select,productId
来源: https://blog.csdn.net/cai1560819/article/details/101050350

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有