事务
1、概念
**数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作; 事务是一组不可再分割的操作集合(工作逻辑单元);**是什么
**update user_account set balance = balance - 1000 where userID = 3;
update user_account set balance = balance +1000 where userID = 1;–****场景(转账)
mysql中如何开启事务:
begin / start transaction – **手工
**commit / rollback – **事务提交或回滚
set session autocommit = on/off; – **设定事务是否自动开启
**JDBC 编程:
connection.setAutoCommit(boolean);–根据参数开启事务
**Spring 事务AOP编程: **
**expression=execution(com.gpedu.dao..(…))–**先开启再进行提交
2、事务特性ACID
原子性(Atomicity)
最小的工作单元,整个工作单元要么一起提交成功,要么全部失败回滚
一致性(Consistency)
事务中操作的数据及状态改变是一致的,即写入资料的结果必须完全符合预设的规则,
不会因为出现系统意外等原因导致状态的不一致
隔离性(Isolation)
一个事务所操作的数据在提交之前,对其他事务的可见性设定(一般设定为不可见)
持久性(Durability)
事务所做的修改就会永久保存,不会因为系统意外导致数据的丢失
3、事务并发的问题
脏读,不可重复读,幻读。
4、事务隔离级别四种
**Read Uncommitted(未提交读) --**未解决并发问题
****Read Committed(提交读) --**解决脏读问题
****Repeatable Read (可重复读) --**解决不可重复读问题
****Serializable(串行化) --**解决所有问题
锁
1、是什么
锁是用于管理不同事务对共享资源的并发访问。
2、有什么
行锁和表锁–InnoDB支持,表锁是将所有的行锁住。
行锁锁住的是索引
InnoDB的行锁是通过给索引加锁来实现的。
只有通过索引条件进行数据检索,InnoDB才使用行级锁,否则,InnoDB 将使用表锁(锁住索引的所有记录)
表锁:lock tables xx read/write;
3、行锁和表锁的区别
锁定粒度:表锁 > 行锁
加锁效率:表锁 > 行锁
冲突概率:表锁 > 行锁
并发性能:表锁 < 行锁
4、锁类型
4.1共享锁(S)
共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改;
select * from users WHERE id=1 LOCK IN SHARE MODE; commit/rollback
4.2排他锁(X)
只有该获取了排他锁的事务是可以对数据行进行读取和修改,(其他事务要读取数据可来自于快照)Undo日志。
delete / update / insert 默认加上X锁
SELECT * FROM table_name WHERE … FOR UPDATE commit/rollback
4.3意向共享锁(IS)
4.4意向排他锁(IX)
意向锁**(IS****、IX)是InnoDB数据操作之前自动加的,不需要用户干预
意义:
当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速返回该表不能 启用表锁
4.5自增锁(AUTO-INC)
针对自增列自增长的一个特殊的表级别锁
show variables like ‘innodb_autoinc_lock_mode’;
默认取值1,代表连续,事务未提交ID永久丢失
5、行锁的算法
5.1临建锁(Next-key)–是InnoDB默认的行锁算法–解决幻读
当sql执行按照索引进行数据的检索时,查询条件为范围查找(between and、<、>等)并有数 据命中则此时SQL语句加上的锁为Next-key locks,锁住索引的记录+区间(左开右闭)。
5.2间隙锁(Gap)–只在**RR(可重复读)**事务隔离级别存在
当sql执行按照索引进行数据的检索时,查询条件的数据不存在,这时SQL语句加上的锁即为Gap locks,锁住索引不存在的区间(左开右开)。
5.3记录锁(Record)
当sql执行按照唯一性(Primary key、Unique key)索引进行数据的检索时,查询条件等值匹 配且查询的数据是存在,这时SQL语句加上的锁即为记录锁Record locks,锁住具体的索引项。
6、利用锁解决事务并发问题
6.1脏读
6.2不可重复读
6.3幻读
7、死锁
![屏幕快照 2019-05-25 上午11.05.58.png](https://cdn.nlark.com/yuque/0/2019/png/143030/1558753563144-c022a233-363e-431b-a2b2-6e27a645633e.png#align=left&display=inline&height=200&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-05-25%20%E4%B8%8A%E5%8D%8811.05.58.png&originHeight=569&originWidth=951&size=130399&status=done&width=335)
避免死锁
**
MVCC
1、是什么
Multiversion concurrency control (多版本并发控制)
并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写操作的堵塞,从而引发读操作的并发问题。
2、MVCC流程
2.1删除
![屏幕快照 2019-05-25 上午11.15.59.png](https://cdn.nlark.com/yuque/0/2019/png/143030/1558754165455-4237a1c1-2ec7-4984-8bbb-4df4596970cd.png#align=left&display=inline&height=272&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-05-25%20%E4%B8%8A%E5%8D%8811.15.59.png&originHeight=851&originWidth=1401&size=317984&status=done&width=448)<br /> 表中有隐藏列数据行的版本号、删除版本号等等。<br />**开启一个事务将拿到系统的事务ID,删除数据行时将此行的删除版本号填入事务ID。**<br />**
2.2修改
当前事务ID为33
当修改数据行时,先将此行数据复制一行,数据行的版本号为33,元数据行删除版本号为33。
**
2.3查询
查数据规则【1&&2–并且关系】
1、数据行的版本号<=当前事务ID
–确保查询出事务之前的数据和自己插入或修改过的数据
2、删除版本号要么为NULL,要么大于当前事务ID
–确保查询****比当前事务ID大的事务正在修改或删除数据的之前数据
注意:【1&&2–并且关系】
**
解决【先事务读后事务写再读】的并发引起的脏读
但【先事务写后事务读】然并卵–脏读问题并没有解决——>用一下Undo日志解决的。
3、Undo log
是什么
事务开始之前,在操作任何数据之前**,**首先将需操作的数据备份到一个地方。
干了什么
UndoLog是为了实现事务的原子性而出现的产物
在事务处理过程中出现了错误或ROLLBACDK语句,mysql利用Undo Log中的备份将数据恢复到事务开始之前的状态。
UndoLog在Mysql innodb存储引擎中用来实现多版本并发控制
事务未提交之前,Undo保存了未提交之前的版本数据,作为数据旧版本快照供
其他并发事务进行快照读-----哈哈哈!解决的【先事务写后事务读】产生脏读问题。
当前读:
读取的最新版本的数据,所有通过锁机制来读取的数据都是当前读。
快照读:不带锁的select是快照读。innodb快照读,数据的读取将由 **cache(原本数据) + undo(事务修改过的数据) **两部分组成。
4、Redo log
是什么
事务中操作的数据**,将最新的数据备份到Redo log。
不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo **中。具体的落盘策略可以进行配置
干了什么
RedoLog是为了实现事务的持久性而出现的产物
防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的未入磁盘数据进行持久化这一特性。
指定Redolog记录在{datadir}/ib_logfile1&ib_logfile2 可通过innodb_log_group_home_dir配置指定 目录存储。
一旦事务成功提交且数据持久化落盘之后,此时Redo log中的对应事务数据记录就失去了意义,所 以Redo log的写入是日志文件循环写入的**----这个地方不懂?
指定Redo log日志文件组中的数量 innodb_log_files_in_group 默认为2
指定Redo log每一个日志文件最大存储量innodb_log_file_size 默认48M
指定Redo log在cache/buffer中的buffer池大小innodb_log_buffer_size 默认16M
Redo buffer持久化Redo log的策略,Innodb_flush_log_at_trx_commit:----到Redo buffer到Redo Log持久化**
取值 0 每秒提交 Redo buffer --> Redo log OS cache -->flush cache to disk[可能丢失一秒内
的事务数据]
取值 1 默认值,每次事务提交执行Redo buffer --> Redo log OS cache -->flush cache to disk
[最安全,性能最差的方式]
取值 2 每次事务提交执行Redo buffer --> Redo log OS cache 再每一秒执行 ->flush cache to disk操作