MYSQL 实验十五:

实验15 事务设计与锁

  一、实验目的

    通过实验,掌握数据库管理系统中事务和锁的概念和并发控制的方法,并且能够进行合理的事务设计。

二、实验原理

   1、事务

    事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为 ACID(原子性、一致性、隔离性和持久性)属性,只有这样才能成为一个事务:

    原子性(事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。);

    一致性(事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。);

    隔离性(由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。);

     持久性(事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。)

   2、事务设计

     START TRANSACTION 标记一个显式本地事务的起始点。START TRANSACTION 代表一点,由连接引用的数据在该点是逻辑和物理上都一致的。如果遇上错误,在 START TRANSACTION 之后的所有数据改动都能进行回滚,以将数据返回到已知的一致状态。每个事务继续执行直到它无误地完成并且用 COMMIT 对数据库作永久的改动,或者遇上错误并且用 ROLLBACK 语句擦除所有改动。

      mysql 事务定义

   START TRANSACTION;

     (事务体,一系列操作)  

     COMMIT;  (提交)

    ROLLBACK ; (回滚)

   

  3、锁

   如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。并发问题包括: 丢失或覆盖更新;未确认的相关性(脏读);不一致的分析(非重复读);幻像读。  

   你可以用下列语句查询全局和会话事务隔离级别:

   SELECT @@global.tx_isolation;

   SELECT @@tx_isolation;

  设置 隔离级别  三级锁

  set transaction isolation level serializable | repeatable read | read committed | read uncommitted

set GLOBAL transaction isolation level  repeatable read;

  注意:不要随便修改隔离级别。

  

 三、实验条件

       操作系统: win7

     开发环境:数据库管理服务器 MYSQL 5.5

 四、实验内容方法

  (一)事务与锁的基本实验  

    1. 创建简单数据库BankDB,验证事务与锁,避免   脏读,不可重复读,幻读

 //银行卡号BankID, 姓名 Cname, 存款 Balance

    DROP SCHEMA IF EXISTS BankDB ;

    CREATE SCHEMA IF NOT EXISTS BankDB default character set gbk;

    USE BankDB ;

      Create table Bank(BankID int, Cname char(20), Balance decimal(10,2) );

         insert into Bank values (20181211,'张三', 20000);

         insert into Bank values (20181212,'李四', 10000);

        insert into Bank values (20181213,'王五', 20000);

      *  检验隔离级别 -读脏数据

   

        开启另外一个命令窗口,在两个命令窗口分别执行,设置为读未提交

            

            在命令窗口1

              set session transaction isolation level read uncommitted;

              SELECT @@tx_isolation;

            Start transaction;   

              update Bank set Balance=Balance+99 where Cname='张三';

              update Bank set Balance=Balance+88 where Cname='王五';

             

          在另命令窗口2

             set session transaction isolation level read uncommitted;

             SELECT @@tx_isolation;

             select * from bank;

              张三的存款?

         在窗口1

           执行     rollback;

             select * from bank;

            张三的存款?

        //恢复隔离级别 repeatable read

       在命令窗口1

              set session transaction isolation level repeatable read;

              SELECT @@tx_isolation;

            Start transaction;   

              update Bank set Balance=Balance+99 where Cname='张三';

              update Bank set Balance=Balance+88 where Cname='王五';

              select * from bank;

          在另命令窗口2

              set session transaction isolation level repeatable read;

             SELECT @@tx_isolation;

             select * from bank;

              张三的存款?

         在窗口1

           执行     rollback;

             select * from bank;

            张三的存款?

   2. 创建不同并发事务

      1)转账存储过程pp1 包含 转账事务T1, 从C1 转账mon 给C2     //call pp1('张三','王五',555);

  Delimiter //   

