Mysql中事务的详细概述

事务(transaction)

概述

一个事务其实就是一个完整的业务逻辑。是一个最小的工作单元。不可再分。

  • 假设从A账户向B账户中转账10000 , 将A账户的钱减去10000(update语句), 将B账户的钱加上10000(update语句), 这就是一个完整的业务逻辑。

事务就是批量的DML语句同时成功,或者同时失败

  • 只有DML语句才会有事务这一说,其它语句和事务无关 , 只要你的操作一旦涉及到数据的增、删、改,那么就一定要考虑安全问题。
  • 如果任何一件复杂的事儿都能一条DML语句搞定,那么事务则没有存在的价值了。但是一个业务通常需要多条DML语句共同联合起来才能完成,所以需要事务的存在。

在mysql当中默认的事务行为是怎样的?

  • mysql默认情况下是支持自动提交事务的(每执行一条DML语句,则提交一次)
  • 这种自动提交实际上是不符合我们的开发习惯,因为一个业务通常是需要多条DML语句共同执行才能完成的,为了保证数据的安全,必须要求同时成功之后再提交,所以不能执行一条就提交一条。
  • 关闭mysql的自动提交机制: start transaction;

原理

事务是怎么做到多条DML语句同时成功和同时失败的呢?

  • 在事务的执行过程中,每一条DML的操作都会记录到 InnoDB 存储引擎提供的“事务性活动的日志文件”中。

在事务的执行过程中,我们可以提交事务,也可以回滚事务(回滚永远都是只能回滚到上一次的提交点)

  • 提交事务: 清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。提交事务标志着,事务的结束。并且是一种全部成功的结束。
  • 回滚事务: 将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件 , 回滚事务标志着,事务的结束。并且是一种全部失败的结束。

事务具有四个特征 ACID

Atomicity(原子性): 说明事务是最小的工作单元。整个事务中的所有操作,必须作为一个单元全部完成或全部取消。

Consistency(一致性): 在同一个事务当中,所有操作必须同时成功,或者同时失败,以保证数据库从一个一致性状态转换到另一个一致性状态。

Isolation(隔离性): A事务和B事务之间具有一定的隔离。决定A事务在操作一张表的时候,另一个事务B也操作这张表会受到什么影响

Durability(持久性): 事务一旦提交后,该事务对数据库所作的更改将持久地保存在数据库之中,并不会被回滚 , 即使数据库发送故障也不应该对其有任何影响

事务中存在一些概念:
a) 事务(Transaction):一批操作(一组 DML)
b) 开启事务(Start Transaction)
c) 回滚事务(rollback)
d) 提交事务(commit)
e) SET AUTOCOMMIT:禁用或启用事务的自动提交模式
当执行 DML 语句是其实就是开启一个事务
关于事务的回滚需要注意:只能回滚 insert、delete 和 update 语句,不能回滚 select(回滚 select 没有任何意义),对于
create、drop、alter 这些无法回滚.

事务只对 DML 有效果。
注意:rollback,或者 commit 后事务就结束了。

事务的提交与回滚演示

    mysql>  use bjpowernode;
            Database changed
            
    mysql> select * from dept_bak;
            Empty set (0.00 sec)

    mysql> start transaction;
            Query OK, 0 rows affected (0.00 sec)

    mysql> insert into dept_bak values(10,'abc', 'tj');
            Query OK, 1 row affected (0.00 sec)

     mysql> insert into dept_bak values(10,'abc', 'tj');
            Query OK, 1 row affected (0.00 sec)

     mysql> select * from dept_bak;
            +--------+-------+------+
            | DEPTNO | DNAME | LOC  |
            +--------+-------+------+
            |     10 | abc   | tj   |
            |     10 | abc   | tj   |
            +--------+-------+------+
            2 rows in set (0.00 sec)

      mysql> rollback;
            Query OK, 0 rows affected (0.00 sec)

      mysql> select * from dept_bak;
            Empty set (0.00 sec)
mysql> use bjpowernode;
		Database changed
mysql> select * from dept_bak;
		+--------+-------+------+
		| DEPTNO | DNAME | LOC  |
		+--------+-------+------+
		|     10 | abc   | bj   |
		+--------+-------+------+
		1 row in set (0.00 sec)

mysql> start transaction;
		Query OK, 0 rows affected (0.00 sec)

mysql> insert into dept_bak values(20,'abc','bj');
		Query OK, 1 row affected (0.00 sec)

mysql> insert into dept_bak values(20,'abc','tj');
		Query OK, 1 row affected (0.00 sec)

mysql> insert into dept_bak values(20,'abc','tj');
		Query OK, 1 row affected (0.00 sec)

mysql> commit;
		Query OK, 0 rows affected (0.01 sec)

mysql> select * from dept_bak;
		+--------+-------+------+
		| DEPTNO | DNAME | LOC  |
		+--------+-------+------+
		|     10 | abc   | bj   |
		|     20 | abc   | tj   |
		|     20 | abc   | tj   |
		|     20 | abc   | tj   |
		+--------+-------+------+
		4 rows in set (0.00 sec)

