qiuyadong's Homepage

Mysql2

2019-07-02

Mysql!

学习笔记

mysql中如何开启事务:

begin / start transaction – 手工

commit / rollback – 事务提交或回滚

set session autocommit = on/off; – 设定事务是否自动开启

JDBC 编程:

connection.setAutoCommit(boolean);

Spring 事务AOP编程:

expression=execution(com.gpedu.dao..(..))

Read Uncommitted(未提交读) –未解决并发问题 事务未提交对其他事务也是可见的,脏读(dirty read) Read Committed(提交读) –解决脏读问题 一个事务开始之后,只能看到自己提交的事务所做的修改,不可重复读(nonrepeatable read) Repeatable Read (可重复读) –解决不可重复读问题 在同一个事务中多次读取同样的数据结果是一样的,这种隔离级别未定义解决幻读的问题 Serializable(串行化) –解决所有问题 最高的隔离级别,通过强制事务的串行执行

锁是用于管理不同事务对共享资源的并发访问

表锁与行锁的区别: 锁定粒度:表锁 > 行锁 加锁效率:表锁 > 行锁 冲突概率:表锁 > 行锁 并发性能:表锁 < 行锁

InnoDB存储引擎支持行锁和表锁(另类的行锁)

共享锁(行锁):Shared Locks 排它锁(行锁):Exclusive Locks 意向锁共享锁(表锁):Intention Shared Locks 意向锁排它锁(表锁):Intention Exclusive Locks 自增锁:AUTO-INC Locks

共享锁: 又称为读锁, 简称S锁, 顾名思义, 共享锁就是多个事务对于同一数据可以共享一把锁, 都能访问到数据, 但是只能读不能修改; 加锁释锁方式: select * from users WHERE id=1 LOCK IN SHARE MODE; commit/rollback

排他锁: 又称为写锁, 简称X锁, 排他锁不能与其他锁并存, 如一个事务获取了一个数据行的排他 锁, 其他事务就不能再获取该行的锁(共享锁、 排他锁) , 只有该获取了排他锁的事务是可以对 数据行进行读取和修改, (其他事务要读取数据可来自于快照) 加锁释锁方式: delete / update / insert 默认加上X锁 SELECT * FROM table_name WHERE … FOR UPDATE commit/rollback

InnoDB的行锁是通过给索引上的索引项加锁来实现的。、

只有通过索引条件进行数据检索,InnoDB才使用行级锁,否则,InnoDB 将使用表锁(锁住索引的所有记录) 表锁:lock tables xx read/write;

意向共享锁(IS) 表示事务准备给数据行加入共享锁, 即一个数据行加共享锁前必须先取得该表的IS锁,意向共享锁之间是可以相互兼容的

意向排它锁(IX) 表示事务准备给数据行加入排他锁, 即一个数据行加排他锁前必须先取得该表的IX锁,意向排它锁之间是可以相互兼容的

意向锁(IS、 IX)是InnoDB数据操作之前自动加的, 不需要用户干预意义:

当事务想去进行锁表时, 可以先判断意向锁是否存在, 存在时则可快速返回该表不能启用表锁

针对自增列自增长的一个特殊的表级别锁 show variables like ‘innodb_autoinc_lock_mode’; 默认取值1, 代表连续, 事务未提交ID永久丢失

按照锁算法类型分为:

Next-key locks=Gap locks+Record locks

Next-key locks:临键锁 锁住记录+区间(左开右闭)type=range 当sql执行按照索引进行数据的检索时,查询条件为范围查找(between and、 <、 >等) 并有数 据命中则此时SQL语句加上的锁为Next-key locks, 锁住索引的记录+区间(左开右闭),为啥使用临键锁的主要原因就是解决幻读问题,innodb使用的b+s树天然是有序的,所以将相邻的区间锁住解决幻读问题,插不进去了,幻读就是数据行多少的问题,命中行以及相邻区间

Gap locks:当命中的时候使用临键锁,当命不中的时候,临建锁退化成了间隙锁,只在rr中存在 锁住数据不存在的区间(左开右开) 当sql执行按照索引进行数据的检索时, 查询条件的数据不存在, 这时SQL语句加上的锁即为 Gap locks, 锁住索引不存在的区间(左开右开)

