2017-12-25 17 views
1

ここで、SpringBootおよびMyBatisアプリケーションでAOPによる動的データソースを使用するようにします。しかし、AOPはデータベースからのクエリの後に常に実行されるため、selectが完了しているため、スイッチのデータソースは無効です。SpringBootでAOP、WebBatisで動的データソース用のアプリケーションが常に実行されています

すべての私のコードは私の依存性は

compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1') 
compile('org.springframework.boot:spring-boot-starter-web') 
compile('org.springframework.boot:spring-boot-starter-aop') 
runtime('mysql:mysql-connector-java') 

あるhttps://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/aspect_dao

にあり、application.properties

application.server.db.master.driver-class-name=com.mysql.jdbc.Driver 

application.server.db.master.url=jdbc:mysql://localhost/redisapi?useSSL=false 
application.server.db.master.port=3306 
application.server.db.master.username=root 
application.server.db.master.password=ihaveapen*^@# 
#application.server.db.master.database=123456 
# 
## application common config 
application.server.db.slave.driver-class-name=com.mysql.jdbc.Driver 
application.server.db.slave.url=jdbc:mysql:/localhost/redisapi2?useSSL=false 
application.server.db.slave.port=3306 
application.server.db.slave.username=root 
application.server.db.slave.password=123456 
#application.server.db.slave.database=redisapi 

mybatis.type-aliases-package=cn.com.hellowood.dynamicdatasource.mapper 
mybatis.mapper-locations=mappers/**Mapper.xml 

CREATE TABLE product(
    id INT PRIMARY KEY AUTO_INCREMENT, 
    name VARCHAR(50) NOT NULL, 
    price DOUBLE(10,2) NOT NULL DEFAULT 0 
); 

DataSourceConfig ur.java

package cn.com.hellowood.dynamicdatasource.configuration; 

    import org.mybatis.spring.SqlSessionFactoryBean; 
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; 
    import org.springframework.boot.context.properties.ConfigurationProperties; 
    import org.springframework.context.annotation.Bean; 
    import org.springframework.context.annotation.Configuration; 
    import org.springframework.context.annotation.Primary; 
    import org.springframework.jdbc.datasource.DataSourceTransactionManager; 
    import org.springframework.transaction.PlatformTransactionManager; 

    import javax.sql.DataSource; 
    import java.util.HashMap; 
    import java.util.Map; 

    @Configuration 
    public class DataSourceConfigurer { 


     @Bean("master") 
     @Primary 
     @ConfigurationProperties(prefix = "application.server.db.master") 
     public DataSource master() { 
      return DataSourceBuilder.create().build(); 
     } 


     @Bean("slave") 
     @ConfigurationProperties(prefix = "application.server.db.slave") 
     public DataSource slave() { 
      return DataSourceBuilder.create().build(); 
     } 


     @Bean("dynamicDataSource") 
     public DataSource dynamicDataSource() { 
      DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource(); 
      Map<Object, Object> dataSourceMap = new HashMap<>(2); 
      dataSourceMap.put("master", master()); 
      dataSourceMap.put("slave", slave()); 

      // Set master datasource as default 
      dynamicRoutingDataSource.setDefaultTargetDataSource(master()); 
      // Set master and slave datasource as target datasource 
      dynamicRoutingDataSource.setTargetDataSources(dataSourceMap); 

      // To put datasource keys into DataSourceContextHolder to judge if the datasource is exist 
      DynamicDataSourceContextHolder.dataSourceKeys.addAll(dataSourceMap.keySet()); 
      return dynamicRoutingDataSource; 
     } 


     @Bean 
     @ConfigurationProperties(prefix = "mybatis") 
     public SqlSessionFactoryBean sqlSessionFactoryBean() { 
      SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); 
      // Here is very important, if don't config this, will can't switch datasource 
      // put all datasource into SqlSessionFactoryBean, then will autoconfig SqlSessionFactory 
      sqlSessionFactoryBean.setDataSource(dynamicDataSource()); 
      return sqlSessionFactoryBean; 
     } 


     @Bean 
     public PlatformTransactionManager transactionManager() { 
      return new DataSourceTransactionManager(dynamicDataSource()); 
     } 
    } 

DynamicRoutingDataSource.java

package cn.com.hellowood.dynamicdatasource.configuration; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 

public class DynamicRoutingDataSource extends AbstractRoutingDataSource { 

    private final Logger logger = LoggerFactory.getLogger(getClass()); 

    @Override 
    protected Object determineCurrentLookupKey() { 
     logger.info("Current DataSource is [{}]", DynamicDataSourceContextHolder.getDataSourceKey()); 
     return DynamicDataSourceContextHolder.getDataSourceKey(); 
    } 
} 
  • DynamicDataSourceContextHolder.java

    package cn.com.hellowood.dynamicdatasource.configuration; 
    
    import java.util.ArrayList; 
    import java.util.List; 
    
    public class DynamicDataSourceContextHolder { 
    
    
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>() { 
         @Override 
         protected String initialValue() { 
          return "master"; 
         } 
        }; 
    
    
        public static List<Object> dataSourceKeys = new ArrayList<>(); 
    
    
        public static void setDataSourceKey(String key) { 
         contextHolder.set(key); 
        } 
    
    
        public static String getDataSourceKey() { 
         return contextHolder.get(); 
        } 
    
    
        public static void clearDataSourceKey() { 
         contextHolder.remove(); 
        } 
    
    
        public static boolean containDataSourceKey(String key) { 
         return dataSourceKeys.contains(key); 
        } 
    } 
    
  • DynamicDataSourceAspect.java

    package cn.com.hellowood.dynamicdatasource.configuration; 
    
    import org.aspectj.lang.JoinPoint; 
    import org.aspectj.lang.annotation.After; 
    import org.aspectj.lang.annotation.Aspect; 
    import org.aspectj.lang.annotation.Before; 
    import org.aspectj.lang.annotation.Pointcut; 
    import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory; 
    import org.springframework.core.annotation.Order; 
    import org.springframework.stereotype.Component; 
    
    
    @Aspect 
    @Order(-100) // To ensure execute before @Transactional 
    @Component 
    public class DynamicDataSourceAspect { 
    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class); 
    
    private final String QUERY_PREFIX = "select"; 
    
    @Pointcut("execution(* cn.com.hellowood.dynamicdatasource.mapper.*.*(..))") 
    public void daoAspect() { 
    } 
    
    
    @Before("daoAspect()") 
    public void switchDataSource(JoinPoint point) { 
        if (point.getSignature().getName().startsWith(QUERY_PREFIX)) { 
         DynamicDataSourceContextHolder.setDataSourceKey("slave"); 
         logger.info("Switch DataSource to [{}] in Method [{}]", 
           DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature()); 
        } 
    } 
    
    
    @After("daoAspect())") 
    public void restoreDataSource(JoinPoint point) { 
        DynamicDataSourceContextHolder.clearDataSourceKey(); 
        logger.info("Restore DataSource to [{}] in Method [{}]", 
          DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature()); 
    } 
    

    }

とは、クエリのためのコントローラ、サービスとダオを持っている、しかし、私は-100としての側面の順序を設定するものの、それはまだAOPの前にクエリを実行し、間違っているところ誰でも見つけることができる、どうもありがとうございました。 This is log screenshot

答えて

0

最後に、DataSourceTransactionManagerのBeanを注入したため、トランザクションがサービスでオープンされるため、DAOの側面はトランザクションが終了するまで機能しません。

@Bean 
public PlatformTransactionManager transactionManager() { 
    return new DataSourceTransactionManager(dynamicDataSource()); 
} 

このコードを削除します。

関連する問題