MySQL中的事务

Wesley13
• 阅读 615

MySQL中的事务

为什么需要事务

现在的软件基本上都是多用户、多程序、多线程的,对同一个表可能同时有很多人在用,为保持数据的一致性,所以提出了事务的概念。

一个事务一般包含多个操作,这些操作必须当成一个整体来执行,要么都成功,要么都失败,不允许部分成功和部分失败。假如要从A的账户给B的账户转账1000元,那么A的账户减少1000元,B的账户就要增加1000元,这两个update语句必须作为一个整体来执行,不然可能会导致A的账户扣钱了,但是B的账户没有加钱这种情况,这样就会导致数据不一致。

什么存储引擎支持事务

查看数据库中的哪些存储引擎支持事务?只有InnoDB支持事务。

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| FEDERATED          | YES     | Federated MySQL storage engine                                 | NO           | NO   | NO         |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+

查看mysql当前默认的存储引擎?

mysql> show variables like '%storage_engine%';
+----------------------------------+--------+
| Variable_name                    | Value  |
+----------------------------------+--------+
| default_storage_engine           | InnoDB |
| default_tmp_storage_engine       | InnoDB |
| disabled_storage_engines         |        |
| internal_tmp_disk_storage_engine | InnoDB |
+----------------------------------+--------+

查看某张表的存储引擎?

mysql> show create table emp;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| emp   | CREATE TABLE `emp` (
  `empno` int(4) NOT NULL,
  `ename` varchar(10) DEFAULT NULL,
  `job` varchar(9) DEFAULT NULL,
  `mgr` int(4) DEFAULT NULL,
  `hiredate` date DEFAULT NULL,
  `sal` float(7,2) DEFAULT NULL,
  `comm` float(7,2) DEFAULT NULL,
  `deptno` int(2) DEFAULT NULL,
  PRIMARY KEY (`empno`),
  KEY `fk_deptno` (`deptno`),
  CONSTRAINT `fk_deptno` FOREIGN KEY (`deptno`) REFERENCES `dept` (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

修改表的存储引擎?

mysql> alter table testmyisam engine=innodb;

事务的特性

事务应该具有4个特性:

  • 原子性

  • 一致性

  • 隔离性

  • 持久性

这四个特性通常称为ACID特性。

原子性

原子性(Atomicity):一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败,对于一个事务来说,不可能只执行其中的一部分操作。

例如上面的转账例子中,A的账户减少1000元和B的账户增加1000元这两个操作要么全部成功,要么全部失败,不能出现A的账户扣钱了,但是B的账户没有加钱这种情况。

一致性

一致性(Consistency):指事务将数据库从一种一致性转换到另外一种一致性状态,在事务开始之前和事务结束之后数据库中数据的完整性没有被破坏。

例如上面的转账例子中,A的账户减少了1000元,那么B的账户就要增加1000元,不能出现B的账户增加1500的情况,一致性与原子性是密切相关的。

持久性

持久性(Durability)也称永久性(permanence),指一个事务一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的修改数据也不会丢失。

隔离性

隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

事务的隔离级别:

事务隔离级别

脏读

不可重复读

幻读

读未提交

不可重复读

可重复读

串行化

未提交读

未提交读(READ UNCOMMITED)也称为读未提交:事务中的修改,即使没有提交,对其它事务也是可见的。

脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。

mysql的默认隔离级别为REPEATABLE-READ,可以使用以下命令查看:

mysql> show variables like '%tx_isolation%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+

脏读的演示:

session1

session2

set session transaction isolation level read uncommitted;

set session transaction isolation level read uncommitted;

begin;

update account set balance=balance-50 where id=1;

select balance from account where id=1; – 950

rollback;

select balance from account where id=1; – 1000

session2中读取到了session1中已经修改但是还没提交的数据,这就是脏读。

已提交读

已提交读 (READ COMMITED):一个事务只能读取已经提交的事务所做的修改。换句话说,一个事务所做的修改在提交之前对其它事务是不可见的。

不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次读取同一数据时结果不一致。

不可重复读的演示:

session1

session2

set session transaction isolation level read committed;

set session transaction isolation level read committed;

begin;

begin;

update account set balance=balance-50 where id=1;

select balance from account where id=1; – 1000

commit;

select balance from account where id=1; – 950

可重复读

可重复读(REPEATABLE READ):保证在同一个事务中多次读取同样数据的结果是一样的。

幻读:事务A将数据库中所有数据都删除的时候,但是事务B就在这个时候新插入了一条记录,当事务A删除结束后发现还有一条数据,就好像发生了幻觉一样。这就叫幻读。

在mysql中无法演示幻读,因为mysql的隔离级别REPEATABLE READ使用间隙锁已经解决了幻读。

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

串行化

串行化(SERIALIZABLE):强制让事务串行执行,就是把表锁住。

串行化的演示:

session1

session2

set session transaction isolation level serializable;

set session transaction isolation level serializable;

begin;

begin;

select count(*) from account; – 1

select count(*) from account; --1

insert into account values(0, 500); – 阻塞

commit;

插入成功

总结:

  • 事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会存在间隙锁间、行锁、页锁的问题,从而锁住一些行;如果没有索引,更新数据时会锁住整张表。

  • 事务隔离级别为串行化时,读写数据都会锁住整张表。

  • 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。

事务的语法

开启事务

  • begin
  • start transaction
  • begin work

事务回滚

  • rollback

事务提交

  • commit

还原点

  • savepoint

    mysql> show variables like '%autocommit%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ mysql> create table test_demo(a int, b int, c int); mysql> set autocommit=0; mysql> insert into test_demo values(5,5,5); mysql> savepoint s1; mysql> insert into test_demo values(6,6,6); mysql> savepoint s2; mysql> insert into test_demo values(7,7,7); mysql> savepoint s3; mysql> select * from test_demo; +------+------+------+ | a | b | c | +------+------+------+ | 5 | 5 | 5 | | 6 | 6 | 6 | | 7 | 7 | 7 | +------+------+------+ mysql> rollback to savepoint s2; mysql> select * from test_demo; +------+------+------+ | a | b | c | +------+------+------+ | 5 | 5 | 5 | | 6 | 6 | 6 | +------+------+------+ mysql> rollback;

更多精彩内容关注本人公众号:架构师升级之路
MySQL中的事务

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这