什么是事务

事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。

数据库事务是保证在并发情况下能够正确执行的重要支撑,MySQL常见的数据库引擎中支持事务的是InnoDB。

事务就是一系列操作,正确执行并提交,如果中途出现错误就回滚。事务要保证能够正常的执行,就必须要保持ACID特性。

事务由单独单元的一个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条SQL语句一旦执行失败或产生错误,整个单元将会回滚。所有受到影响的数据将返回到事物开始以前的状态。如果单元中的所有SQL语句均执行成功,则事物被顺利执行。

1.事务的开始和结束
  • COMMIT 或ROLLBACK 语句

  • DDL 或DCL 语句(自动提交)

  • 用户会话正常结束

  • 系统异常终了

2. 执行DML需要手动开启和提交事务吗
 SHOW VARIABLES LIKE '%autocommit%';

对于DML数据操作,我们必须要记住提交事务,如果autocommit为1的话,当然就不用我们自己操心了!!数据库会帮我们提交的!!但是在我们的MyBatis持久层框架中,进行DML操作时我们必须要手动开启事务,并且手动提交事务!!因为在MyBatis持久层框架中,它们处理DML语句的时候会自动设置autocommit=0;如果DML中不进行手动提交事务,那么最后事务就会进行回滚。

为什么我们在写SSM项目的时候,不用手动提交呢?

org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(Object, TransactionDefinition)

3. 事务的四个特性

① 原子性(atomicity) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

事务是一个原子操作, 由一系列动作组成。 组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交。

事务中的任何一个数据库操作失败,已经执行的任何操作都必须被撤销,让数据库返回初始状态。

② 一致性(consistency) 事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

一旦所有事务动作完成, 事务就被提交。数据和资源就处于一种满足业务规则的一致性状态,即数据不会被破坏。

比如a+b=100,一个事务改变了a比如增加了a的值,那么必须同时改变b,保证在事务结束以后a+b=100依然成立,这就是一致性。

③ 隔离性(isolation) 事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对对方产生干扰。准确地说,并非要求做到完全无干扰。

数据库规定了多种事务隔离级别,不同的隔离级别对应不用的干扰程度。隔离级别越高,数据一致性越好,但并发行越弱。

比如对于A对B进行转账,A没把这个交易完成的时候,B就不知道A要给他转多少钱。

④ 持久性(durability) 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。

数据库管理系统一般采用重执行日志来保证原子性、一致性和持久性。

重执行日志记录了数据库变化的每一个动作,数据库在一个事务中执行一部分操作后发生错误退出,数据库即可根据重执行日志撤销已经执行的操作。对于已经提交的事务即使数据库崩溃,在重启数据库时也能根据日志对尚未持久化的数据进行相应的重执行操作。

4. 事务的隔离机制

一个事务与其他事务隔离的程度称为隔离级别。

数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。

对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制,

就会导致各种并发问题。

隔离级别存在问题
READ UNCOMMITTED脏读、不可重复读、幻读
READ COMMITTED不可重复读、幻读
REPEATABLE READ幻读
SERIALIZABLE

① DEFAULT(读提交) 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。

另外四个与JDBC的隔离级别相对应。大部分数据库的默认级别都是READ_COMMITTED(读取已提交)。

② READ_UNCOMMITTED(读取未提交) 这是事务最低的隔离级别,允许当前事务读取未被其他事务提交的变更。

这种隔离级别会产生脏读,不可重复读和幻读。

产生脏读场景:A事务读取一个字段,但是这个字段被另外一个事务更新却未提交,

再次读取该字段时如果另外一个事务回滚则出现了脏读现象(读到的数据与第一次,

数据库中的数据都不同)。

产生不可重复读场景:A事务读取一个字段,但是这个字段被另外一个事务更新并提交,

再次读取该字段值不一样则出现了不可重复读现象(同一个事务中,不能保证读取的字段值相同)。

产生幻读场景:A事务读取一个字段集合,但是这个表被另外一个事务更新并提交(如插入了几行),

再次读取该表可能会多几行则出现了幻读现象。

③ READ_COMMITTED(读取已提交) 保证一个事务修改的数据提交后才能被另外一个事务读取,

另外一个事务不能读取该事务未提交的数据。可以避免脏读,但不可重复读和幻读的现象仍然可能出现。

不可重复读

A事务读取一个字段,但是这个字段被另外一个事务更新并提交,再次读取该字段值不一样则出现了不可重复读现象(同一个事务中,不能保证读取的字段值相同)。

举例就是对于一个数A原来是50,然后提交修改成100,这个时候另一个事务在A提交修改之前,
读取到了A是50,刚读取完,A就被修改成100了,这个时候另一个事务再进行读取发现A就突然变成100了
幻读

读取一个字段,但是这个表被另外一个事务更新并提交(如插入了几行),再次读取该表可能会多几行则出现了幻读现象。

④ REPEATABLE_READ(可重复读) 确保事务可以多次从某行记录的一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新。这种事务隔离级别可以防止脏读,不可重复读,但是可能出现幻读。

它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了在一个事务过程,

读取的数据不会发生变化(即使数据库中的数据在该事务过程中发生了变化)。

//如下代码所示,可重复读意味着两次读取字段A值相同!
​
public void test(){
    //开启事务
    //读取字段A;
    //此时数据库中A发生了变化;
    //读取字段A;
    //提交事务;
    //关闭事务;
}

⑤ SERIALIZABLE :(可串行化) 在并发情况下和串行化的读取的结果是一致的,没有什么不同。这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。但性能十分低下!

⑥ 什么是脏读、不可重复读和幻读? 脏读: 对于两个事务 T1, T2。T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的,也就是脏数据。

不可重复读:对于两个事务 T1, T2。 T1 读取了一个字段, 然后 T2 更新了该字段。之后, T1再次读取同一个字段, 值就不同了。

幻读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一些新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这些多出来的新纪录就是幻读。

不可重复读和幻读的区别:

不可重复读重点是在update,即事务前后对比特定数据内容的修改。而幻读是insert和delete,即事务前后数据结果集的对比。

Oracle数据库支持READ COMMITTED(默认) 和 SERIALIZABLE这两种事务隔离级别。所以Oracle不会出现脏读。

MySQL 支持 4 种事务隔离级别:READ_UNCOMMITTED(读取未提交),READ_COMMITTED(读取已提交),REPEATABLE_READ(可重复读-默认)和SERIALIZABLE (可串行化)。

Oracle 默认使用的是READ_COMMITTED。MySQL默认事务隔离级别为 REPEATABLE_READ。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值