Mysql事务
避免事务,会占用内存
事务是啥?
简而言之:事务 - 就是保护多条执行的sql语句,要么全部成功,要么全部失败
比如:转账就是一个事务:从一个用户将资金转出,再将资金转入到另一个用户,这两个操作看做一体
事务是在哪个层实现的?
事务是引擎层实现的,mysql是多引擎的系统,不是所有引擎都支持事务的,比如MySQL原生的MyISAM就不支持事务,这也是MyIASM被InnoDB取代的原因之一。
事务ACID特性
- 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。(简单的案例就是银行转账,A转账给B,不会发生A转账成功,B没收到钱,只可能是A转账失败)
- 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
事务的四种隔离级别和默认级别
mysql查看隔离级别
select @@tx_isolation;
隔离级别
1.读未提交
2.读以提交
3.可重复读
4.串行化
set tx_isolation='read-uncommitted';
set tx_isolation='read-committed';
set tx_isolation='repeatable-read';
set tx_isolation='serializable';
其实还有一种就是无事务,当我没说
数据库默认的级别是可重复读
很久以前主从复制,是基于binlog的,在Mysql在5.0这个版本以前,binlog只支持STATEMENT这种格式!而这种格式在读已提交(Read Commited)这个隔离级别下主从复制是有bug的(主从不一致),因此Mysql将可重复读(Repeatable Read)作为默认的隔离级别!
解决方案其中一种就是就是提高隔离级别到可重复读,所以默认就设为可重复读
项目中的隔离级别
设置
#查看隔离级别
SELECT @@tx_isolation;
#配置文件修改隔离级别为读提交,之后在重启服务
[mysqld]
transaction-isolation=Read-Committed
项目中
项目中我们一般都是使用读已提交
这个隔离级别,我们知道读已提交会有不可重复读和幻读的问题,那我们为啥选择读以提交
为啥不用,读提交和串行化
一个逻辑上就说不过去,还有一个性能不佳
对比读提交(RC)和可重复读(RR)为何选择读提交
缘由一:在RR隔离级别下,存在间隙锁,导致出现死锁的几率比RC大的多!
缘由二:在RR隔离级别下,条件列未命中索引会锁表!而在RC隔离级别下,只锁行
缘由三:在RC隔离级别下,半一致性读(semi-consistent)特性增加了update操作的并发性!
事务隔离级别
原理:
事务的隔离性其实是由锁来实现的
读未提交(脏读):
允许一个事务读取另外一个事务没有提交的数据。
读提交(解决脏读可能出现的问题):
指一个事务只能读取到另外一个事务已经提交的数据。
可重复读:(解决不可重复读可能出现的问题):
当数据在另一事务操作中时,无法读取,只有当那个事务完成了,才能读取到数据。
串行化(解决幻读):
sql按顺序执行,不会出现问题,但是效率低。
隔离级别总结
脏读:
一个事务获取到另一个事务还没有提交的数据修改,这样的操作是很危险的,因为没有提交的修改是可以回滚的
不可重读:
一个事务内查询数据,查询相同的数据,在后面的查询会突然变化
可重复读:
当一个事务对某个记录进行了修改,那么另一个事务查询得到数据是没有修改之前的数据(快照),只有当两个事务都提交完之后才会读取修改后的数据
幻读:(假设本来有两条数据)
当一个事务添加了一条记录(3),并且提交后,另一个事务执行,查询只有2条数据(可重复读),但是如果这个时候进行一个全表更新更改数据的操作之后,在查询就有3条数据,这就是幻读
串行化:(没有并发能力)
串行化,就是事务一个一个执行,一个事务在操作一个表,就会给这个表加锁,别的事务无法读取和操作这个表,直到事务一提交
MYSQL 事务处理主要有两种方法:
1、用 BEGIN, ROLLBACK, COMMIT来实现
- BEGIN 开始一个事务
- ROLLBACK 事务回滚
- COMMIT 事务确认
2、直接用 SET 来改变 MySQL 的自动提交模式:
- SET AUTOCOMMIT=0 禁止自动提交
- SET AUTOCOMMIT=1 开启自动提交
案例
# mysql中事务的执行
create table bank(
id int,
name varchar(16),
money decimal(65, 2)
);
insert into bank values(1, 'Tom', 10), (2, "Bob", 10);
# 假设出现以下执行情况
# 没有事务支持情况下,Tom的钱就丢了
update bank set money=money-1 where name='Tom';
update bank set money=money+1 where name='ruakei';
# 将两条sql看做事务处理
# 开启事务
begin;
update bank set money=money-1 where name='Tom';
update bank set money=money+1 where name='ruakei';
# 确认无误,提交事务
commit;
# 确认有误,回滚
rollback;
参考博客:
https://blog.csdn.net/DorAction/article/details/87971378