Record locks:记录锁type=eq_ref 锁住具体的索引项 当sql执行按照唯一性(Primary key、 Unique key) 索引进行数据的检索时, 查询条件等值匹 配且查询的数据是存在, 这时SQL语句加上的锁即为记录锁Record locks, 锁住具体的索引项。如果是普通键查找的时候会将临界的两个区间都锁住

  • 如何解决脏读问题呢?

就是读的时候不允许别人修改

在select的时候加上s锁

  • 如何解决不可重复读

同样就是读的时候不允许别人修改

在select的时候加上s锁

  • 如何解决幻读问题呢?

在select上加上Next-key locks

  • 死锁

多个并发事务(2个或者以上);

每个事务都持有锁(或者是已经在等待锁);

每个事务都需要再继续持有锁;

事务之间产生加锁的循环等待,形成死锁

有向无环图

  • 如何避免死锁

1)类似的业务逻辑以固定的顺序访问表和行。

2)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。

3)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概 率。

4)降低隔离级别,如果业务允许,将隔离级别调低也是较好的选择

5)为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁(或者说是表锁)

查看mysql的设置的事务隔离级别

select global.@@tx_isolation; select @@tx_isolation;

默认是REPEATABLE-READ级别

  • MVCC 多版本控制

先读的不会出现问题

后读发现出现了不可重复读问题

  • 不是出现在mvcc的问题,那么问题出在哪里呢?

脏读,不可重复读都不是通过mvcc处理的

Undo Log 是什么:

undo意为取消, 以撤销操作为目的, 返回指定某个状态的操作

undo log指事务开始之前, 在操作任何数据之前,首先将需操作的数据备份到一个地方 (Undo Log)

UndoLog是为了实现事务的原子性而出现的产物

Undo Log实现事务原子性:

事务处理过程中如果出现了错误或者用户执行了 ROLLBACK语句,Mysql可以利用Undo Log中的备份 将数据恢复到事务开始之前的状态

UndoLog在Mysql innodb存储引擎中用来实现多版本并发控制

Undo log实现多版本并发控制:

事务未提交之前, Undo保存了未提交之前的版本数据, Undo 中的数据可作为数据旧版本快照供 其他并发事务进行快照读

快照读:解决幻读问题,mvcc

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是为了实现事务的持久性而出现的产物 Redo Log实现事务持久性: 防止在发生故障的时间点, 尚有脏页未写入磁盘, 在重启mysql服务的时候, 根据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: 取值 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操作,推荐使用,mysql挂了,最后一次事务失败,系统挂了,1秒钟事务丢失

  • 配置优化

最大连接数配置

max_connections

系统句柄数配置

/etc/security/limits.conf

ulimit -a

mysql句柄数配置

/usr/lib/systemd/system/mysqld.service

每一个connection内存参数配置: sort_buffer_size connection排序缓冲区大小 建议256K(默认值)-> 2M之内 当查询语句中有需要文件排序功能时, 马上为connection分配配置的内 存大小 join_buffer_size connection关联查询缓冲区大小 建议256K(默认值)-> 1M之内 当查询语句中有关联查询时, 马上分配配置大小的内存用这个关联查 询, 所以有可能在一个查询语句中会分配很多个关联查询缓冲区 上述配置4000连接占用内存: 4000*(0.256M+0.256M) = 2G

Innodb_buffer_pool_size innodb buffer/cache的大小(默认128M) Innodb_buffer_pool

数据缓存

索引缓存

缓冲数据

内部结构

大的缓冲池可以减小多次磁盘I/O访问相同的表数据以提高性能

参考计算公式:

Innodb_buffer_pool_size = (总物理内存 - 系统运行所用 - connection 所用) * 90%

wait_timeout 服务器关闭非交互连接之前等待活动的秒数

innodb_open_files 限制Innodb能打开的表的个数

innodb_write_io_threads innodb_read_io_threads innodb使用后台线程处理innodb缓冲区数据页上的读写 I/O(输入输出)请求

innodb_lock_wait_timeout InnoDB事务在被回滚之前可以等待一个锁定的超时秒数

https://www.cnblogs.com/wyy123/p/6092976.html 常见配置的帖子

  • 数据库表设计

简单一点:

1, 每一列只有一个单一的值, 不可再拆分,,,将建立太多的列,可以放json

2, 每一行都有主键能进行区分

3, 每一个表都不包含其他表已经包含的非主键信息。,,,太多表的关联关系,订单表中冗余用户名的字段



Comments