事务的特性(transaction/tx)

本文详细介绍了数据库事务的概念,包括其ACID特性,以及在MySQL中的实现。通过实例展示了事务如何确保数据的一致性和完整性,特别是如何处理突发情况如断电。还探讨了事务的隔离级别,如读未提交、读已提交、可重复读和串行化,并通过案例演示了不同隔离级别下的数据可见性问题。此外,文章还提到了锁机制在事务管理中的作用,以及行锁和表锁的区别。

事务(transaction/tx)

需求:有一张银行账户表,有a用户给b用户转账.A账户钱减少,b账户钱增加.但是当a账户钱减少时,断电了,B账户并没有增加钱.

解决方案:a减少钱,但是不要立即修改数据表,b的钱增加之后,同时修改表.

事务:

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。

演示:

CREATE TABLE `account` (

  `id` int(50) NOT NULL,

  `name` varchar(50) NOT NULL,

  `money` int(255) NOT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO account VALUES(1,'张三',1000);

INSERT INTO account VALUES(2,'李四',1000);

修改a的钱

Update account set money=money-1000 where id=1;

此时退出mysql,再次进去查看b账户的钱.没有增加

1、 Mysql中的事务

mysql的存储引擎: ENGINE=InnoDB,是支持事务.

a、mysql引擎是支持事务的

b、mysql默认自动提交事务。每条语句都处在单独的事务中。

-- 查看当前数据库事务的提交方式

SHOW VARIABLES like ‘autocommit’

  • 查看当前数据库事务的提交方式

select @@autocommit; 0是手动提交,1是自动提交

  • 设置当前数据库的提交方式

set @@autocommit = 0

看到是autocommit on  开启自动提交

手动关闭: set autocommit = off   / 或者= 0

再演示:直接修改数据,在别的窗口可以查看效果,数据没有修改.需要手动处理:提交或回滚

c、手动控制事务

开启事务:start transaction | begin

提交事务:commit

回滚事务:rollback

原始数据:

CREATE TABLE `account` (

  `id` int(50) NOT NULL,

  `name` varchar(50) NOT NULL,

  `money` int(255) NOT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO account VALUES(1,'张三',1000);

INSERT INTO account VALUES(2,'李四',1000);

手动控制事务:

BEGIN;  -- 开启事务(等价START TRANSACTION)

UPDATE account SET money=money-100 WHERE `name`='张三';

COMMIT; -- 提交事务

未提交之前,假设发生错误,比如命令行关闭,电脑关机,都会自动回滚.

手动回滚:

BEGIN;  -- 开启事务

UPDATE account SET money=money-100 WHERE `name`='张三';

ROLLBACK; -- 回滚,数据不会变动

2、事务的特性(ACID)(面试题)

原子性(Atomicity):指事务的整个操作是一个整体,要么都成功,要么都失败

一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态。转账前和转账后的总金额不变。

隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

  • 讲解:一个事务A开始事务,修改a表数据,自己查询数据,已经修改
  • 另外开启一个事务B:操作同一个表-> 修改a表其他列数据,自己查看已经修改
  • 但是A事务再查表数据,并未看见B事务做出的修改.同样B事务也看不见A事务做出的修改.

持久性(Durability):指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

2、 事务的隔离级别

隔离级别:

数据库通过设置事务的隔离级别防止以上情况的发生:

1、读未提交-READ UNCOMMITTED: 赃读、不可重复读、虚读都有可能发生。

2、读已提交-READ COMMITTED: 避免赃读。不可重复读、虚读都有可能发生。(oracle默认的)

3、可重复读-REPEATABLE READ:避免赃读、不可重复读。虚读有可能发生。(mysql默认)

4、串行化-SERIALIZABLE: 避免赃读、不可重复读、虚读。

以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。

不同的隔离级别产生如下情况:

赃读:指一个事务读取了另一个事务未提交的数据。

不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同。一个事务读取到了另一个事务提交后的数据。(update)

虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。 (insert)

脏读:

对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段.

之后, 若 T2 回滚, T1读取的内容就是临时且无效的.

不可重复读:

对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段.

之后, T1再次读取同一个字段, 值就不同了.

幻读:

对于两个事物 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中

插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.

mysql中:

查看当前的事务隔离级别:SELECT @@TX_ISOLATION;

更改当前的事务隔离级别:

SET [glogal | session] TRANSACTION ISOLATION LEVEL 四个级别之一。

设置隔离级别必须在事务之前

案例演示:

   Navicat演示隔离级别效果。

锁机制

Innodb默认是行锁,但是在事务(增删改)中,没有使用到索引,那么系统会自动升级会表锁,

行锁:事务开始后,其他用户不能操作该行数据,

表锁:事务开始后,其他用户不能操作这张表

CREATE TABLE `account` (

  `id` int(50) NOT NULL,

  `name` varchar(50) NOT NULL,

  `money` int(255) NOT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO account VALUES(1,'张三',1000);

INSERT INTO account VALUES(2,'李四',1000);

-- 转账

update account set money = money - 100 where id = 1;

update account set money = money + 100 where id = 2;

-- 查看当前数据库提交方式

SHOW VARIABLES like 'autocommit'

-- 设置自动提交关闭

set autocommit = off

-- ============== 手动管理事务 ==========================

-- 开启事务

start transaction;

-- 正常sql代码

update account set money = money - 100 where id = 1;

-- 断电了

update account set money = money + 100 where id = 2;

-- 提交事务

commit;

-- 回滚事务,如果正常的sql没有正常执行完,就选择执行回滚

rollback;

-- ============== 演示隔离级别 ==========================

-- 查询隔离级别

SELECT @@TX_ISOLATION;

-- 设置隔离级别

SET global TRANSACTION ISOLATION LEVEL REPEATABLE READ

-- 事务1

start TRANSACTION;

update account set money = money - 100 where id = 1;

insert into account values(3,'王五',1000);

update account set money = money + 100 where id = 2;

commit;

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值