注解的定义
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
...
}
根据元注解的定义,事务注解可以定义在类、接口、枚举、方法上 ,在日常的开发中一般写到service层(约定)
常见问题分析
- 在springboot项目中放在controller层是否起作用?
答案是:起作用。(但是约定不能这么做)
下方例子中:保存点A不报错,保存点B处报错,保存点A数据回滚(数据回滚,因为发生了运行时异常,rollbackFor默认回滚运行时异常或非受检异常,还有error级别异常)
/**
* controller层进行事务测试
*/
@RequestMapping("/tran")
//rollbackFor = {Exception.class} 此处其实不起作用,发生了运行时异常
@Transactional(rollbackFor = {Exception.class})
public void testTransaction(){
Dlzd dlzd = new Dlzd();
dlzd.setDlbh("99");
dlzd.setDlmc("test");
dlzdService.save(dlzd); // 保存点A
Dgd dgd = new Dgd();
dgd.setDdh("1111");
dgdService.save(dgd);// 保存点B
}
- @transactional 只有在public修饰的方法上起作用,protected,private不起作用?
答案是:正确的
下方例子中:保存点A不报错,保存点B处报错,保存点A数据不回滚,数据保存到了数据库中,证明注解不起作用
/**
* controller层进行事务测试
*/
@RequestMapping("/tran")
@Transactional(rollbackFor = {Exception.class})
protected void testTransaction(){
Dlzd dlzd = new Dlzd();
dlzd.setDlbh("99");
dlzd.setDlmc("test");
dlzdService.save(dlzd); // 保存点A
Dgd dgd = new Dgd();
dgd.setDdh("1111");
dgdService.save(dgd);// 保存点B
}
- @transactional 为什么建议加上rollbackfor = Exception.class?
答案是:注解默认回滚的是unchecked exception非受检的异常 ,runtimeException。受检的Exception,不进行事务的回滚,顾要加上
下方例子中:保存点A不报错,保存点B处报错,保存点A数据不回滚(没有加rollbackFor)
@RequestMapping("/test3")
@Transactional
public void testTransaction3() throws Exception{
Dlzd dlzd = new Dlzd();
dlzd.setDlbh("99");
dlzd.setDlmc("test");
dlzdService.save(dlzd); //保存点A
Dgd dgd = null;
try {
dgd = new Dgd();
dgd.setDdh("1111");
dgdService.save(dgd); //保存点B
} catch (Exception e) {
e.printStackTrace();
throw new Exception("test");
}
}
此处一开始测试时,使用了lombok的@SneakyThrows注解,数据照样回滚(原因是lombok捕获异常后抛出的仍然为runtimeException,故照样回滚)
@RequestMapping("/test3")
@Transactional
@SnekyThrows
public void testTransaction3(){
Dlzd dlzd = new Dlzd();
dlzd.setDlbh("99");
dlzd.setDlmc("test");
dlzdService.save(dlzd); //保存点A
Dgd dgd = null;
try {
dgd = new Dgd();
dgd.setDdh("1111");
dgdService.save(dgd); //保存点B
} catch (Exception e) {
e.printStackTrace();
throw new Exception("test");
}
}
@SnekyThrows