MySQL中事务详解
mysql怎么读英语事务是⼀系列的动作,它们综合在⼀起才是⼀个完整的⼯作单元,这些动作必须全部完成,如果有⼀个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发⽣过⼀样。
数据库事务是保证在并发情况下能够正确执⾏的重要⽀撑,MySQL常见的数据库引擎中⽀持事务的是InnoDB。
事务就是⼀系列操作,正确执⾏并提交,如果中途出现错误就回滚。事务要保证能够正常的执⾏,就必须要保持ACID特性。
事务由单独单元的⼀个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。⽽整个单独单元作为⼀个不可分割的整体,如果单元中某条SQL语句⼀旦执⾏失败或产⽣错误,整个单元将会回滚。所有受到影响的数据将返回到事物开始以前的状态。如果单元中的所有SQL语句均执⾏成功,则事物被顺利执⾏。
事务的开始和结束
以第⼀个DML 语句的执⾏作为开始,以下⾯的其中之⼀作为结束:
COMMIT 或ROLLBACK 语句
DDL 或DCL 语句(⾃动提交)
⽤户会话正常结束
系统异常终了
关于DDL和DCL参考下图:
【1】事务的四个特性
事务的四个关键属性(ACID)。
①原⼦性(atomicity)
原⼦性是指事务是⼀个不可分割的⼯作单位,事务中的操作要么都发⽣,要么都不发⽣。
事务是⼀个原⼦操作, 由⼀系列动作组成。 组成⼀个事务的多个数据库操作是⼀个不可分割的原⼦单元,只有所有的操作执⾏成功,整个事务才提交。
事务中的任何⼀个数据库操作失败,已经执⾏的任何操作都必须被撤销,让数据库返回初始状态。
②⼀致性(consistency)
事务必须使数据库从⼀个⼀致性状态变换到另外⼀个⼀致性状态。
⼀旦所有事务动作完成, 事务就被提交。数据和资源就处于⼀种满⾜业务规则的⼀致性状态,即数据不会被破坏。
⽐如a+b=100,⼀个事务改变了a⽐如增加了a的值,那么必须同时改变b,保证在事务结束以后a+b=10
0依然成⽴,这就是⼀致性。③隔离性(isolation)
事务的隔离性是指⼀个事务的执⾏不能被其他事务⼲扰,即⼀个事务内部的操作及使⽤的数据对并发的其他事务是隔离的,并发执⾏的各个事务之间不能互相⼲扰。
在并发数据操作时,不同的事务拥有各⾃的数据空间,它们的操作不会对对⽅产⽣⼲扰。准确地说,并⾮要求做到完全⽆⼲扰。
数据库规定了多种事务隔离界别,不同的隔离级别对应不⽤的⼲扰程度。隔离级别越⾼,数据⼀致性越好,但并发⾏越弱。⽐如对于A对B 进⾏转账,A没把这个交易完成的时候,B是不知道A要给他转钱。
④持久性(durability)
持久性是指⼀个事务⼀旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
数据库管理系统⼀般采⽤重执⾏⽇志来保证原⼦性、⼀致性和持久性。
重执⾏⽇志记录了数据库变化的每⼀个动作,数据库在⼀个事务中执⾏⼀部分操作后发⽣错误退出,
数据库即可根据重执⾏⽇志撤销已经执⾏的操作。对于已经提交的事务即使数据库崩溃,在重启数据库时也能根据⽇志对尚未持久化的数据进⾏相应的重执⾏操作。
【2】事务的传播属性
即当前的事务⽅法被另外⼀个事务⽅法调⽤时如何使⽤事务,默认取值为required,即使⽤调⽤⽅法的事务。
事务传播⾏为类型说明
REQUIRED如果有事务在运⾏,当前的⽅法就在这个事务内运⾏;否则,就启动⼀个新的事务,并在⾃⼰的事务内运⾏;
REQUIRES_NEW当前的⽅法必须启动新事务,并在它⾃⼰的事务内运⾏;如果有事务正在运⾏,应该将它挂起。
MANDATORY当前的⽅法必须运⾏在事务内部,如果没有正在运⾏的事务,将抛出异常。
SUPPORTS如果有事务在运⾏,当前的⽅法就在这个事务内运⾏;否则它可以不运⾏在事务中。
NOT_SUPPORTED当前的⽅法不应该运⾏在事务中,如果有运⾏的事务,将它挂起。
NEVER当前的⽅法不应该运⾏在事务中,如果有运⾏的事务,就抛出异常。
NESTED如果有事务在运⾏,当前的⽅法就应该在这个事务的嵌套事务内运⾏。否则,就启动⼀个新的事务,并在它⾃⼰的事务内运⾏。
其中,最常使⽤的是 REQUIRED 、REQUIRES_NEW。
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的⼀个特殊变量。 它要求事务管理器或者使⽤JDBC 3.0 Savepoint API提供嵌套事务⾏为(如Spring的DataSourceTransactionManager)
ROPAGATION_REQUIRES_NEW 启动⼀个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back ⽽不依赖于外部事务, 它拥有⾃⼰的隔离范围, ⾃⼰的锁, 等等. 当内部事务开始执⾏时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执⾏.
另⼀⽅⾯, PROPAGATION_NESTED开始⼀个 “嵌套的” 事务, 它是已经存在事务的⼀个真正的⼦事务。潜套事务开始执⾏时, 它将取得⼀个savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint。 潜套事务是外部事务的⼀部分, 只有外部事务结束后它才会被提交.
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最⼤区别在于:
PROPAGATION_REQUIRES_NEW 完全是⼀个新的事务, ⽽ PROPAGATION_NESTED 则是外部事务的⼦事务, 如果外部事务 commit,潜套事务也会被 commit, 这个规则同样适⽤于 roll back。
【3】事务的隔离级别
⼀个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别, 不同隔离级别对应不同的⼲扰程度, 隔离级别越⾼, 数据⼀致性就越好, 但并发性越弱。
数据库系统必须具有隔离并发运⾏各个事务的能⼒, 使它们不会相互影响, 避免各种并发问题。
对于同时运⾏的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题。
五种隔离级别:DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE。
Oracle ⽀持的2 种事务隔离级别:READ_COMMITTED, SERIALIZABLE。Oracle 默认的事务隔离级别为: READ_COMMITTED。
MySQL⽀持4 种事务隔离级别:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE。MySQL 默认的事务隔离级别为: REPEATABLE_READ
① DEFAULT(读提交)
这是⼀个PlatfromTransactionManager默认的隔离级别,使⽤数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。⼤部分数据库的默认级别都是READ_COMMITTED(读取已提交)。
② READ_UNCOMMITTED(读取未提交)
这是事务最低的隔离级别,允许当前事务读取未被其他事务提交的变更。这种隔离级别会产⽣脏读,不可重复读和幻读。
产⽣脏读场景:A事务读取⼀个字段,但是这个字段被另外⼀个事务更新却未提交,再次读取该字段时如果另外⼀个事务回滚则出现了脏读现象(读到的数据与第⼀次,数据库中的数据都不同)。
产⽣不可重复读场景:A事务读取⼀个字段,但是这个字段被另外⼀个事务更新并提交,再次读取该字段值不⼀样则出现了不可重复读现象(同⼀个事务中,不能保证读取的字段值相同)。
产⽣幻读场景:A事务读取⼀个字段集合,但是这个表被另外⼀个事务更新并提交(如插⼊了⼏⾏),再次读取该表可能会多⼏⾏则出现了幻读现象。
或者说事务A开启事务,查询当前表-⽬标数据不存在;事务B开启事务插⼊⼀条新数据(id为主键);事
务A 插⼊和事务B⼀样的数据,会出现锁等待超时现象。事务B提交后,事务A再次尝试插⼊,出现Duplicate entry…事务B很诧异,明明查询出来不存在将要插⼊的数据┭┮﹏┭┮
③ READ_COMMITTED(读取已提交)
保证⼀个事务修改的数据提交后才能被另外⼀个事务读取,另外⼀个事务不能读取该事务未提交的数据。可以避免脏读,但不可重复读和幻读的现象仍然可能出现。
不可重复读
A事务读取⼀个字段,但是这个字段被另外⼀个事务更新并提交,再次读取该字段值不⼀样则出现了不可重复读现象(同⼀个事务中,不能保证读取的字段值相同)。
举例就是对于⼀个数A原来是50,然后提交修改成100,这个时候另⼀个事务在A提交修改之前,读取到了A是50,刚读取完,A就被修改成100了,这个时候另⼀个事务再进⾏读取发现A就突然变成100了
幻读
读取⼀个字段,但是这个表被另外⼀个事务更新并提交(如插⼊了⼏⾏),再次读取该表可能会多⼏⾏则出现了幻读现象。
④ REPEATABLE_READ(可重复读)
确保事务可以多次从某⾏记录的⼀个字段中读取相同的值,在这个事务持续期间,禁⽌其他事务对这个字段进⾏更新。这种事务隔离级别可以防⽌脏读,不可重复读,但是可能出现幻读。
它除了保证⼀个事务不能读取另⼀个事务未提交的数据外,还保证了在⼀个事务过程,读取的数据不会发⽣变化(即使数据库中的数据在该事务过程中发⽣了变化)。
//如下代码所⽰,可重复读意味着两次读取字段A值相同!
public void test(){
//开启事务
//读取字段A;
沈阳钢结构公司前十名include放句首//此时数据库中A发⽣了变化;
//读取字段A;
//提交事务;
//关闭事务;
}
hive解析json数组幻读
读取⼀个字段集合,但是这个表被另外⼀个事务更新并提交(如插⼊了⼏⾏),再次读取该表可能会多⼏⾏则出现了幻读现象。
⑤ SERIALIZABLE :(可串⾏化)
在并发情况下和串⾏化的读取的结果是⼀致的,没有什么不同。这是花费最⾼代价但是最可靠的事务隔离级别,事务被处理为顺序执⾏。
除了防⽌脏读,不可重复读外,还避免了幻读。但性能⼗分低下!
⑥什么是脏读、不可重复读和幻读?
脏读: 对于两个事务 T1, T2。T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且⽆效的,也就是脏数据。
不可重复读:对于两个事务 T1, T2。 T1 读取了⼀个字段, 然后 T2 更新了该字段。之后, T1再次读取同⼀个字段, 值就不同了。
幻读:事务T1读取⼀条指定where条件的语句,返回结果集。此时事务T2插⼊⼀些新记录,恰好满⾜T1的where条件。然后T1使⽤相同的条件再次查询,结果集中可以看到T2插⼊的记录,这些多出来的新纪录就是幻读。
或者说事务A开启事务,查询当前表;事务B开启事务插⼊⼀条新数据(id为主键);事务A 插⼊和事务B⼀样的数据,会出现锁等待超时现象。事务B提交后,事务A再次尝试插⼊,出现Duplicate entry…事务B很诧异,明明查询出来不存在将要插⼊的数据┭┮﹏┭┮
不可重复读重点是在update,即事务前后对⽐特定数据内容的修改。⽽幻读是insert和delete,即事务前后数据结果集的对⽐。
⑦事务隔离级别与存在问题
隔离级别存在问题
READ UNCOMMITTED脏读、不可重复读、幻读
隔离级别存在问题
READ COMMITTED不可重复读、幻读
REPEATABLE READ幻读
SERIALIZABLE⽆
Oracle数据库⽀持READ COMMITTED(默认) 和 SERIALIZABLE这两种事务隔离级别。所以Oracle不会出现脏读。
MySQL ⽀持 4 种事务隔离级别:READ_UNCOMMITTED(读取未提交),READ_COMMITTED(读取已提交),REPEATABLE_READ(可重复读-默认)和SERIALIZABLE (可串⾏化)。
SQL标准所定义的默认事务隔离级别是SERIALIZABLE,但是Oracle 默认使⽤的是READ COMMITTED。MySQL默认事务隔离级别
为REPEATABLE_READ。
事务的隔离级别要得到底层数据库引擎的⽀持, ⽽不是应⽤程序或者框架的⽀持。需要注意的是事务的隔离级别和数据库并发性是成反⽐的,隔离级别越⾼,并发性越低。
⑧设置MySQL的事务隔离级别
每启动⼀个mysql 程序, 就会获得⼀个单独的数据库连接。每个数据库连接都有⼀个全局变量@@tx_isolation, 表⽰当前的事务隔离级别。查看当前的隔离级别:
前端毕业设计题目可以做哪些SELECT@@tx_isolation;
设置当前mySQL 连接的隔离级别:
set transaction isolation level read committed;
设置数据库系统的全局的隔离级别:
set global transaction isolation level read committed;
【4】事务的其他属性
①事务的回滚属性
默认情况下只有未检查异常(RuntimeException和Error类型的异常)会导致事务回滚,⽽受检查异常不会。
事务的回滚规则可以通过 rollbackFor 和 noRollbackFor 属性来定义. 这两个属性被声明为 Class[] 类型
的, 因此可以为这两个属性指定多个异常类.
rollbackFor:遇到时必须进⾏回滚织梦cms收费对普通人的影响
noRollbackFor:⼀组异常类,遇到时必须不回滚
rollbackFor={UserAccountException.class},
noRollbackFor={ArithMeticException.class}
②事务的超时和只读属性
由于事务可以在⾏和表上获得锁, 因此长事务会占⽤资源, 并对整体性能产⽣影响。
如果⼀个事物只读取数据但不做修改, 数据库引擎可以对这个事务进⾏优化。
超时事务属性: ( timeout=millons )事务在强制回滚之前可以保持多久。这样可以防⽌长期运⾏的事务占⽤资源。
只读事务属性:(readOnly=true/false) 表⽰这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务。
【5】MySQL如何避免脏读、不可重复读和幻读?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论