一个事务会涉及到大量的cpu计算和IO操做,这些操做被打包成一个执行单元,要么同时都完成,要么同时都不完成.mysql
事务是一组原子性的sql命令或者说是一个独立的工做单元,若是数据库引擎可以成功的对数据库应用该组的所有sql语句,那么就执行该组命令sql
若是其中有任何一条语句由于崩溃或者其它缘由没法执行,那么该组中全部的sql语句都不会执行数据库
若是没有显示启动事务,数据库会根据autocommit的值.默认每条sql操做都会自动提交.安全
一个事务中的全部操做,要么都完成,要么都不执行.对于一个事务来讲,不可能只执行其中的一部分.服务器
数据库老是从一个一致性的状态转换到另一个一致性状态.并发
一个事务所作的修改在最终提交之前,对其它事务是不可见的.多个事务之间的操做相互不影响. 每下降一个事务隔离级别都能提升数据库的并发mvc
1.读未提交 其它事务未提交就能够读
2.读已提交 其它事务只有提交了才能读
3.可重复读 只管本身启动事务时候的状态,不受其它事务的影响(mysql默认)
4.事务串行 按照顺序提交事务保证了数据的安全性,但没法实现并发ide
一旦一个事务已经提交了,就算服务器崩溃,仍然须要在下次启动的时候自动恢复.性能
结合事务日志完成:设计
事务日志写入磁盘的时候是顺序IO,写数据文件的时候是随机IO
一旦事务提交了,必须当即执行一个IO操做,确保此事务当即写入磁盘.
事务的状态
活动
部分提交
失败
停止
提交
事务一旦成功提交,便没法再撤销.
事务并发访问控制方式:
锁
时间
多版本和快照隔离(mvcc)
MVCC是行级锁的一个变种,可是它在不少状况下避免了加锁操做,所以开销更低,虽然实现机制有所不一样,但大都实现了非阻塞的读操做,写操做也只锁定必要的行.
MVCC的实现是经过保存数据在某个时间点的快照来实现的,也就是说,无论须要执行多长时间,只要事务开始时间相同,每一个事务看到的数据都是一致的,事务开始的时间不一样时,每一个事务对同一张表,同一时刻看到的数据多是不同的(由于不一样的时间点可能数据就已经产生了不一样的快照版本,而每一个事务在默认的RR隔离级别下只能看到事务开始时的数据快照)
innodd的mvcc是经过在每行记录后面保存两个隐藏列来实现的.这两个列,一个保存了行的建立时间.一个保存了行的过时时间(删除时间).列里面存储的并非实际的时间值.而是系统版本号.每开启一个新的事务,系统版本号都会自动递增.
一个事务在开启的时刻的系统版本号做为当前事务的版本号,用来和查询到的每行记录的版本号作对比.mvcc具体操做以下:
select:
A:过滤建立版本
innodb只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样能够确保事务读取的行,要么是在事务开始以前已经存在,要么是事务自身插入或修改的数据.
B: 过滤删除版本
行的删除版本要么未定义,要么大于当前事务版本号,这能够确保事务读取到的行,在事务开始以前未被删除(即,这样作的目的是为了事务不会读取到被真正删除的行,删除版本号小于当前事务版本号的表示操做删除记录的事务已经提交--数据已经被删除,删除版本号大于当前事务版本号的表示这个事务是在当前事务以后开始的--当前事务开始时这些记录是还存在的,根据事务的隔离性,一致性要求,以后开始的事务操做的记录并提交,对当前事务不可见,因此还须要当前事务可以查询这些记录--只可以查询,不可以修改和删除)
只有知足以上两个条件的才能够返回做为查询结果
insert:
innodb为新插入的每一行保存当前系统版本号做为行版本号
delete:
innodb为删除的每一行保存当前系统版本号做为行删除标识
update:
innodb为插入一行新记录,保存当前系统版本号做为行版本号
修改表中原来行把当前系统版本号更新到原来的行做为行删除版本号
保存这两个额外的系统版本号,使大多数读操做均可以不用加锁,这样设计使得读数据操做很简单,性能很好,而且也能保证只会读取到符合标准的行,不足之处是每行记录都须要额外的存储空间,须要作更多的行检查工做,以及一些额外的维护工做。
MVCC只在repeatable-read和read-committed两个隔离级别下才工做,其余两个隔离级别都和MVCC不兼容,由于read uncommitted老是读取最新的数据行,而不是符合当前事务版本的数据行,而serializeble则会对全部读取的行都加锁。
另外要注意:MVCC在RR和RC隔离级别下的区别,在RR隔离级别下,一个事务只能读取到事务开始的那个时刻的数据快照,即,别的事务修改并提交的数据在自身没有提交以前通常读取不到(加for update语句的select除外,由于这个语句要对数据加X锁必须读取最新的数据快照),在RC隔离级别下,事务老是读取数据行的最新快照,即会产生不可重复读的问题。
两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源的状态
mysql默认采用自动提交(AUTOCOMMIT)模式.若是没有显示的开始一个事务,那么每条sql语句都会被看成一个事务执行提交的操做
当AUTOCOMMIT=0的时候全部的sql语句都是在一个事务中,直到显示的执行COMMIT和ROLLBACK回滚该事务结束.同时又开始了另一个新的事务.
开启事务
START TRANSACTION
结束事务
(1) COMMIT: 提交
(2) ROLLBACK: 回滚
注意:一旦一个事务成功提交,将没法回滚.一个事务要想回滚,只能在没有提交成功以前执行回滚
只有事务型存储引擎中的DML语句方能支持此类操做
建议:显式请求和提交事务,而不要使用“自动提交”功能 set autocommit={1|0}
事务支持保存点 savepoint:
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
事务要保证ACID的完整性必须依靠事务日志作跟踪,每个操做在真正写入数据数据库以前,先写入到日志文件中
如要删除一行数据会先在日志文件中将此行标记为删除,可是数据库中的数据文件并无发生变化.
只有在(包含多个sql语句)整个事务提交后,再把整个事务中的sql语句批量同步到磁盘上的数据库文件
在事务引擎上的每一次写操做都须要执行两遍:
1.先写入日志文件中
写入日志文件中的仅仅是操做过程,而不是操做数据自己,因此速度比写数据库文件速度要快不少.
2.而后再写入数据库文件中
写入数据库文件的操做是重作事务日志中已提交的事务操做的记录.
日志组
通常不止设置一个日志文件,一个文件写满以后使用另一个日志文件提升服务器效率.
日志文件的日志同步到磁盘后空间会自动释放,单个日志文件不宜设置过大 若是日志文件过大mysql进程在把日志同步到数据文件的时候可能会崩溃
事务日志能够帮助提升事务的效率,使用事务日志,存储引擎在修改表的数据的时候只须要修改其内存拷贝,再把该行为记录到持久在磁盘的事务日志中.而不用每次都将修改的数据自己持久到磁盘.事务日志采用的是追加方式,所以写日志的操做是磁盘上一小块区域的顺序IO,而不像随机IO须要磁盘在多个地方移动.因此采用事务日志的方式相对来讲要快的多,事务日志持久后,内存中的修改在后台慢慢的刷回磁盘.期间若是系统发生崩溃,存储引擎在重启的时候依靠事务日志自动恢复这部分被修改数据