Create Procedure pp1(in C1 char(20), in C2 char(20),in mon decimal(10,2))

 Begin

  declare point decimal(10,2);    /*  最低存款数,低于此数不能转账  */

  Start transaction;   

    set point =1000;   /*  最低存款数=1000  */

    select Balance  转账方转账前存款 from Bank where Cname=C1;

    select Balance  接账方转账前存款 from Bank where Cname=C2;

  do sleep(20);  /*  暂停20秒  */

      update Bank set Balance=Balance - mon where Cname=C1;  /*  从C1中转出mon  */

      update Bank set Balance=Balance + mon where Cname=C2;  /*  C2中转入mon  */

     select Balance  转账方转账后存款 from Bank where Cname=C1;

     select Balance  接账方转入后存款 from Bank where Cname=C2;        

     /* 当转账一方的存款少于1000,取消转账 */

    if (point>(select Balance from Bank where cname=C1)) then

         rollback;

      else

         commit;

    end if;

     select Balance  事务结束后转账方转账后存款 from Bank where Cname=C1;

     select Balance  事务结束后接账方转入后存款 from Bank where Cname=C2;

 end //

delimiter ;

    

   2)读取数据存储过程 pp2, 包含读取账户存款信息的事务T2,没有写操作

   Delimiter //   

Create Procedure pp2()

 Begin

  Start transaction;   

    select Balance  张三转账前存款 from Bank where Cname='张三';

    select Balance 王五转入前存款 from Bank where Cname='王五';

    select sum(Balance) 张三与李四存款总和 from Bank where Cname in('张三','李四');

  

 do sleep(30);  /*  暂停30秒  */

     select Balance  张三转账后存款 from Bank where Cname='张三';

     select Balance  王五转入后存款 from Bank where Cname='王五';

     select sum(Balance) 张三与李四存款总和 from Bank where Cname in('张三','李四');

    commit;

 end //

delimiter ;

    

     3 并发实验1

       在现有的客户端(客户端1)  再开启1个客户端(cmd,命令窗口 登录 mysql -u root -p ),(客户端2),注意要切换到BankDB数据库(use BankDB;)

        为保证并发实验,下列两个客户端执行的命令时间不要超过10秒

         1)在客户端1执行存储过程pp1, 含事务张三 转555元给王五

                call pp1('张三','王五',555);  

         2)在客户端2执行存储过程pp2,含事务读取账户信息

               call pp2();

      记录实验结果,有没有出现不重复读?

    4.并发实验2

    制造回滚

       call pp1('张三','王五',27900);  /*  转账数超过存款数  */

       call pp2();

     记录实验结果,有没有出现脏读,不可重复读

    5. 死锁实验

      1)设计转账存储过程pp3 包含转账事务T3, 从C2的存款的10% 转账 给C1     

              注意 T1的事务是从C1 转账mon 给C2 ,T3的事务是从C2的存款的10% 转账 给C1      

    Delimiter //   

  Create Procedure pp3(in C1 char(20), in C2 char(20))

  Begin

      declare data2 decimal(10,2);

     Start transaction;   

       /* data2  是王五10% 的存款 */

     select Balance*0.1 into data2 from bank where Cname=C2;

   select data2 王五百分之10的存款;

    select Balance  王五转账前存款 from Bank where Cname=C2;

  

   /* 扣除王五存款 */

    update Bank set Balance=Balance - data2  where Cname=C2;

     select Balance 张三转入前存款 from Bank where Cname=C1;

        /* 转入张三账户*/

      update Bank set Balance=Balance + data2 where Cname=C1;

     select Balance  王五转账后存款 from Bank where Cname=C2;

     select Balance  张三转入后存款 from Bank where Cname=C1;

 end //

