事务:
数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;
事务是一组不可再分割的操作集合(工作逻辑单元);
典型事务场景(转账):
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.*.*(..))
原子性(Atomicity)
最小的工作单元,整个工作单元要么一起提交成功,要么全部失败回滚
一致性(Consistency)
事务中操作的数据及状态改变是一致的,即写入资料的结果必须完全符合预设的规则,
不会因为出现系统意外等原因导致状态的不一致
隔离性(Isolation)
一个事务所操作的数据在提交之前,对其他事务的可见性设定(一般设定为不可见)
持久性(Durability)
事务所做的修改就会永久保存,不会因为系统意外导致数据的丢失
脏读
不可重复读
幻读
SQL92 ANSI/ISO标准:
http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
innodb引擎对隔离级别的支持程度
锁是用于管理不同事务对共享资源的并发访问
表锁与行锁的区别:
锁定粒度:表锁 > 行锁
加锁效率:表锁 > 行锁
冲突概率:表锁 > 行锁
并发性能:表锁 < 行锁
InnoDB存储引擎支持行锁和表锁(另类的行锁)
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html
共享锁(行锁):Shared Locks
排它锁(行锁):Exclusive Locks
意向锁共享锁(表锁):Intention Shared Locks
意向锁排它锁(表锁):Intention Exclusive Locks
行锁的算法
自增锁:AUTO-INC Locks
记录锁 Record Locks
间隙锁 Gap Locks
临键锁 Next-key Locks
共享锁(S):
又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,
都能访问到数据,但是只能读不能修改;
-- 加锁释锁方式:
select * from users WHERE id=1 LOCK IN SHARE MODE;
commit/rollback
排他锁(X):
又称为写锁,简称X锁,排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他
锁,其他事务就不能再获取该行的锁(共享锁、排他锁),只有该获取了排他锁的事务是可以对
数据行进行读取和修改,(其他事务要读取数据可来自于快照)**
-- 加锁释锁方式:
delete / update / insert 默认加上X锁
SELECT * FROM table_name WHERE ... FOR UPDATE
commit/rollback
InnoDB的行锁是通过给索引上的索引项加锁来实现的。
只有通过索引条件进行数据检索,InnoDB才使用行级锁,否则,InnoDB将使用表锁(锁住索引的所有记录)
表锁:lock tables xx read/write;
理解行锁机制,才能设计高效的sql
意向共享锁(IS)
表示事务准备给数据行加入共享锁,即一个数据行加共享锁前必须先取得该表的IS锁,
意向共享锁之间是可以相互兼容的
意向排它锁(IX)
表示事务准备给数据行加入排他锁,即一个数据行加排他锁前必须先取得该表的IX锁,
意向排它锁之间是可以相互兼容的
意向锁(IS 、IX) 是InnoDB 数据操作之前 自动加的,不需要用户干预
意义:
当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速返回该表不能
启用表锁
在表上面打个标记,有点像java的偏向锁 (CAS操作)
针对自增列自增长的一个特殊的表级别锁
show variables like 'innodb_autoinc_lock_mode';
# 默认取值1 ,代表连续,事务未提交ID
Next-key locks :
锁住记录+ 区间(左开右闭)
当sql执行按照索引进行数据的检索时,查询条件为范围查找(between and、<、>等)并有数
据命中则此时SQL语句加上的锁为Next-key locks, 锁住索引的记录+ 区间(左开右闭)
临键锁解决了幻读问题
Gap locks:
锁住数据不存在的区间(左开右开)
当sql执行按照索引进行数据的检索时,查询条件的数据不存在,这时SQL语句加上的锁即为
Gap locks, 锁住索引不存在的区间(左开右开)
Record locks:
锁住具体的索引项
当sql执行按照唯一性(Primary key、Unique key)索引进行数据的检索时,查询条件等值匹
配且查询的数据是存在,这时SQL语句加上的锁即为记录锁Record locks ,锁住具体的索引项
利用X锁解决脏读问题
利用S锁解决不可重复读
利用邻键锁解决幻读问题
死锁的避免
undo 意为取消,以撤销操作为目的,返回指定某个状态的操作
undo log 指事务开始之前, 在操作任何数据之前, 首先将 需操作的 数据备份到一个地方 (Undo Log)
UndoLog 是为了实现事务的原子性而出现的产物
Undo Log 实现事务 原子性 :
事务处理过程中 如果出现了错误或者用户执行了 ROLLBACK 语句,Mysql 可以利用Undo Log 中的备份
将数据恢复到事务开始之前的状态
UndoLog 在Mysql innodb 存储引擎中用来实现多版本并发控制
Undo log 实现多版本并发控制:
事务未提交之前,Undo 保存了未提交之前的版本数据,Undo 中的数据可作为数据旧版本快照供
其他并发事务进行快照读
MVCC:
Multiversion concurrency control (多 多 版本并发 控制)
普通话解释:
并发访问(读或写)数据库时,对正在事务内处理的数据做
多版本的管理。以达到用来避免写操作的堵塞,从而引发读操
作的并发问题。
快照读:
SQL 读取的数据是快照版本,也就是历史版本 , 普通的SELECT 就是快照读
innodb 快照读,数据的读取将由 cache( 原本数据) + undo( 事务修改过的数据) 两部分组成
当前读:
SQL 读取的 数据 是最新版本 。通过锁机制来保证读取的数据无法通过其他事务进行修改
UPDATE 、DELETE 、INSERT 、SELECT … LOCK IN SHARE MODE 、SELECT … FOR UPDATE 都是
当前读
Redo Log 是什么:
Redo ,顾名思义就 是 重做。以恢复操作为目的,重现操作 ;
Redo log 指事务中 操作 的 任何数据,将 将 最新的 数据备份到一个地方 (Redo Log)
Redo log 的持久:
不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo 中。具体
的落盘策略可以进行配置
RedoLog 是为了实现事务的持久性而出现的产物
防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql 服务的时候,根据redo
log 进行重做,从而达到事务的 未入磁盘数据进行 持久化
Redo log补充知识
指定Redo log 记录在{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
:
基于参数的作用域:
set global autocommit = ON/OFF;
set session autocommit = ON/OFF;
注意:
mysql --help #寻找配置文件的位置和加载顺序
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf
mysql --help | grep -A 1 'Default options are read from the following
files in the given order'
port = 3306
socket = /tmp/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql
pid-file = /data/mysql/mysql.pid
user = mysql
bind-address = 0.0.0.0
max_connections=2000
lower_case_table_names = 0 # 表名区分大小写
server-id = 1
tmp_table_size=16M
transaction_isolation = REPEATABLE-READ
ready_only=1
每一个connection 内存参数配置:
sort_buffer_size connection 排序缓冲区大小
建议256K( 默认值)-> 2M 之内
当查询语句中有需要文件排序功能时,马上为connection 分配配置的内存大小
join_buffer_size connection 关联查询缓冲区大小
建议256K( 默认值)-> 1M 之内
当查询语句中有关联查询时,马上分配配置大小的内存用这个关联查询,所以有可能在一个查询语句中会分配很多个关联查询缓冲区
上述配置4000 连接占用内存:
4000*(0.256M+0.256M) = 2G
大的缓冲池可以减小多次磁盘I/O 访问相同的表数据以提高性能
参考计算公式:
Innodb_buffer_pool_size = (总物理内存 - 系统运行所用 - connection 所用)* 90%
https://www.cnblogs.com/wyy123/p/6092976.html 常见配置的帖子
简单一点 :
1 , 每一列只有一个 单一的 值 ,不可再拆分
2 , 每一行都 有主键能进行 区分
3 , 每一个表都不包含其他表已经包含的非 主键 信息。
数据从磁盘到缓冲区,缓冲区脏页到磁盘进行持久的过程中,列的数量过多
会导致性能下降。过多的列影响转换和持久的性能
SELECT
*
FROM
XXXXX
WHERE
(convert((price_full * 100 - price * 100) , SIGNED) - convert(coupon_price*100,SIGNED)
AND
is_del = 0)
ORDER BY
id
desc
limit 100
-- 设计冗余字段,在添加联合索引解决问题