spring boot shiro 事務無效

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。這樣事務就正常了!當然數據庫要注意一些數據庫引擎是否支持事務!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章