delimiter ;

   2)并发实验 测试是否出现死锁

   再开启1个客户端,注意要切换到BankDB数据库(use BankDB),

   在3个客户端窗口的执行顺序:

      call pp1('张三','王五',555);   /* T1事务:张三 转555元给王五    */  

      call pp3('张三','王五');   /* T3事务: 王五又将10%的存款转给张三  */

      call pp2();  /* T2事务: 读取账户信息   */

  

  如果出现死锁,系统如何处理!

  (二)事务设计

     1. 从业务逻辑中抽出事务

    根据事务的ACID 特性,找出那些是要么全做、要么全不做的,密切关联的业务(原子性),导致数据库发生改变的(要求一致性)(如一系列的SQL修改操作,不是查询),,不受干扰,永久发生作用的业务。

    注意

     ** 不能将没有关联的业务设计为一个事务。

     ** 不能设计过长、过于复杂的事务

   例如商贸活动很多中有, a.商场采购产品,b.供应商提供产品, c 客户浏览产品,d. 商场年终盘点,e.创建订单信息,f.订购产品,g.运输商发货,h.更新库存...

  事务一:

      a.商场采购产品

      b.供应商提供产品

      c 客户浏览产品

      e.创建订单

      f.订购产品

      h.更新库存

   事务二:

      e.创建订单

      f.订购产品

      g.运输商发货

      h.更新库存

   事务三:

      e.创建订单

      f.订购产品

      h.更新库存

   分析哪个事务设计是合适的。

    2. 在存储过程中实现事务

      1).用老师提供的数据库脚本trade2_script.txt 创建数据库trade2

      2). 创建存储过程 transp  ,检验事务效果-破坏性实验

     Delimiter //   

    Create Procedure transp()

      Begin

      Start Transaction;  /* 开始事务 */

      /* e.创建订单  订单号 11088, 客户编码ALFKI,客户编号 6,订购时间 '2018-12-17' */

      insert into orders (OrderID,CustomerID,EmployeeID,OrderDate) values(11088,'ALFKI',6,'2018-12-17');

       /*  f.订购产品: 订单ID=11088, 产品ID=13,单价=6,数量=10,折扣=0.1 */

      insert into orderdetails values(11088,13,6,10,0.1);

       

       /*  h.更新库存     */

      update products set unitsinstock = unitsinstock - 10  where productid=13;

      

       /*  f.订购产品:订单ID=11088, 产品ID=18,单价=62.5,数量=15,折扣=0.13 */

      insert into orderdetails values(11088,18,62.5,15,0.13);

      /*  h.更新库存     */

      update products set unitsinstock = unitsinstock - 15  where productid=E18;   /* 破坏性 错误无 E18*/

      commit; /* 提交 */

   end //

