• MySQL事务



    数据库中事务的重要性,就不多说了!本篇博文主要针对MySQL数据库介绍事务的重要性!

    一、事务概述

    事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则每个操作所有的更改将会被撤销,这也是事务的原子性(要么成功,要么失败)。

    MySQL的事务是在存储引擎曾实现的。MySQL的事务有ACID:

    • A:原子性(atomicity):一个事务必须被视为一个不可分割的单元;
    • C:一致性(consistency):数据库是从一种状态切换到另一种状态;
    • I:隔离性(isolation):事务在提交之前,对于其他事务不可见;
    • D:持久性(durablity):一旦事务提交,所修改的将永久保存到数据库;

    二、事务的基本语法

    2.1 示例

    mysql> create table bank (
        -> name varchar(25),
        -> money float );
    #创建表
    mysql> insert into bank values('lu','1000'),('qi','5000');
    #插入数据
    mysql> select * from bank;
    +------+-------+
    | name | money |
    +------+-------+
    | lu   |  1000 |
    | qi   |  5000 |
    +------+-------+
    #查看数据
    mysql> begin;
    #begin开启事务,start transaction也可开启事务
    mysql> update bank set money=money - 1000 where name='qi';
    mysql> update bank set money=money+1000 where name ='lu';
    #更新数据
    mysql> select * from bank;
    +------+-------+
    | name | money |
    +------+-------+
    | lu   |  2000 |
    | qi   |  4000 |
    +------+-------+
    #查看数据
    mysql> rollback;
    #回滚事务
    mysql> select * from bank;
    +------+-------+
    | name | money |
    +------+-------+
    | lu   |  1000 |
    | qi   |  5000 |
    +------+-------+
    #再次查询数据,发现已经便会了原来的值
    mysql> commit;
    #提交事务
    mysql> select * from bank;
    +------+-------+
    | name | money |
    +------+-------+
    | lu   |  1000 |
    | qi   |  5000 |
    +------+-------+
    #查询数据
    

    一个事务涉及到的命令:

    • 事务的开始:start transaction或begin;
    • 事务提交:commit;
    • 事务回滚:rollback;

    2.2 查看提交模式并更改

    mysql> show variables like 'AUTOCOMMIT';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | autocommit    | ON    |
    +---------------+-------+
    #ON表示自动提交
    mysql> set AUTOCOMMIT=0;
    #关闭自动提交,0是关闭,1是开启
    mysql> show variables like 'AUTOCOMMIT';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | autocommit    | OFF   |
    +---------------+-------+
    #OFF表示已经关闭自动提交
    

    2.3 事务的四种隔离级别

    事务在提交之前对其他事务不可见。

    • read unaommitted(未提交读)
    • read committed(已提交读)
    • Repeatable read(可重复读)
    • seaializable(可串行化)

    2.4 未提交读

    事务中修改没有提交对其他事务也是可见的,俗称脏读。

    mysql> create table student (
        -> id int not null auto_increment,
        -> name varchar(32) not null default '',
        -> primary key(id)
        -> )engine=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    #创建测试表
    

    接下来需要自行开启两个MySQL会话终端,A和B,两个终端都需执行以下命令:

    mysql> set session tx_isolation='read-uncommitted';
    #设置为未提交读
    

    客户端A

    mysql> begin;
    mysql> select * from student;
    mysql> insert into student(name) values('zhangsan');
    #注意,此时事务未提交
    

    客户端B

    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    +----+----------+
    #查询表,即可看到客户A没有提交的事务
    

    总结:以上可以看出未提交读隔离级别非常危险,对于一个没有提交事务所做修改对另一个事务是可见状态,出现了脏读!非特殊情况不建议使用此级别。

    2.5 已提交读

    多数数据库系统默认为此级别(MySQL不是)。已提交读级别为一个事务只能已提交事务所做的修改,也就是解决了未提交读的问题。

    需执行完成以下命令,再进行测试!

    mysql> set session tx_isolation='read-committed';
    #设置为已提交读
    

    客户端A

    mysql> begin;
    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    +----+----------+
    mysql> insert into student(name) values('lisi');
    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    |  4 | lisi     |
    +----+----------+
    

    客户端B

    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    +----+----------+
    #并没有查看到客户端A刚刚插入的数据
    

    客户端A

    mysql> commit;
    

    客户端B

    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    |  4 | lisi     |
    +----+----------+
    #客户端A提交完成后便可查看到已经更新的数据
    

    总结:从上面可以看出,提交读没有了未提交读的问题,但是我们可以看到客户端A的一个事务中客户端B执行了两次同样的SELECT语句,得到不同的结果,因此已提交读又被称为不可重复读。同样的筛选条件可能得到不同的结果。

    2.6 可重复读

    可重复读解决了不可重复读的问题,数据库级别没有解决幻读的问题。

    以下是客户端A和客户端B同时操作(都设置为可重复读,然后两边都开启一个事务):

    mysql>  set session tx_isolation='repeatable-read';
    mysql>  begin;
    

    客户端A

    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    |  4 | lisi     |
    +----+----------+
    mysql> update student set name='wangwu' where id=5;
    mysql> commit;
    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    |  4 | wangwu   |
    +----+----------+
    

    客户端B

    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    |  4 | lisi     |
    +----+----------+
    mysql> commit;
    mysql> select * from student;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    |  4 | wangwu   |
    +----+----------+
    即可看到客户端A更新的数据
    

    总结:上面可以看出,可重复读两次读取的内容不一样。数据库的幻读问题并没有得到解决。幻读只读锁定里面的数据,不能读锁定外的数据,解决幻读出了mvcc机制Mvcc机制。

    2.7 可串行化

    是最高隔离级别,强制事务串行执行,执行串行了也就解决问题了,这个只有在对数据一致性要求非常严格并且没有并发的情况下使用。

    在客户端A及客户端B进行以下操作(设置为可串行读):

    mysql> set session tx_isolation='serializable';
    

    客户端A

    mysql> begin;
    mysql> select * from student where id < 5;
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | zhangsan |
    |  4 | wangwu   |
    +----+----------+
    

    客户端B

    mysql> insert into student(name) values('maliu');
    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
    #此时进行插入操作时,会一直卡在这里,然后出现下面的报错信息,除非客户端Acommit提交事务
    

    总结:我们发现INSERT 语句被阻塞执行,原因是A执行了查询表student同时满足id<10,已被锁定。如果查询表student同时满足id<5,则新增语句可以正常执行。

    以上几种的隔离界别对比如下:

    隔离级别 脏读 不可重复 幻读 加锁读
    未提交读
    提交读
    可重复读
    串行读
    *************** 当你发现自己的才华撑不起野心时,就请安静下来学习吧!***************
  • 相关阅读:
    eclipse如何与git 配合工作。
    git托管代码(二)
    PPC2003 安装 CFNET 3.5成功
    我的Window Mobile WCF 項目 第三篇 WM窗体设计
    我的Window Mobile WCF 項目 第一篇Mobile开发和WinForm开发的区别
    我的Window Mobile WCF 項目 第七天
    我的Window Mobile WCF 項目 第二篇 WindowsMobile访问WCF
    WCF 用vs2010 和 vs2008的简单对比测试
    vs2010beta1 和 搜狗输入法 冲突,按下 Ctrl 键就报错,重装搜狗解决
    我的Window Mobile WCF 項目 第六天 (二)
  • 原文地址:https://www.cnblogs.com/lvzhenjiang/p/14197306.html
Copyright © 2020-2023  润新知