分布式事务中是否可以有加锁解锁的逻辑?可以,但是不规范的话会有线程安全问题。
下方逻辑:在解锁后,并发线程会再执行一遍锁里的逻辑,因为此时事务未提交,在隔离级别不是read uncommited的情况下,都读取不到原线程insert的数据,所以并发线程会再次insert数据;
这种情况是对于线程执行的原子性进行了割裂;
解决:对事务进行加锁,而不是放到内层;但是因为在加锁与解锁的过程中,中间事务的逻辑耗时大的话,会导致获取锁失败的异常变多。
思考:修改操作会不会有问题?不会,因为数据库对修改就是加锁的,并且也就不用加锁;
public void method(){
transactionTemplate.execute(new TransactionCallback<T>(){
public T doInTransaction(TransactionStatus status){
lock(){
object = query();
if(null == object){
insert;
}
}
//解锁后逻辑
...
return T;
}
});
}
spring声明式事务失效的场景
spring声明式事务失效的场景:(大部分是由于spring事务的机制,通过aop动态代理对方法重写,通过数据库连接来实现)
- 修饰符造成失效;
a. 非public的权限修饰符,会直接返回null
b. static静态修饰符
c. final修饰符,导致不能被重写 - 事务方法被没有事务的方法调用;还是由于spring事务的机制;
a. 在类中注入自己本身,并调用该事务方法;
b.使用AopContext.currentProxy() 去获得对应的代理对象去调用事务方法; - 类未被spring管理,即没有在容器中初始化类对象;注解 或xml配置;
- 多线程调用:新启了一个线程去调用事务方法,该事务方法回滚,外层事务不会回滚(因为内层事务即线程跟外层用的不是用一个数据库连接;)
- 数据库不支持事务:如MyISAM
- 未开启事务;
- 使用错了事务(配置的传播特性不适合当前场景)propagation属性
- 手动catch了异常,并未抛出;或者抛出的异常不是运行异常或者error;
- 事务设置的回滚异常 与 运行时抛出的异常不一致,导致不会滚;(通常设置的回滚异常应为:Exception或 Throwable)rollbackFor属性
- 嵌套事务回滚多了:内层事务回滚影响外层事务(可以对内层事务的调用处捕获异常,且不抛出)
spring事务传播行为
- PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。
- 声明式事务的默认传播行为;
- PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
- 外层事务回滚,对内层事务没有影响;内层事务是独立的事务
- PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
解释:
- 嵌套事务:相当于父事务与子事务的概念;只有父事务提交了,子事务才会被提交;父事务回滚了,子事务也会回滚;
spring事务隔离级别
- ISOLATION_DEFAULT -- 使用数据库默认的隔离级别,mysql为REPEATABLE_READ,oracle为READ_COMMITTED
- ISOLATION_READ_UNCOMMITTED -- 最低的隔离级别,会出现脏读、不可重复读、幻读;
- ISOLATION_READ_COMMITTED -- 会出现不可重复读,幻读;
- ISOLATION_REPEATABLE_READ -- 会出现幻读;
- ISOLATION_SERIALIZABLE -- 可串行化:最高的隔离级别,完全服从 ACID 的隔离级别。事务逐个执行,之间不会产生干扰;
spring事务超时时间
事务允许运行的最长时间,超过这个时间还没有执行完成,则会回滚;int类型,单位是s,默认值为-1;
spring事务只读属性
对于只有数据查询的事务,可以设置为只读属性;
问题:为什么全都是查询的逻辑还要加事务?
spring事务回滚规则
这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常(RuntimeException 的子类)时才会回滚,Error 也会导致事务回滚,但是,在遇到检查型(Checked)异常时不会回滚。
@Transactional
@Transactional注解中的属性在上面都已列出;
属性名 | 说明 |
---|---|
propagation | 事务的传播行为,默认值为 REQUIRED,可选的值在上面介绍过 |
isolation | 事务的隔离级别,默认值采用 DEFAULT,可选的值在上面介绍过 |
timeout | 事务的超时时间,默认值为-1(不会超时)。如果超过该时间限制但事务还没有完成,则自动回滚事务。 |
readOnly | 指定事务是否为只读事务,默认值为 false。 |
rollbackFor | 用于指定能够触发事务回滚的异常类型,并且可以指定多个异常类型。 |