Delimiter ;

  测试事务

   测试用例: 在更新库存中出错 productid=E18,

       预期:在订单表中撤销订单号及相关信息, 在订单细节表中撤销订购的产品信息,在产品表中恢复原来的库存。

    执行存储过程之前(事务发生前 检查产品库存: productid 13 库存 24; productid18 库存 42;

     select unitsinstock from products where productid=13;

     select unitsinstock from products where productid=18;  

     调用存储过程 call transp();

     检查与预期是否一致?将会报错,但是将出现不一致的情况。

        

    select * from orderdetails where orderid=11088 and productid=13;

   select * from orderdetails where orderid=11088 and productid=18;

    不一致需要逐条小心地恢复 (还必须考虑删除顺序)

    update products set unitsinstock = unitsinstock + 10  where productid=13;

    delete from orderdetails where orderid=11088;

    delete from orders where orderid=11088;

     3. 错误回滚 rollback

     加入一条 错误处理标记 declare CONTINUE HANDLER FOR SQLEXCEPTION SET t_err = 1;

       if t_err =1 then

          Rollback; /* 有sql 错误 回滚 */

       else

          commit; /* 无 sql 错误 提交 */

       end if;

将存储过程改造为:

Delimiter //   

Create Procedure transp1()

 Begin

   declare t_err int default 0;

   declare CONTINUE HANDLER FOR SQLEXCEPTION SET t_err = 1;

  Start Transaction;

 insert into orders (OrderID,CustomerID,EmployeeID,OrderDate) values(11088,'ALFKI',6,'2018-12-10');

       /* 订单ID=11088, 产品ID=13,单价=6,数量=10,折扣=0.1 */

      insert into orderdetails values(11088,13,6,10,0.1);

      update products set unitsinstock = unitsinstock - 10  where productid=13;

      

       /* 订单ID=11088, 产品ID=18,单价=62.5,数量=15,折扣=0.13 */

      insert into orderdetails values(11088,18,62.5,15,0.13);

      update products set unitsinstock = unitsinstock - 15  where productid=E18;   /* 错误无 E18*/

       if t_err =1 then

          Rollback; /* 有sql 错误 回滚 */

       else

          commit; /* 无 sql 错误 提交 */

       end if;

   end //

Delimiter ;

执行此存储过程

 call transp1();

  按上面的方法测试事务。

  (五)扩展实验

    根据上述思路,在Java 程序中实现事务。

  1. 实验结果分析及总结

实验结果分析:实验结果都在预期范围之内;总结:学会 SELECT[ALL|DISTINCT]<目标列表达式〉[,<目标列表达式〉]...

   FROM<表名或视图名〉[,<表名或视图名〉]...

   [WHERE<条件表达式>]

   [GROUP BY<列名1〉[HAVING<条件表达式>]]

   [ORDERBY<列名2〉[ASC|DESC]]等用法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/8839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cheetah3D for Mac - 轻松打造专业级3D作品

对于追求专业级3D作品的设计师来说&#xff0c;Cheetah3D for Mac无疑是一款不可多得的工具。 这款软件拥有强大的建模、渲染和动画功能&#xff0c;能够满足您在3D设计方面的各种需求。通过简单的操作&#xff0c;您可以轻松构建出复杂的3D模型&#xff0c;并为其添加逼真的材…

Gitlab自动化测试的配置

1. 代码分支命名规范检测 Setting → Repository → Push rules → Branch name&#xff0c;添加分支命名规范对应的正则表达式。如&#xff1a; ^(Release|Tag|Develop|Feature)_._.|Main$ 表示分支名只能以以下关键字之一开头&#xff1a;Release、Tag、Develop和Feature。 …

使用C++ __builtin_expect优化程序性能后,程序体积不改变原因

结论 使用__builtin_expect优化程序性能&#xff0c;开启-O3的情况下&#xff0c;确实程序的体积可能不改变&#xff0c;但是还是会产生优化效果。 测试代码 不使用__builtin_expect #include <iostream>void fun(int a, int b) {// 不使用__builtin_expectif (a <…

Spring aop切面编程

Spring aop切面编程 如何使用利用AuditAction创建切入点 如何使用 Aspect // 1. 创建一个类&#xff0c;用Aspect注解标记它&#xff0c;表明这是一个切面类。 Component public class LoggingAspect {// 2. 定义切点&#xff1a;在通知方法上&#xff0c;使用切点表达式来指定…

案例|200多套设备实时监测,守护江西彰湖水库安全

中型水库作为水利建设的重要组成部分&#xff0c;在防洪、供水、农业灌溉、改善民生和生态效益等方面都具有重要意义。国务院发布《关于切实加强水库除险加固和运行管护工作的通知》&#xff0c;重点提出要提升信息化管理能力&#xff0c;要加快建设水库雨水情测报、大坝安全监…

【XR806开发板试用】SPI驱动数码管显示

准备工作 安装repo 创建repo安装目录。 mkdir ~/bin下载repo wget https://storage.googleapis.com/git-repo-downloads/repo -P ~/bin/改变执行权限 chmod ax ~/bin/repo设置环境变量&#xff0c;在~/.bashrc文件的最后输入 export PATH~/bin:$PATH和export REPO_URLhttps://…

分布式光纤测温DTS的测温范围是多少?

分布式光纤测温DTS的测温范围不仅仅取决于光缆的感温能力&#xff0c;还受到多种复杂因素的影响。尽管高温光缆可以耐高温&#xff0c;低温光缆可以耐低温&#xff0c;甚至镀金光缆能够耐受高达700摄氏度的极高温度&#xff0c;然而&#xff0c;这些因素并不能完全解释测温范围…

Jmeter性能测试(六)

一、查询数据库进行参数化步骤 1、添加并配置JDBC Connection Configuration 2、添加并配置JDBC Request 3、添加并配置循环控制器组件 4、添加并配置计数器组件(控制循环中的变量取值) 5、通过函数助手生成引用变量名 6、引用变量进行参数化 二、添加配置JDBC Connection Co…

3万字长文看懂Django面试

目录 Django框架的核心设计哲学是什么? 解释Django中的MTV模式与MVC模式的区别。

zookeeper启动后占用8080端口问题分析及解决

ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务。它为分布式应用提供一致性服务的软件&#xff0c;提供的功能包括&#xff1a;配置维护、域名服务、分布式同步、组服务等。 我们经常在运行zookeeper服务时&#xff0c;不需要配置服务端口&#xff0c;…

MySQL 性能模式 performance_schema

文章目录 前言1. 性能模式特点2. 开启性能模式3. 性能模式表分类3.1 采集设置表3.2 实例信息表3.3 等待事件记录表3.4 阶段性事件记录表3.5 语句事件记录表 后记 前言 performance_schema 是 MySQL 提供的一个较为底层的监控&#xff0c;它可以监控数据库中每个线程的所有动作…

运用分支结构与循环结构写一个猜拳小游戏

下面我们运用平常所学的知识来写一个小游戏&#xff0c;这样能够加强我们学习的趣味性&#xff0c;并且能够更加的巩固我们所学的知识。 游戏代码&#xff1a; 直接放代码&#xff1a;&#xff08;手势可以使用数字来代替&#xff0c;比如0对应石头&#xff0c;1对应剪刀&…

【Linux第四课 - git、gdb】git仓库的使用、dgb代码调试

目录 一 、gitgit、gitee、github的理解Linux中git的使用提交删除 二 、gdb - 调试工具进入gdb版本gdb开始调试123、范围查找 一 、git 在linux中使用 分支管理、多人协作 git、gitee、github的理解 git是版本控制工具&#xff0c;gitee和github是网站 Linux中git的使用 提…

编程入门(六)【Linux系统基础操作四】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f525; 欢迎来到我的博客 &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️寻至善的主页 文章目录 &#x1f525;前言&#x1f680;if else条件控制基本的if语句带else的if语句嵌…

rancher 证书过期网页进不去 问题解决

参考文章&#xff1a;https://docs.rancher.cn/docs/rancher2.5/cluster-admin/certificate-rotation/_index/#%E6%A6%82%E8%BF%B0 一、问题故障描述&#xff1a; 查看 rancher 容器 日志 docker logs --tail 100 dfc1ef8e4f29提示以下信息&#xff1a; 2024/05/07 08:49:5…

Jmeter性能测试(四)

一、遇到问题解决思路 1、检查请求头是否正确 2、检查请求参数是否正确 3、检查鉴权信息是否正确 4、检查变量作用域 5、检查数据提取是否正确(正则/json提取器) 二、请求头检查 1、在Http信息头管理器查看 2、注意这里的变量作用域是全局的 三、请求参数检查 1、在查看结…

硬件知识积累 音频插座的了解,看音频插座的原理图来了解音频插座的引脚。

1. 音频接口 音频插座是一种用于连接音频信号线路的电子元件&#xff0c;常见于音频设备&#xff08;如音响、耳机、话筒等&#xff09;中。它的主要作用是将电子信号转化为声音信号&#xff0c;以满足人们对于音乐、电影、游戏等方面的需求。 根据插头形状的不同&#xff0c;音…

萤瓴优选:短视频带货新风口,普通人不可错过的黄金赛道!

随着电商行业的快速发展&#xff0c;短视频带货成为了现代营销中的一股新势力。在这个激烈竞争的市场环境中&#xff0c;如何找准一个适合自己的发展方向成为了很多人的关注焦点。2024年起&#xff0c;萤瓴优选应运而生&#xff0c;打造出了一个让普通人也能参与其中的短视频带…

Linux设置open files

临时设置 ulimit -n 1025 查看是否成功 ulimit -n 永久设置&#xff0c;网上很多说添加* soft nofile 65535 * hard nofile 65535但设置后不生效 vim /etc/security/limits.conf * soft nofile 65535 * hard nofile 65535 * soft nproc 65535 * hard nproc 65535 然后重新…

使用 Parallels Desktop 在 Mac 上畅玩 PC 游戏

我们不再需要接受 “Mac 不是为游戏而打造” 这一事实&#xff1b;Parallels Desktop 通过将电脑变成高性能的游戏设备&#xff0c;从而改变了一切。 Parallels Desktop 充分利用 Mac 硬件的强大功能&#xff0c;让您无缝畅玩 Windows 专享游戏。 性能得到提升&#xff0c;可玩…