版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzw2312/article/details/81030277
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
* 注解声明式事务
* @author 胡汉三
*
* 2018年7月11日 下午2:52:49
*/
@Configuration
public class TxConfig {
/*事务拦截类型*/
@Bean("txSource")
public TransactionAttributeSource transactionAttributeSource(){
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
/*只读事务,不做更新操作*/
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setReadOnly(true);
readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
/*当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务*/
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED,
Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
requiredTx.setTimeout(5);
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("add*", requiredTx);
txMap.put("save*", requiredTx);
txMap.put("insert*", requiredTx);
txMap.put("update*", requiredTx);
txMap.put("edit*", requiredTx);
txMap.put("del*", requiredTx);
txMap.put("get*", readOnlyTx);
txMap.put("load*", readOnlyTx);
txMap.put("find*", readOnlyTx);
txMap.put("query*", readOnlyTx);
source.setNameMap( txMap );
return source;
}
/**切面拦截规则 参数会自动从容器中注入*/
@Bean
public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor){
AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();
pointcutAdvisor.setAdvice(txInterceptor);
pointcutAdvisor.setExpression("execution (* com.deeps.gzsti.service.*.impl.*.*(..))");
return pointcutAdvisor;
}
/*事务拦截器*/
@Bean("txInterceptor")
TransactionInterceptor getTransactionInterceptor(PlatformTransactionManager tx){
return new TransactionInterceptor(tx , transactionAttributeSource()) ;
}
}
上面是事务管理的配置,而后在我一个service.impl类中进行了一条正确的插入,一条错误的插入,发现每次都会往数据库中插入数据,明明报错了就是不回滚。
public boolean saveRole(Role role) throws Exception{
// TODO Auto-generated method stub
roleMapper.saveRole(role);
return roleMapper.saveRole(role);
}
因为编码是唯一键,重复插入会报错。刚刚开始以为是tx切面没有切到,后来搜索了一下才发现是shiro在启动配置的时候Spring还没启动。
解决办法:
新建一个spring的监听来设置realm。
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* spring初始化完成后设置自己的realm
* @author 胡汉三
*
* 2018年7月13日 下午1:49:37
*/
@Component
public class SpringEventListener {
@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
DefaultWebSecurityManager manager = (DefaultWebSecurityManager) context.getBean("securityManager");
AuthorizingRealm realm = (AuthorizingRealm) context.getBean("authRealm");
realm.setCredentialsMatcher(new CredentialsMatcher());
manager.setRealm(realm);
}
}
并且一定要注释掉原来shiro配置里面的realm:
@Bean(name="securityManager")
public SecurityManager securityManager() {
System.err.println("--------------shiro已经加载----------------");
DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
//manager.setRealm(authRealm);
// 自定义缓存实现 使用redis
manager.setCacheManager(cacheManager());
// 自定义session管理 使用redis
manager.setSessionManager(SessionManager());
//记住我
manager.setRememberMeManager(rememberMeManager());
return manager;
}
一定要注释shiro配置类中securityManager里面的manager.setRealm。这样事务就正常了!当然数据库要注意一些数据库引擎是否支持事务!