首先你要注意的是你的sql语句是不是create table等ddl语句 有:CREATE DATABASE,CREATE TABLE,ALTER TABLE ,DROP TABLE,CREATE VIEW,ALTER VIEW ,DROP VIEW 等
如果是这样的,事务是不会生效的!!!!
一.事务不生效
1.访问权限的问题
如果我们在开发过程中,把有事务的方法定义了错误的权限,就会导致事务功能出错。众所周知,spring要求被代理的方法必须是public的。说白了,在AbstrctFallbackTransactionAttributedSource类的computeTransactionAttribute方法中有个判断,如果目标不是public则TransactionAttribute返回的是空
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
if (this.allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
} else {
Class<?> userClass = ClassUtils.getUserClass(targetClass);
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
TransactionAttribute txAttr = this.findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
} else {
txAttr = this.findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
} else {
if (specificMethod != method) {
txAttr = this.findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
txAttr = this.findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
}
}
}
2.方法被final修饰
spring事务底层使用的是aop,也就是哦通过jdk动态代理或者cglib动态代理,如果某个方法使用final修饰后,在代理类中就无法重写。
3,方法内部调用
比如在service某个事务方法中调用了另外一个事务方法。事务会失效
public void doSomeThing() {
Random random = new Random();
Integer s = random.nextInt(100);
Mamber mamber = new Mamber(s, "zhangsan", "123");
mamberMapper.saveData(mamber);
int i =1/0;
updateData(mamber);
}
@Transactional
public void updateData(Mamber mamber){
mamber.setName("lisi");
mamberMapper.updateData(mamber);
}
是因为在调用updateData的时候,用了this对象的方法,又因为是动态代理,所以updateData不会生成事务.
((Service)AopContext.currentProxy()).updateData(mamber);
4.没有写@Service 就是没有被Spring管理
5.多线程调用
因为不同的线程调用的是不同的数据库链接,这个数据库连接是用ThreadLocal保存的, 多个线程会有多个ThreadLocal,所以链接不同了,事务也就失效了
6.表不支持事务 比如MyISAM
7.未使用@Transactional注解
二.事务不回滚
1.错误的传播特性
spring支持7种传播特性
REQUIRED 如果当前上下文存在事务,那么加入该事务,不存在事务就创建一个事务(默认)
SUPPORTS 如果当前上下文存在事务,则支持事务加入事务,如果不存在事务,就使用非事务的方式执行
MANDATORY 如果当前上下文存在事务,否认抛出异常
NOT_SUPPORTS 如果当前上下文存在事务,则挂起当前事务,然后新的方法在没有事务的环境下执行
NEVER 如果上下文存在事务则抛出异常,否则在无事务环境上执行代码
NESTED 如果上下文存在事务,则嵌套事务执行,如果不存在事务,则新建事务
2.自己吞了异常
事务不回滚 可能是开发者在代码中手动try catch了异常
3.手动抛出别的异常
即使开发者没有手动捕获异常,但是如果抛出的异常不正确,spring事务也不会回滚
默认情况下只会回滚RuntimeException 和Error。对于普通异常不会回滚
4.自定义异常
在使用@Transactional注解生命十五是,有时候我们想自定义回滚的异常,spring也是支持的,可以通过设置rollbackFor参数来完成这个功能
rollBack默认值是UncheckdException包括RuntimeException和Error
所以建议设置成Exception或者Throwable.
5.嵌套事务回滚多了
还是上面事务方法调用了另一个事务方法,但是我不想让第一个事务方法中回滚,那么只需要在另一个事务方法中手动捕获异常就可以了