事务

什么是事务

数据库事务(Database Transaction),是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。

简单的说:事务就是将一堆的SQL语句(通常是增删改操作)绑定在一起执行,要么都执行成功,要么都执行失败,即都执行成功才算成功,否则就会恢复到这堆SQL执行之前的状态。

事务的四大特性

事务的四大特性(ACID)是:

(1)原子性(Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。

(2)一致性(Consistency):事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账户金额之和在事务前后应该是保持不变的。
(3)隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。也就是说,在事中务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。例如:在A事务中,查看另一B事务(正在修改张三的账户金额)中张三的账户金额,要查看到B事务之前的张三的账户金额,要么查看到B事务之后张三的账户金额。
(4)持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
MySQL中的事务

在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。因为底层在执行SQL语句之前会自动开启事务,在SQL语句执行完后,会立即结束事务!

如果需要在一个事务中包含多条SQL语句,那么需要手动开启事务和结束事务。

  • 开启事务:start transaction;

  • 结束事务:commit(提交事务)或 rollback(回滚事务)。

在执行SQL语句之前,先执行 strat transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所做出的影响会持久化到数据库中。或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤消了!
下面演示A账户给B账户转账的例子:

-- 1、创建数据库jt_db数据库(如果不存在才创建)
create database if not exists jt_db charset utf8;
use jt_db; -- 选择jt_db数据库
-- 2、在 jt_db 库中创建 acc 表(银行账户表),要求有id(主键),name(姓名),money(账户金额)
drop table if exists acc;
create table acc(
    id int primary key auto_increment,
    name varchar(50),
    money double
);
-- 3、往 acc 表中, 插入2条记录
insert into acc values(null,'A',1000);
insert into acc values(null,'B',1000);
-- 查询acc表中的所有记录
select * from acc;

下面分别演示事务开启及执行一系列SQL之后,回滚事务、提交事务及中断操作的效果。
rollback(回滚事务)

-- 查询acc账户表中A和B的金额
select * from acc;
-- 开启事务
start transaction;
-- 开始转账,A账户减去100元
update acc set money=money-100 where name='A';
-- 查询acc账户表中A和B的金额
select * from acc;
-- B账户增加100元
update acc set money=money+100 where name='B';
-- 查询acc账户表中A和B的金额
select * from acc;
-- 回滚事务
rollback;
-- 再次查询acc账户表中A和B的金额
select * from acc;

commit(提交事务):将上面的操作再做一次,最后将rollback替换为commit,即提交事务
中断操作:将上面的操作再做一次,最后将rollback替换为quit,即中断操作

事务并发读问题

多个事务对相同的数据同时进行操作,这叫做事务并发。

在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,破坏数据的完整性等。这些问题中,其中有三类是读问题,分别是:脏读、不可重复读、幻读。

(1)脏读(dirty read):在一个事务中,读取到另一个事务未提交更新的数据,即读取到了脏数据;

例如:在一个事务中,A给B转账100元但未提交事务,在另一事务中B查询账户金额,查询到了A未提交更新的数据,我们称之为脏读。
提示:需要将数据库的事务隔离级别设置为最低,才能够看到脏读现象
事务1:开启事务; A - 100 = 900; B + 100 = 1100; (没有提交事务)
事务2:开启事务; 查询B账户的金额 1100, 这个过程叫做脏读, 1100就是一个脏数据
(2)不可重复读(unrepeatable read):对同一记录的两次读取结果不一致,因为在两次查询期间,有另一事务对该记录做了修改(是针对修改操作)

例如:在事务1中,前后两次查询A账户的金额,在两次查询之间,另一事物2对A账户的金额做了修改(并且也提交了事务),此种情况可能会导致事务1中,前后两次查询的结果不一致。这就是不可重复读。
事务1:开启事务—
第一次读取A账户的金额:1000
第二次读取A账户的金额:900
事务2:开启事务—
A账户 - 100 = 900;
提交事务—
(3)幻读(虚读)(phantom read):对同一张表的两次查询结果不一致,因为在两次查询期间,有另一事务进行了插入或者是删除操作(是针对插入或删除操作);
事务1:开启事务—
select * from acc where id=3;//不存在id为3的记录
insert into acc value(3,‘C’,2000);
select * from acc where id=3;//存在id为3的记录
事务2:开启事务—
insert into acc value(3,‘C’,2000);
提交事务—

事务隔离级别

事务隔离级别分四个等级,在相同数据环境下,对数据执行相同的操作,设置不同的隔离级别,可能导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力也是不同的。

set tx_isolation='read-uncommitted';

1、READ UNCOMMITTED(读未提交数据)**

安全性最差,可能出现任何事务并发问题(比如脏读、不可以重复读、幻读等)

但性能最好(不使用!!)

2、READ COMMITTED(读已提交数据)(Oracle默认)

安全性较差

性能较好

可以防止脏读,但不能防止不可重复读,也不能防止幻读;

3、REPEATABLE READ(可重复读)(MySQL默认)

安全性较高

性能较差

可以防止脏读不可重复读,但不能防止幻读问题;

4、SERIALIZABLE(串行化)

安全性最高,不会出现任何并发问题,因为它对同一数据的访问是串行的,非并发访问;

性能最差;(不使用!!)

MySQL的默认隔离级别为REPEATABLE READ,即可以防止脏读和不可重复读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值