手工控制事务
Hibernate的事务操作:
public void save(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Info info = new Info("ezbcw");
info.setContent("ezbcw");
session.save(info );
session.getTransaction().commit();
}
JDBC的事务操作:
Connection conn = null;
try {
.......
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.executeUpdate("update person where name='叶天'");
conn.commit();
.....
} catch (Exception e) {
conn.rollback();
} finally{
conn.close();
}
使用Spring, 我们就不再需要手工控制事务
public class Bean1 {
@Transactional(propagation=Propagation.Required)
public void update(){
executeUpdate(“update account set amount=? where id=?");
}
}
Spring中Propagation类的事务属性详解:
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
ServiceA {
/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodB() {
}
}
PROPAGATION_REQUIRED
最常见的选择,默认就是这个。
如果当前正要执行的事务不在另外一个事务里,那么就起一个新的事务。
如果当前正要执行的事务已经在另一个事务中,那么就公用另一个事务。
第一个场景
ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候, ServiceA.methodA开启事务,这时调用ServiceB.methodB,
ServiceB.methodB看到自己已经运行在ServiceA.methodA的事务内部,就不再起新的事务。
第二个场景
ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。
就算ServiceB.methodB已经执行完,但是ServiceA.methodA在接下来抛异常要回滚,ServiceB.methodB也要回滚。
PROPAGATION_REQUIRES_NEW
ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,
ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,
那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,他才继续执行。
他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。
因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。
如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。
如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。
Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚。