MySQL数据库——事务基础

目录

 

什么是事务?

为什么要有事务?

使用命令行演示事务

数据准备

查看autocommit变量值

关闭autocommit自动提交

开启事务

执行sql语句

执行提交或者回滚

关于mysql和oracle数据库的提交

事务的四大特性

原子性

一致性

隔离性

持久性

事务的安全隐患

安全隐患分类

读问题

脏读

不可重复读

幻读

事务四大隔离级别

Read uncommitted 读未提交

Read committed 读已提交

Repeatable read 可重复读

Serializable 可串行化

查询和修改事务隔离级别

查询事务的隔离级别

改变连接的隔离级别


什么是事务?

事务(Transaction)其实指的一组操作,里面包含许多个单一的逻辑。只要有一个逻辑没有执行成功,那么都算失败。 所有的数据都回归到最初的状态(回滚)

为什么要有事务?

为了确保逻辑的成功,典型例子:银行转账

将一笔钱从A->B;:一是从A账户中减去对数据库中的操作主要有两个步骤这笔钱;二是把B账户中的钱增加一笔。其实这两个步骤操作就是一个逻辑单元,就是一个操作集合,就是一个事务。这就要求两个步骤操作同步执行,要么它们都操作成功,要么都操作失败。如果一个操作失败,整个事务也就失败了,并且已经执行的操作都会被撤消,也就是回滚到先前账户不变动的状态,如果是A账户扣钱了,B账户却没增加钱,显得很不合理

使用命令行演示事务

数据准备

-- 创建数据表
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000);

 

查看autocommit变量值

首先我们要知道MySQL是自动提交事务的,可以查一下有关于commit的变量,sql语句如下:

show variables like'%commit%';  这个语句不止在命令行能执行,在mysql客户端也能执行

当执行这条语句后,如下图所示

autocommit属性值等于ON,证明是自动提交是打开的

关闭autocommit自动提交

autocommit属性为on,自动提交是开启的状态,这样你每执行一条语句就会提交一次事务,如果我们想演示事务,可先暂时关闭

运行下列sql语句:

SET autocommit = off;

再次查询:

SHOW VARIABLES LIKE'%commit%'; 

开启事务

执行语句:START TRANSACTION;

Mysql默认都是每执行一条DML(增删改)语句,会自动提交一次事务,但是当我们开启事务的时候,就会变成手动提交,如果我们后面没有执行提交commit操作,那么在此次事务之后执行的SQL只是在这个窗口的临时数据变化,并不是持久化到硬盘的变化,再打开另一个窗口的时候查询数据,数据是不生效的

执行sql语句

无论执行什么sql,这里会被当做是事务中一个单一的逻辑

例如:UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';

UPDATE account SET balance = balance - 500 WHERE NAME = 'lisi';

这里就是两个单一的逻辑

执行提交或者回滚

执行sql:commit;或者 rollback;

关闭了自动提交之后事务的控制就掌握在你自己手里了,而不是原先的写一条语句执行,就自动提交完成了一次事务,现在是只要你每执行commit;或者 rollback;,这个事务就不会结束,数据就一直在内存中,不会进入硬盘中

所以当执行了上述操作后,不执行commit命令数据不会生效

关于mysql和oracle数据库的提交

Mysql是自动提交的,一条DML(增删改)语句会自动提交一次事务

Oracle 数据库默认是手动提交事务,需要执行commit,通常我们在客户端都有个按钮commit

查看事务的默认提交方式:SELECT @@autocommit; -- 1 代表自动提交  0 代表手动提交

修改事务提交的两种方式: set @@autocommit = 0;或者SET autocommit = off;(设置成手动提交)

查看事务提交方式:show variables like'%commit%';

事务的四大特性

原子性

> 指的是 事务中包含的逻辑,不可分割,是最小的操作单位。

例如,转账,A账户减少,B账户增加。虽然是两条 DML语句,但是被当做是一个整体,一次事务。两条语句只能同时成功或者同时失败

一致性

> 指的是 事务执行前后。数据完整性(总数不变)

(简单解释就是账户A和B,要么都是转账前的状态,要么都是转账后的状态。不能A账户的钱减少了但是B账户的钱没有增加,事务执行前和执行后,数据的总和相同,他们钱的总数是不会变的)

隔离性

