Spring事务管理分为声明式事务管理和编程式事务管理,声明式事务管理又分为xml和注解两种配置方式。应该优先选择声明式事务,因为声明式事务对程序代码的影响最小,因此最符合非侵入式轻量级容器的理想 。只有在进行少量事务操作时,才应该选择编程式事务管理的方式。
声明式事务管理
xml配置方式
Spring配置文件:
${jdbc_driverClassName}
${jdbc_url}
${jdbc_username}
${jdbc_password}
config.properties:
jdbc_driverClassName=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://192.168.1.77:3306/testdb?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
jdbc_username=root
jdbc_password=root
UserService.java:
public class UserService {
private JdbcTemplate jdbcTemplate;
public void addUser(String name, int age){
jdbcTemplate.update("insert into test007 (name,age) values (name,age)", name, age);
}
public void updateUserName(String name, int id){
jdbcTemplate.update("update test007 set name=? where id=?", name, id);
}
public void updateUserAge(int age, int id){
jdbcTemplate.update("update test007 set age=? where id=?", age, id);
}
public void updateUser(String name, int age, int id){
updateUserName(name, id);
//模拟异常
Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
updateUserAge(age, id);
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
main方法:
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.updateUser("小王", 18, 1);
}
使用注解方式
Spring配置文件中添加:
然后在需要事务管理的方法上添加@Transactional注解
@Transactional
public void updateUser(String name, int age, int id){
updateUserName(name, id);
//模拟异常
Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
updateUserAge(age, id);
}
注意:注解方式和xml方式可以二选一,也可以结合使用,两者没有依赖关系。
异常捕获和回滚
异常捕获会导致事务机制失效,继而不会触发回滚。
可以调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手动回滚。
@Transactional
public void updateUser(String name, int age, int id){
try{
updateUserName(name, id);
//模拟异常
Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
updateUserAge(age, id);
}catch(NumberFormatException ex){
//手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
ex.printStackTrace();
}
}
非RuntimeException时回滚
Spring事务管理机制默认只在抛出RuntimeException时才会触发回滚,可以设置rollbackFor属性来指定其他类型的异常也能回滚。
//rollbackFor指定抛出Exception类型异常时回滚
@Transactional(rollbackFor=Exception.class)
public void updateUser(String name, int age, int id) throws Exception{
updateUserName(name, id);
if(id == 1){
throw new Exception("Id为1的用户不可修改");
}
updateUserAge(age, id);
}
编程式事务管理
修改Spring配置文件:
修改UserService:
private TransactionTemplate transactionTemplate;
public void updateUser(final String name, final int age, final int id){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateUserName(name, id);
//模拟异常
Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
updateUserAge(age, id);
}
});
}
public TransactionTemplate getTransactionTemplate() {
return transactionTemplate;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}