SQLyog基本操作(八)-事务
6 事务
定义:数据库事务是构成单一逻辑工作单元的操作集合。
一个典型的数据库事务如下:
BEGIN TRANSACTION //事务开始
SQL1
SQL2
COMMIT/ROLLBACK //事务提交或回滚
可以理解为:将一组SQL放在一个批次中去执行
关于事务的定义有几点需要解释:
-
数据库事务可以包含一个或多个数据库操作,但这些操作构成一个逻辑上的整体。
-
构成逻辑整体的这些数据库操作,要么全部执行成功,要么全部不执行。
-
构成事务的所有操作,要么全都对数据库产生影响,要么全都不产生影响,即不管事务是否执行成功,数据库总能保持一致性状态。
-
事务的四个原则:ACID(原子性、一致性、隔离性、持久性)
参考博客
-
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作,要多都发生,要么都不发生;要么都成功,要么都失败。
针对同一个事务而言
举例:银行转账
这个过程包含两个步骤:
A:800 - 200 = 600 转出200 B:200 + 200 = 400 转入200
原子性表示,这两个步骤要么一起成功,要么一起失败,不能只发生其中一个动作。
-
一致性(Consistency)
一致性是指事务前后的数据完整性要保持一致(最终一致性、过程一致性)。
针对一个事务操作前与操作后的状态一致。
举例:银行转账
操作前A:800,B:200 操作后A:600,B:400
一致性表示事务完成后,符合逻辑运算(前后过程、最终的总钱数也都保持一致:1000)
-
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的(不可逆,被持久化到数据库中),接下来即使数据库发生故障也不应该对其产生任何影响。
表示事务结束后的数据不随着外界原因导致数据丢失。
举例:银行转账
操作前A:800,B:200 操作后A:600,B:400
-
如果在操作前(即事务还没有被提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为 A:800,B:200
-
如果在操作后(即事务已经被提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为 A:600,B:400
-
隔离性(Isolation)
事务的隔离性是指多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
针对多个用户同时操作,主要是排除其他事务对本次事务的影响。
举例:银行转账
事务一:A向B转账200
事务二:C向B转账100
两个事务同时进行,其中一个事务读取到另外一个事务还没有提交的数据,执行步骤如图所示:
隔离性用于解决以上问题。
隔离所导致的一些问题:
-
脏读
指一个事物读取了另外一个事务未提交的数据。
举例:
-
不可重复读
在一个事务内读取表中的某一行数据,多次读取结果不同(这不一定是错误,只是某些场合不对)。
举例:页面统计查询值
生成报表的时候,B有人转账进来300(B事务已经提交)
-
虚读(幻读)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取的不一样,一般是行影响。
举例:多了一行
事务流程:
-- mysql是默认开启事务自动提交的
SET autocommit=0 /* 关闭事务自动提交 */
SET autocommit=1 /* 开启事务自动提交 */
?
-- 手动处理事务,要先关闭自动提交
SET autocommit=0
?
-- 标记一个事务的开始,从这个之后的sql都在同一个事务内
START TRANSACTION
?
-- 一组事务
INSERT xx
INSERT xx
?
-- 提交:成功-->持久化,就不能再回滚了
COMMIT
?
-- 回滚:失败-->回滚(回到原来的样子),未提交时,可以回滚
ROLLBACK
?
-- 事务结束,开启自动提交
SET autocommit=1
?
-- 了解
SAVEPOINT 保存点名 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点
举例:转账业务
-- 事务案例:转账业务
-- 创建数据库
CREATE DATABASE `bank` CHARACTER SET utf8 COLLATE utf8_general_ci
-- 使用数据库
USE `bank`
?
-- 创建表
CREATE TABLE `account`(
`id` INT(4) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
?
-- 插入数据
INSERT INTO `account`(`name`,`money`) VALUES(‘A‘,10000.00),(‘B‘,20000.00)
?
-- 模拟转账:事务
SET autocommit=0; -- 关闭自动提交
START TRANSACTION -- 开始一个事务(一组事务)
-- 具体事务
UPDATE `account` SET `money`=`money`-500 WHERE `name`=‘A‘ -- A减500
UPDATE `account` SET `money`=`money`+500 WHERE `name`=‘B‘ -- B加500
COMMIT -- 成功提交事务,数据就被持久化了
ROLLBACK -- 失败回滚事务
SET autocommit=1; -- 事务结束,开启自动提交
?