spring 事务管理器,由spring来负责数据库的打开,提交,回滚 .
一致的编程模型,管理不同的事务API,例如:
- JTA(Java Transaction API)
- JDBC
- Hibernate
- JPA(Java Persistence API和JDO(Java Data Objects)
@Transactional 可以作用于接口、接口方法、类以及类方法上。
Spring团队不建议在【接口】上使用@Transactional 注解。
因为在如果基于类的代理使用,事务定义会被绕过。(基于接口的代理不会出现这种情况)
当标于类前时, 标示类中所有方法都进行事物处理 , 例子:
@Transactional public class TestServiceBean implements TestService {}
默认遇到"运行时例外"会回滚,即遇到不受检查(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("注释");
}
属性名称 | 作用说明 | 参数 |
---|---|---|
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(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 | 串行化 , 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。 | 但是这将严重影响程序的性能。通常情况下也不会用到该级别。 |
**脏读 **
一个事务读取到另一事务未提交的更新数据
幻读
一个事务读到另一个事务已提交的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);
}