spring boot shiro 事务无效

版权声明:本文为博主原创文章,未经博主允许不得转载。 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。这样事务就正常了!当然数据库要注意一些数据库引擎是否支持事务!



猜你喜欢

转载自blog.csdn.net/hzw2312/article/details/81030277