事务四大特性(ACID):
原子性:强调事务的不可分割。
一致性:事务的执行的前后数据的完整性保持一致。
隔离性:一个事务执行的过程中,不应该受到其他事务的干扰。
持久性:事务一旦结束,数据就持久到数据库。
事务隔离级别:
1.未提交读RU —— 最低级别只能保证不读取物理上损坏的数据 会出现脏读问题(直接读写磁盘)
2.已读提交RC —— 语句级 会出现不可重复读问题(查询磁盘 操作内存)
3.可重复读取RR —— 事务隔离级别 会出现幻读问题 mysq默认事务隔离级别(查内存 写内存)
4.序列化 —— 最高级别 事务级 可以解决所有问题 但是性能慢 在数据安全性很重要的时候使用(事务串行化 一个一个执行)
使用事务会出现得问题:
1.数据更新丢失:
既:两个事务或者多个事务并行得时候,因为事务隔离级别不够从而产生联级回滚 因为先行得事务报错导致后面并行得事务也出现报错而抛出异常回滚使后面得事务因为异常从而丢失了需要更新得数据。(级联回滚5.7以下版本)
出现隔离级别:除序列化以外的
解决方法:提高事务隔离级别或加排他锁解决
2.脏读:
既:两个事务或多个事务并行的时候其中一个事务读取到了其他事务已修改但是未提交的数据。
出现隔离级别:未提交读(RU)
解决方法:提高事务隔离级别或使用锁
3.不可重复读:
既:一个事务对同一行数据重复读取两次,但是却得到了不同的结果。例如,在两次读取的中途,有另外一个事务对该型数据进行了修改,并提交。
出现隔离级别:已读提交(RC)
解决方法:提高隔离级别或使用锁
4.幻读:
既:两个事务或者多个事务并行的时候,在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(SQL不一定一样),或事务未读取到另外一个事务已提交的数据,但是却导致执行SQL不成功。
出现隔离级别:可重复读取(RR)
解决方法:提高隔离级别或使用锁
事务日志:
执行流程:
写操作 ——> database/table ——> 缓存数据(内存) ——> innodb_log_Buffer(日志缓存区) ——> Undo log/Redo log ——> 数据落盘
当我们开启事务执行一条sql语句对事务进行修改的时候,它会先将数据从磁盘读入内存,并更新内存中的缓存数据,然后生成一条重做日志写入重做日志缓存。当事务真正的进行提交的时候,MySQL会将重做日志缓存中的内容刷新到重做日志文件。再将内存中的数据更新到磁盘上。
注:事务的整个过程中MySQL的日志优先级会大于数据。
回滚日志 undo:
回滚日志中记录的是与你执行SQL相反的SQL语句,当你的事务遇到异常或错误等其他因素数据需要回滚的时候 MySQL就从回滚日志中记录执行相反操作的SQL语句从而让已执行的操作进行回滚,从而保证事务的原子性,MySQL中事务的回滚就是靠回滚日志(undo log)来实现恢复机制的。
注:系统发生崩溃、数据库进程直接被杀死后、当用户再次启动数据库进程时,还能够立刻通过查询回滚日志将之前未完成的事务进行回滚,这也就需要回滚日志必须先于数据持久化到磁盘上,这也是需要先写日志后写数据库的主要原因。
重做日志 redo:
MySQL 使用重做日志(redo log)实现事务的持久性,重做日志由两部分组成:一是内存中重做日志的缓存区,因为在内存中所以它是易丢失去的,二是磁盘中的重做日志,它是持久的。
注:若事务提交后 MySQL因为一些物理性原因,数据还没来得及写入磁盘那么在MySQL重启就会执行重做日志(redo log),来恢复数据。
注:当事务执行完成以后 MySQL就不会再执行回滚日志了。
在数据库中,这两种日志经常都是一起工作的,可以将它们整体看做一条事务日志,其中包含了事务的 ID、修改的行元素以及修改前后的值。
事务声明周期:
创建日志 => 日志刷盘(ib_logfile) => 数据刷盘 => 写KCP (ib_data)
事务在操作数据的时候,会先创建日志文件(文件标识即日志ID),然后在执行修改写入的时候从数据库中获取数据将数据更新到缓存区中,然后将修改写入之前的数据先记录到日志文件中,接着再去进行数据的操作,操作完成以后,当你执行commit提交的时候,这时候再次把操作后的数据写入到日志文件,然后才做数据更新的操作(数据刷盘)。最后再去做事务一致性的校验。
事务日志写入频率(innodb_flush_log_at_trx_commit 参数解析):
innodb_flush_log_at_trx_commit (mysql通过这个参数来设置写入日志时间 即日志刷新频率)
注:这个参数影响的是日志声明周期中的日志刷盘环节写入到redo log的时间频率
注:参数值:0/1/2
查看innodb_flush_log_at_trx_commit参数设置:
show variables like 'innodb_flush_log_at_trx_commit';
修改innodb_flush_log_at_trx_commit参数设置:
set @@global.innodb_flush_log_at_trx_commit = 0; -- 0,1,2
0值:性能最好 但是数据安全性最差 若是服务器死机或者断电 就会丢失数据
1值:性能最差 但是保证数据安全性最高 只要提交就不会丢失数据
2值:性能折中 即安全性比参数1差 但是性能比1好一点 安全性比0好一点性能比 0差一点 也会出现数据丢失的情况
注:MySQL默认此参数的值设置是1,且此参数是针对全局的,若是单机运行的话则默认使用1,若是集群服务则可以在不是很重要的数据设置为0以提高性能。