什么是事务?
在数据库中,所谓事务是指一组逻辑操作单元即一组sql语句,当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交。判断事务是否配置成功的关键点在于出现异常时事务是否会回滚。
二、事务的特性(ACID)
1.原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2.一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)
3.隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰。
4.持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,即使系统重启也不会丢失。
在JDBC中,事务默认是自动提交的,每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
为了让多个SQL语句作为一个事务执行:
(1)执行语句前调用Connection对象的setAutoCommit(false);以取消自动提交事务。
(2)在所有的SQL语句都成功执行后,调用commit();方法提交事务。
(3)在出现异常时,调用rollback();方法回滚事务。
三、事务的隔离级别
事务的隔离性,当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性;
在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种问题:
1,脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
2,不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3,虚读(幻读)
幻读是事务非独立执行时发生的一种现象。
系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
四、MySQL数据隔离级别
现在来看看MySQL数据库为我们提供的四种隔离级别:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
五、事务传播特性
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
-
- propagation_requierd:方法被调用时,如果没有事务覆盖则自动开启事务,如果已经在事务范围内则使用外层提供的事务,
无论调用了多少个方法,都使用同一个事务,只要有一个方法出现异常,则全部回滚,否则开启新事务。 - propagation_requires_new:无论之前有没有开启事务自身都会单独开启新的事务,开启的每个事务出现异常时只会影响自己的事务。
- propagation_supports:自身不会开启事务,如果在事务范围内则使用外层方法提供的事务,否则不使用事务,当不使用事务时Mysql会自动提交,Oracle不会。
- propagation_not_supported:自身不会开启事务,在事务范围内使用,自身挂起事务(但是如果出现异常会影响外层的事务),运行完毕恢复事务。
- propagation_mandatory:自身不开启事务,必须在事务环境使用否则报错。
- propagation_never:自身不会开启事务,在事务范围使用抛出异常。
- propagation_nested:如果一个活动的事务存在,则运行在一个嵌套的事务中(会使用外层提供的事务),如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。
- propagation_requierd:方法被调用时,如果没有事务覆盖则自动开启事务,如果已经在事务范围内则使用外层提供的事务,
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。