什么是事务
事物就是一组原子性的sql查询,要么全部成功,要么全部失败。最经典的就是银行转账的例子,比如A向B转1000块,A这边显示扣费成功,但是B却没有收到钱,这种情况是肯定不能发生的,所以必须要保证A转钱成功和B收钱成功这两个动作是同时成功,或者同时失败的。
事务的四大特性
原子性:一个事物的操作是原子性的,要么全部成功,要么全部失败,如果事物出错,就会回滚到事物之前的状态。
一致性:事物开始前后,数据库的完整性约束没有被破坏,数据库从一个一致的状态转变成另一个一致的状态。例如:A向B转钱,不能A扣钱了,B却没收到钱。
隔离性:同一时间只允许一个事物请求这一个数据,不同的事物之间彼此没有干扰。例如A在取钱的过程中,B不能向这张卡里转账。
持久性:事物一旦结束,对数据库的操作永久性的保存到数据库中,即便数据库崩溃,也可以通过日志文件进行恢复。
事务的并发问题
脏读(Dirty reads):一个事物读取了另一个事物未提交的数据。
不可重复读(Nonrepeatable read):事物A多次读取一条数据,事物B在A读取的过程中,对数据做出了修改并提交(不提交A读取不到),导致事物A多次读取同一条数据时,结果不一致
幻读(Phantom read):事物A多次读取一条数据,事物B在A读取的过程中,读数据做出了添加并提交(不提交A读取不到),导致事物A多次读取同一条数据时,结果不一致(多了一条数据,出现了幻读)。
事务的隔离级别
读未提交 read-uncommitted 会出现脏读,不可重复读,幻读 最不安全,效率最高
读已提交 read-committed 会出现不可重复读,幻读 oracle默认
可重复读 repeatable-read 会出现幻读,mysql默认 (实际上mysql中mvcc机制解决了幻读问题)
串行化 serializable 都不会出现,这是最安全的,效率最低(相当于排队)
mysql8.0查看事物的默认隔离级别:select @@transaction_isolation;
mysql8.0之前查看事物的默认隔离级别:select @@tx_isolation;
设置事物的隔离级别 set transaction_isolation = ‘事物隔离级别’;
spring的声明式事务
1、Spring的声明式事务管理在底层是建立在AOP的基础上。其本质是在方法前后进行拦截,然后在目标方法开始之前创建一个事务,在执行这目标方法结束后,根据执行情况提交或进行回滚事务。
2、声明式事务最大的优点就是不需通过编程的方式而进行管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明,便可将事务规则应用到业务逻辑中。
3、声明式事务不足的地方在于,与编程式事务相比,只能作用到方法级别,无法像编程式事务那样可以作用到代码块级别
spring事务的传播机制
PROPAGATION_REQUIRED:表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务(spring默认的传播机制)
PROPAGATION_SUPPORTS:表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
PROPAGATION_MANDATORY:表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
PROPAGATION_REQUIRED_NEW:表示当前方法必须运行在它自己的事务中。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
PROPAGATION_NOT_SUPPORTED:表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。
PROPAGATION_NEVER:表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
PROPAGATION_NESTED:表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。
spring事务的隔离级别
DEFAULT(-1), 和数据库隔离级别相同
READ_UNCOMMITTED(1), 读取未提交
READ_COMMITTED(2), 不可重复读
REPEATABLE_READ(4), 可重复读
SERIALIZABLE(8); 串行化
spring事物是否只读
如果一个事务只对后端数据库执行读操作,那么该数据库就可能利用那个事务的只读特性。
开启只读 @Transactional(readOnly = true)
spring事物的超时机制
假设事务的运行时间变得格外的长,由于事务可能涉及对后端数据库的锁定,所以长时间运行的事务会不必要地占用数据库资源。这时就可以声明一个事务在特定秒数后自动回滚,不必等它自己结束
@Transactional(timeout = 10)
spring事物的回滚规则
它们定义哪些异常引起回滚,哪些不引起。在默认设置下,事务只在出现运行时异常回滚,而在出现编译期异常时不回滚。不过,也可以声明在出现特定受检查异常时像运行时异常一样回滚。同样,也可以声明一个事务在出现特定的异常时不回滚
@Transactional(rollbackFor = XXX.class,noRollbackFor = XXX.class)