mysql> rollback;
		Query OK, 0 rows affected (0.00 sec)

mysql> select * from dept_bak;
		+--------+-------+------+
		| DEPTNO | DNAME | LOC  |
		+--------+-------+------+
		|     10 | abc   | bj   |
		|     20 | abc   | tj   |
		|     20 | abc   | tj   |
		|     20 | abc   | tj   |
		+--------+-------+------+
		4 rows in set (0.00 sec)

数据库中读取数据存在的三大读问题

  • 脏读:在一个事务中读取到其它事务未提交到数据库的数据。
  • 不可重复读:在同一个事务当中多次执行同一查询语句,读取到其他事务提交到数据库的数据 , 导致当前事务每次查询到的结果集不一样。
  • 幻读:在同一个事务当中多次执行同一查询语句,只要当前事务不结束, 永远读取的都是刚开启该事务时的数据 。脑子中想的数据和真实数据不同

InnoDB 实现了四个隔离级别,用以控制事务所做的修改,并将修改通告至其它并发的事务

隔离级别脏读不可重复读**幻读 , **只要是多个事务并发 , 一定是存在幻读的加锁读
读未提交(READ_UNCOMMITTED) **允许一个事务可以看到其他事务未提交的修改,**这种隔离级别一般都是理论上的,大多数的数据库隔离级别都是二档起步不加锁
读已提交(READ_COMMITTED) **允许一个事务只能看到其他事务已经提交的数据,未提交的修改是不可见的。**这种隔离级别是比较真实的数据,每一次读到的数据是绝对的真实 (Oracle默认级别)不加锁
可重复读(REPEATABLE_READ) **确保如果在一个事务中执行两次相同的 SELECT 语句,都能得到相同的结果,不管其他事务是否提交这些修改。**永远读取的都是刚开启事务时的数据(MySql默认级别)不加锁
序列化(SERIALIZABLE)**将一个事务与其他事务完全地隔离。这是最高隔离级别,**每一次读取到的数据都是最真实的,解决了所有的问题 , 但是事务排队执行不能并发 , 效率最低。加锁

设置服务器缺省隔离级别

A教室和B教室中间有一道墙,这道墙可以很厚,也可以很薄。这就是事务的隔离级别。这道墙越厚,表示隔离级别就越高。

通过修改配置文件设置

可以在 my.ini 文件中使用 transaction-isolation 选项来设置服务器的缺省事务隔离级别。

#该选项值可以是:READ-UNCOMMITTED , READ-COMMITTED , REPEATABLE-READ , SERIALIZABLE
[mysqld]
#设置隔离级别 , 如果没有设置 , 默认是REPEATABLE-READ
transaction-isolation = READ-COMMITTED

通过命令在运行的服务器中动态设置隔离级别

  • 设置完隔离级别后需要退出MYSQL服务重新进入
--其中的<isolation-level>可以是:READ UNCOMMITTED , READ COMMITTED , REPEATABLE READ , SERIALIZABLE
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL <isolation-level>

事务隔离级别的作用范围分为两种

  • 全局级(GLOBAL):对所有的会话有效
  • 会话级(SESSION):只对当前的会话有效 , 默认设置的是当前
--设置会话级隔离级别为 READ COMMITTED 
mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED--设置会话级隔离级别为 READ COMMITTED 
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED--设置全局级隔离级别为 READ COMMITTED :
mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED

查看隔离级别

为了查看当前隔离级别,可访问服务器变量 tx_isolation(默认保存保存着当前的会话隔离级别)

--查看会话级的当前隔离级别
mysql> SELECT @@tx_isolation;
--查看会话级的当前隔离级别:
mysql> SELECT @@session.tx_isolation;
--查看全局级的当前隔离级别:
mysql> SELECT @@global.tx_isolation;

验证四种隔离界别

验证:read uncommited

事务A事务B
s1>use bjpowernode;s2>set global transaction isolation level read uncommitted;
s1>create table tx ( id int(11),num int (10));s2>use bjpowernode;
s1>start transaction;s2>start transaction;
s2>select * from tx;(空表)
s1>insert into tx values (1,10);
s2>select * from tx;(读取到数据)
s1>rollback;
s2>select * from tx;

验证:read commited

事务A事务B
s1>use bjpowernodes2> set global transaction isolation level read committed;
s1>start transaction;s2>use bjpowernode;
s2>start transaction;
s2>select * from tx;(空表)
s1>insert into tx values (1,10);
s2>select * from tx;(空表)
s1>commit;
s2>select * from tx;(读取到数据)

验证:repeatable read

事务A事务B
s1>use bjpowernodes2>set global transaction isolation level repeatable read;
s1>start transaction;s2>use bjpowernode;
s2>start transaction;
s2>select * from tx;(原先的数据)
s1>insert into tx values (1,10);
s1>commit;
s2>select * from tx;(原先的数据)

验证:serializable

事务A事务B
s1>use bjpowernodes2>set global transaction isolation level serializable;
s1>start transaction;s2>use bjpowernode;
select * from tx;s2>start transaction;
s1>insert into tx values (1,10);
s2>select * from tx;(不能访问tx表)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值