Spring事务管理:事务应该在service层统一控制
开发步骤:
编程式事务控制:可以实现细粒度的事务控制,但是开发效率较低,且事务管理和代码耦合度高
Jdbc:conn.setAutoCommit(false);
Hibernate:Session.beginTransaction();
声明式事务控制:Spring提供的对事物的管理,当不需要细粒度事务管理时,可以通过配置文件来实现。基于AOP,实现了事务控制和代码的解耦。但是不能实现对某个方法中特定几行代码应用事务,是粗粒度的事务控制。(AOP拦截的是方法)
事务管理器类:
Jdbc技术:DataSourceTransactionManager;
Hibernate技术:HibernateTransactionManager;
因此,对DeptService中的所有方法实现了事务管理,切面类由“org.springframework.jdbc.datasource.DataSourceTransactionManager”实现,save()方法中执行到int i = 1/0;抛出异常,事务回滚,数据库中没有变化。如果不配置事务管理,数据库中会存入一条数据!
public class DeptService {
private DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
public void save(Dept dept){
deptDao.save(dept);
int i=1/0;//异常:java.lang.ArithmeticException: / by zero
deptDao.save(dept);
}
}
配置:
在Service中对需要应用事务管理的方法,或者类注解(类中所有方法都应用Spring声明式事务管理)即可。
特殊情况可以定义在父类上,执行父类中的方法时,应用事务。
@Service
public class DeptService {
@Resource
private DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
@Transactional
public void save(Dept dept){
deptDao.save(dept);
int i=1/0;
deptDao.save(dept);
}
}
@Transactional(
readOnly=false //只读状态,优化查询
,timeout=-1//超时时间,-1表示不限制,最终是由数据库底层配置起作用的,这里设置不一定起作用
,noRollbackFor=ArithmeticException.class//遇到数学异常,不回滚
,isolation=Isolation.DEFAULT//事务隔离级别,数据库默认
,propagation=Propagation.REQUIRED//事务传播行为,当前方法时是否需要在事务中执行
//Propagation.REQUIRED :当前运行的方法中,如果存在子事务,会与现有事务合并;
//Propagation.REQUIRED_NEW :当前运行的方法中,如果存在子事务,当前事务挂起,执行完子事务后,再执行该事务,自事务和现有事务不相互影响;
)
一句话:被Propagation.REQUIRED_NEW属性修饰的事务,事务不受别人影响。案例:
新建一组service和dao,用于dept表操作的日志:
建表:
CREATE TABLE t_logInfo(
content VARCHAR(20)
);
dao:
@Repository
public class LogDao {
@Resource
private JdbcTemplate jdbcTemplate;
public void insert(){
jdbcTemplate.update("insert into t_logInfo values('saving into log!!!');");
}
}
service:
@Service
public class LogService {
@Resource
private LogDao logDao;
@Transactional(propagation=Propagation.REQUIRED)
public void insert(){
logDao.insert();
}
}
修改DeptService:
@Service
public class DeptService {
@Resource
private DeptDao deptDao;
@Resource
private LogService logService;
@Transactional
public void save(Dept dept){
logService.insert();
int i=1/0;
deptDao.save(dept);
}
}
由于logService的事务传播行为定义为“propagation=Propagation.REQUIRED”,即,事务存在传播行为;因此,数据插入不成功时,日志也不记录。如果修改日志插入的事务传播行为:
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void insert(){
logDao.insert();
}
则,日志成功记录,即使数据没有成功保存。