> 指的是 事务在执行期间不应该受到其他事务的影响

事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立

持久性

> 指的是 事务执行成功,那么数据应该持久保存到磁盘上。

事务提交成功后,数据修改永远生效 

事务的安全隐患

在考虑事务的隔离级别之前,需要认识到如果不考虑事务的隔离性,会发生的异常情况

安全隐患分类

总共分为两类:读和写的问题

读问题

脏读

简单解释:指的是一个事务读到另外一个事务还未提交的数据,读到的是数据库内存中的数据,而并非是真正磁盘上的数据

不可重复读

在同一个事务内,多次读同一个数据时,发现该数据已经被另一个已经提交的事务修改。(在一个事务内两次读到的数据时是不一样的。)

幻读

一个事务根据相同的查询条件,重新执行查询,返回的记录中包含与前一次执行查询返回的记录不同的行。(一个事务读到了另一个事务插入的数据 ,造成前后查询结果不一致 。)

事务四大隔离级别

数据库事务的隔离级别有4个,由低到高依次为Read uncommitted (读未提交)、Read committed(读已提交) 、Repeatable read (重复读)、Serializable (可串行化),这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题

√: 可能出现    ×: 不会出现

 

脏读

不可重复读

幻读

Read uncommitted

Read committed

×

Repeatable read

×

×

Serializable

×

×

×

从上面的表格我们可以看出

读未提交

> 引发问题: 脏读 不可重复读 幻读

读已提交

> 解决: 脏读 , 引发: 不可重复读 幻读

可重复读

> 解决: 脏读 、 不可重复读 , 未解决: 幻读

可串行化

> 解决: 脏读、 不可重复读 、 幻读。

注意:我们讨论隔离级别的场景,主要是在多个事务并发的情况下,因此,接下来的讲解都围绕事务并发。

Read uncommitted 读未提交

公司发工资了,领导把5000元打到singo的账号上,但是该事务并未提交,而singo正好去查看账户,发现工资已经到账,是5000元整,非常高兴。可是不幸的是,领导发现发给singo的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后singo实际的工资只有 2000元,singo空欢喜一场。

出现上述情况,即我们所说的脏读 ,两个并发的事务,“事务A:领导给singo发工资”、“事务B:singo查询工资账户”,事务B读取了事务A尚未提交的数据。

当隔离级别设置为Read uncommitted 时,就可能出现脏读,如何避免脏读,请看下一个隔离级别。

Read committed 读已提交

singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在 singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为何出现上述情况,即我们所说的不可重复读 ,两个并发的事务,“事务A:singo消费”、“事务B:singo的老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。当隔离级别设置为Read committed 时,避免了脏读,但是可能会造成不可重复读。
大多数数据库的默认级别就是Read committed,比如Sql Server , Oracle。如何解决不可重复读这一问题,请看下一个隔离级别。

Repeatable read 可重复读

当隔离级别设置为Repeatable read 时,可以避免不可重复读。当singo拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),singo的老婆就不可能对该记录进行修改,也就是singo的老婆不能在此时转账。
虽然Repeatable read避免了不可重复读,但还有可能出现幻读 。

singo的老婆工作在银行部门,她时常通过银行内部系统查看singo的信用卡消费记录。有一天,她正在查询到singo当月信用卡的总消费金额为80元,而singo此时正好在外面胡吃海塞后在收银台买单,消费1000元,即新增了一条1000元的消费记录,并提交了事务,随后singo的老婆将singo当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,singo的老婆很诧异,以为出现了幻觉,幻读就这样产生了。

注:Mysql的默认隔离级别就是Repeatable read。

Serializable 可串行化

Serializable 是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。如果有一个连接的隔离级别设置为了串行化 ,那么谁先打开了事务, 谁就有了先执行的权利,谁后打开事务,谁就只能等着,等前面的那个事务,提交或者回滚后,才能执行。但是这种隔离级别一般比较少用。容易造成性能上的问题。效率比较低。类似多线程变成了单线程,必须逐个执行

注意:隔离级别从小到大安全性越来越高,但是效率越来越低

查询和修改事务隔离级别

查询事务的隔离级别

select @@tx_isolation(默认级别是可重复读)

改变连接的隔离级别

从默认的重复读到读未提交:set session transaction isolation level read uncommitted;

