Spring注解,@Transactional

@Transactional 事务注解

spring 事务管理器,由spring来负责数据库的打开,提交,回滚 .

一致的编程模型,管理不同的事务API,例如:
- JTA(Java Transaction API)
- JDBC
- Hibernate
- JPA(Java Persistence API和JDO(Java Data Objects)

一、 定义 & 触发

@Transactional 定义

@Transactional 可以作用于接口、接口方法、类以及类方法上。

Spring团队不建议在【接口】上使用@Transactional 注解。

因为在如果基于类的代理使用,事务定义会被绕过。(基于接口的代理不会出现这种情况)

当标于类前时, 标示类中所有方法都进行事物处理 , 例子:

@Transactional public class TestServiceBean implements TestService {}

@Transactional 触发

默认遇到"运行时例外"会回滚,即遇到不受检查(unchecked)的例外时回滚;

默认情况:

throw new RuntimeException("") ; 会,触发回滚
thorw new Exception(""); 不会,触发回滚

指定回滚:

@Transactional(rollbackFor=Exception.class)
public void methodName() {
   throw new Exception("...");
}

指定不回滚

@Transactional(noRollbackFor=Exception.class)
public ItimDaoImpl getItemDaoImpl() { 
    throw new Exception("注释");
}

@Transactional 属性

属性名称 作用说明 参数
robackFor 指定触发回滚,的异常类型 @Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName 指定触发回滚的,异常类名称(多选)
noRollbackFor 那些异常类,不需要回滚 @Transactional(noRollbackFor=RuntimeException.class)
timeout 超时(秒数 ) 默认 -1 永不超时
readOnly 开启只读事务 @Transactional(readOnly=true)
propagation 事务的传播特性 @Transactional(propagation=Propagation.NOT_SUPPORTED)
isolation 事务隔离特性

@Transactional 特性

  1. 触发特性
  2. public 特性, 只能被用于 public 方法上,其他类型不生效。
  3. 传播特性
  4. 隔离级别
  5. 事务超时

二、事务传播特性

@Transactional(propagation=Propagation.REQUIRED)
模式 说明
REQUIRED 默认 如果有事务, 那么加入事务, 没有的话新建一个
REQUIRES_NEW 始终创建 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
MANDATORY 追随 必须在一个已有的事务中执行,否则抛出异常
NEVER 排他 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
NOT_SUPPORTED 忽略 容器不为这个方法开启事务
SUPPORTS 支持者 如果其他 bean 调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.

三、事务隔离级别

@Transactional (isolation=Isolation.DEFAULT)
说明 补充
ISOLATION_DEFAULT 默认值 ,使用底层数据库的默认隔离级别。 大部分数据库,该值等于 ISOLATION_READ_COMMITTED
ISOLATION_READ_UNCOMMITTED 可以读取另一个事务修改,未提交的数据。 会出现:脏读、幻读、不可重复读。因此很少使用。比如PostgreSQL实际上并没有此级别。
ISOLATION_READ_COMMITTED 只能读取另一个事务已经提交的数据。 可以防止脏读,这也是大多数情况下的推荐值。(会出现不可重复读和幻读)
ISOLATION_REPEATABLE_READ 该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。 该级别可以防止脏读和不可重复读。(会出现幻读)
ISOLATION_SERIALIZABLE 串行化 , 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。 但是这将严重影响程序的性能。通常情况下也不会用到该级别。

数据库,默认隔离级别

  • MYSQL , 默认为REPEATABLE_READ级别
  • SQLSERVER:, 默认为READ_COMMITTED

脏读 & 幻读

**脏读 **
一个事务读取到另一事务未提交的更新数据

幻读
一个事务读到另一个事务已提交的insert数据

不可重复读
在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据

四、事务超时

@Transactional (timeout=30)

事务超时,指一个事务所允许执行的最长时间,如果超过该时间但事务还没有完成,则自动回滚事务。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

五、编程式事务 & 声明式事务

spring支持编程式事务管理和声明式事务管理两种方式。

编程式事务管理使用 TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

六、源码 & 实现

spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

public interface PlatformTransactionManager {
     

  TransactionStatus getTransaction(TransactionDefinition definition)
    throws TransactionException;

  void commit(TransactionStatus status) throws TransactionException;

  void rollback(TransactionStatus status) throws TransactionException;
}

org/springframework/jdbc/datasource/DataSourceTransactionManager.java

// switch to manual commit if necessary. this is very expensive in some jdbc drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getautocommit()) {
     
    txobject.setmustrestoreautocommit(true);
    if (logger.isdebugenabled()) {
     
        logger.debug("switching jdbc connection [" + con + "] to manual commit");
    }
    con.setautocommit(false);
}

参考

  • http://www.blogjava.net/zhaoguo543166/articles/373912.html
  • https://www.cnblogs.com/yepei/p/4716112.html

你可能感兴趣的:(spring)