完整的SET TRANSACTION语句: SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

对上面的语句进行解释:

注意:默认的行为(不带session和global)是为下一个(未开始)事务设置隔离级别。如果你使用GLOBAL关键字,语句在全局对从那点开始创建的接下去所有新连接设置默认事务级别。使用SESSION 关键字为将来在当前连接上执行的事务设置默认事务级别,如果是SESSION则只要关闭当前连接,创建新连接他的隔离级别又会变回REPEATABLE READ可重复读

此时再次查询当前连接的事务级别,就变成了读未提交

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 确实,MySQL的varchar类型在InnoDB存储引擎中的存储结构比较复杂。在InnoDB中,每个记录都被存储为一个B+树节点,每个节点都有一个固定大小的页,通常为16KB。 当一个varchar类型的列被插入到InnoDB表中时,它会被拆分成两个部分:一个是实际的数据,另一个是长度信息。长度信息会被存储在记录头中,而实际的数据会被存储在记录的数据页中。 在InnoDB中,如果一个varchar类型的列的长度小于等于768个字节,那么它会被存储在记录的数据页中。如果一个varchar类型的列的长度超过了768个字节,那么它会被存储在单独的页中,并且在记录中只存储一个指向这个页的指针。 此外,由于InnoDB使用了行级锁定,每个记录都需要存储一个事务ID,用于实现MVCC(多版本并发控制)。因此,在InnoDB中,每个记录头还需要存储一个6字节的事务ID和一个2字节的回滚指针。 综上所述,当使用varchar类型时,需要注意其实际数据的长度和存储引擎的存储结构,以便更好地设计表结构和查询语句。 ### 回答2: MySQL的varchar存储结构确实是相当深奥的。在InnoDB存储引擎中,varchar类型的数据存储在表的记录中,其存储结构会影响数据写入、存储空间占用和查询性能。 首先,varchar类型的数据在记录中是以变长字符串的形式进行存储的。这意味着,varchar字段占用的存储空间与其实际存储的数据长度相关,而不是固定的。相比之下,固定长度的数据类型(如char)在存储时会占用固定的存储空间,无论实际数据的长度是多少。 其次,varchar类型的数据在记录中的存储格式是由一个表示长度的字节和真实字符串数据构成的。这个长度字段用于指示存储的实际数据的长度,使得数据库可以根据需要动态地分配存储空间,从而节省了存储空间。 此外,在InnoDB存储引擎中,varchar字段的数据存储在页内部的某个位置,而不是直接存储在页上。这是由于InnoDB采用了B+树的数据结构来组织数据,为了节省存储空间和提高数据访问效率,varchar字段的数据会被存储在叶子节点中。这样一来,在查询时可以更快地遍历和定位数据,提高查询性能。 综上所述,MySQL的varchar存储结构的深度体现在其变长存储方式、长度字段和数据存储位置等方面。了解和理解这些存储结构对于正确使用varchar类型的字段、优化存储空间和提高查询性能都是非常重要的。 ### 回答3: MySQL的varchar存储结构在InnoDB引擎中确实是一个很深入的话题。InnoDB引擎是MySQL的默认引擎,它采用了B+树索引来存储数据。在InnoDB的记录存储结构中,varchar类型字段经过了一系列处理。 首先,InnoDB将每个记录分为固定长度部分和变长长度部分。varchar字段属于变长长度部分。对于varchar字段,MySQL会额外存储一个指针,指向数据存储区域。 其次,在实际存储varchar字段值时,InnoDB会使用两种方式。对于较短的varchar字段值,会直接将其存储在记录的数据域中。这样做的好处是可以减少额外的存储开销。 而对于较长的varchar字段值,InnoDB会将其存储在一个称为“Overflow Page”的额外存储空间中。Overflow Page的指针存储在记录的数据域中。Overflow Page与主记录有一个单独的物理连接。 另外,需要注意的是,在InnoDB中,varchar字段的长度是可变的,存储的最大长度由定义时的最大长度决定。这与char字段是不同的,char字段的长度是固定的。 总之,MySQL的varchar存储结构在InnoDB引擎中是相对复杂的。它采用了不同的存储方式来处理不同长度的字段值,既保证了数据的存储效率,又满足了灵活性的要求。对于开发人员来说,了解varchar存储结构对于正确使用和优化数据库非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值