Springboot統合mybatis、動的データソース構成
60917 ワード
このアイテムは、データ・クエリー・インタフェース・サービスです.ブラウザでurlにアクセスし、jsonパラメータを渡し、jsonデータを返します.springbootマイクロサービスで構築し、mybatisを統合し、データベースをクエリーします.データは2つのデータベースに保存されているため、プロジェクトではサービスによってクラスが存在するパッケージを実現したり、カスタム注釈によってデータソースを動的に切り替えたりします.次のように構成されています.
1.導入依存
2.springbootポータルクラス構成の開始
3.マルチデータソース構成3.1アプリケーション.propertiesプロファイルspringbootコアプロファイルとはresourcesルートディレクトリの下のアプリケーションを指す.propertiesまたはapplication.ymlプロファイル、ここでpropertiesプロファイルを使用して、propertiesプロファイルを読み込む方法は2つあります.1つは@Value('${}")です.1つは@Autowired private Environment envです.env.getProperty(“test.msg”);
3.2動的データソース構成まずクラスを定義し、現在のスレッドで使用されているデータソース名を保存する
次にjavaxをカスタマイズします.sql.Springが事前に実装してくれた親AbstractRoutingDataSourceを継承するだけで、DataSourceインタフェースを実装できます.
次にAOP接面を作成し,データソース切替論理を実現する.ここで問題があります.一般的にトランザクションはサービス層に追加されます.springの宣言トランザクション管理を使用すると、サービス層コードを呼び出す前にspringはaopでトランザクション制御コードを動的に追加します.したがって、トランザクションが有効であることを保証するには、springがトランザクションを追加する前にデータソースを動的に切り替えなければなりません.すなわち、動的切替データソースのaopは、少なくともサービスに追加する、spring宣言式事物aopの前に追加する.
データソース注記の定義
3.3 springboot集積mybatis実現ここではデータソース注入とsqlSessionFactory注入を一緒に置く.@コンフィギュレーションはspringを使うときxmlの中のラベル@Beanはspringを使うときxmlの中のラベルと理解できます
4.ログ構成springbootのログ構成デフォルトはresourcesディレクトリの下でlogback.xmlまたはlogback-spring.xmlファイル
ここまでspringboot統合mybatisでマルチデータソースプロジェクトの構成を実現すれば完了し、開発時にはビジネスロジックに注目する必要があり、一般的なcontrollerは以下の通りである.
参照可能
1.導入依存
<groupId>com.lancygroupId>
<artifactId>interfaces-serviceartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>jarpackaging>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
<version>1.4.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>1.4.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<version>1.4.2.RELEASEversion>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
<version>1.4.2.RELEASEversion>
dependency>
<dependency>
<groupId>com.oraclegroupId>
<artifactId>ojdbc6artifactId>
<version>11.2.0.1.0version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.1.1version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.0.16version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>4.3.4.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>4.3.4.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.9version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>4.1.6version>
dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>1.4.2.RELEASEversion>
<configuration>
<fork>truefork>
<mainClass>com.lancy.interfaces.InterfacesApplicationmainClass>
configuration>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
2.springbootポータルクラス構成の開始
package com.lingnanpass.interfaces;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = { "com.lancy.interfaces.common", "com.lancy.interfaces.*.dao",
"com.lancy.interfaces.*.service.impl", "com.lancy.interfaces.controller",
"com.lancy.interfaces.util" })
//@ComponentScan Spring ( ) spring spring 。
public class InterfacesApplication {
public static void main(String[] args) {
SpringApplication.run(LntInterfacesApplication.class, args);
}
}
3.マルチデータソース構成3.1アプリケーション.propertiesプロファイルspringbootコアプロファイルとはresourcesルートディレクトリの下のアプリケーションを指す.propertiesまたはapplication.ymlプロファイル、ここでpropertiesプロファイルを使用して、propertiesプロファイルを読み込む方法は2つあります.1つは@Value('${}")です.1つは@Autowired private Environment envです.env.getProperty(“test.msg”);
# 1-- :lnt
jdbc1.db.type=oracle
jdbc1.driver = oracle.jdbc.driver.OracleDriver
jdbc1.url=jdbc:oracle:thin:@192.168.1.203:1521/test1
jdbc1.user=lancy
jdbc1.pass=123456
jdbc1.maxPoolSize=10
jdbc1.minPoolSize=2
jdbc1.initialPoolSize =2
jdbc1.maxWaitTime =60000
jdbc1.checkIdlePoolTime = 60000
jdbc1.minConnTime = 300000
jdbc1.filters=stat,log4j
# 2-- :ykt
jdbc2.db.type=oracle
jdbc2.driver = oracle.jdbc.driver.OracleDriver
jdbc2.url=jdbc:oracle:thin:@192.168.1.205:1521/test2
jdbc2.user=udev_ykt
jdbc2.pass=123456
jdbc2.maxPoolSize=10
jdbc2.minPoolSize=2
jdbc2.initialPoolSize =2
jdbc2.maxWaitTime =60000
jdbc2.checkIdlePoolTime = 60000
jdbc2.minConnTime = 300000
jdbc2.filters=stat,log4j
oracle.typeAliasesPackage=com.lancy.interfaces.*.entity
oracle.mapperLocations=com/lancy/interfaces/*/dao/oracle/impl*/*.xml
# allow, IP, , ,
oracle.druidAllow=10.230.0.1/255,192.168.1.100/255
oracle.druidUsername=admin
oracle.druidPassword=123456
oracle.druidResetEnable=false
3.2動的データソース構成まずクラスを定義し、現在のスレッドで使用されているデータソース名を保存する
package com.lancy.interfaces.common;
/**
* @ClassName: DataSourceTypeManager.java
* @Description:
*/
public class DataSourceTypeManager {
private static final ThreadLocal dataSourceTypes = new ThreadLocal(){
@Override
protected String initialValue(){
return DataSourceRounting.defaultDataSourceKey;
}
};
public static String get(){
return dataSourceTypes.get();
}
public static void set(String dataSourceType){
dataSourceTypes.set(dataSourceType);
}
public static void reset(){
dataSourceTypes.set(DataSourceRounting.defaultDataSourceKey);
}
}
次にjavaxをカスタマイズします.sql.Springが事前に実装してくれた親AbstractRoutingDataSourceを継承するだけで、DataSourceインタフェースを実装できます.
package com.lancy.interfaces.common;
import java.util.Map;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
*
* @ClassName: DataSourceRounting.java
* @Description: , ,
*/
public class DataSourceRounting extends AbstractRoutingDataSource {
public static String defaultDataSourceKey;//
public static Map
次にAOP接面を作成し,データソース切替論理を実現する.ここで問題があります.一般的にトランザクションはサービス層に追加されます.springの宣言トランザクション管理を使用すると、サービス層コードを呼び出す前にspringはaopでトランザクション制御コードを動的に追加します.したがって、トランザクションが有効であることを保証するには、springがトランザクションを追加する前にデータソースを動的に切り替えなければなりません.すなわち、動的切替データソースのaopは、少なくともサービスに追加する、spring宣言式事物aopの前に追加する.
package com.lancy.interfaces.common;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* ,aop
*
* @ClassName: DataSourceAdvice.java
* @Description: , serviceImpl
*/
@Aspect
@Component
public class DataSourceAdvice {
// , serviceImpl
@Pointcut("execution(* com.lancy..service.impl..*(..))")
public void aspect() {
}
@AfterReturning("aspect()")
public void afterReturning() throws Throwable {
DataSourceTypeManager.reset();//
}
@Before("aspect()")
public void before(JoinPoint joinPoint) throws Throwable {
Object target = joinPoint.getTarget();
// , ,
String cls = target.toString().toLowerCase();
if (!cls.startsWith("com.lancy.interfaces.")) {
cls = target.getClass().getName().toLowerCase();
}
if (!cls.startsWith("com.lancy.interfaces.")) {
return;
}
String className = cls.replace("com.lancy.interfaces.", "");
String packageName = className.substring(0, className.indexOf("."));
//packageName lnt ykt 。 dao,service,mapper ,
//
String dsName = "";
// DataSource ,
if (target.getClass().isAnnotationPresent(DataSource.class)) {
DataSource datasource = target.getClass().getAnnotation(DataSource.class);
dsName = datasource.value();
}
//
if (DataSourceRounting.targetDataSources.containsKey(dsName)) {
//
DataSourceTypeManager.set(dsName);
} else if (DataSourceRounting.targetDataSources.containsKey(packageName)) {
DataSourceTypeManager.set(packageName);
} else {
DataSourceTypeManager.set(DataSourceRounting.defaultDataSourceKey);
}
}
}
データソース注記の定義
package com.lancy.interfaces.common;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
*
* @ClassName: DataSource.java
* @Description: (service ) ,
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface DataSource {
//
String value();
//
public static final String LNT = "lnt";
public static final String YKT = "ykt";
}
3.3 springboot集積mybatis実現ここではデータソース注入とsqlSessionFactory注入を一緒に置く.@コンフィギュレーションはspringを使うときxmlの中のラベル@Beanはspringを使うときxmlの中のラベルと理解できます
package com.lancy.interfaces.common;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import com.alibaba.druid.pool.DruidDataSource;
import com.github.pagehelper.PageHelper;
/**
* springboot mybatis 1) 2) SqlSessionFactory
*/
/**
* @ClassName: OracleMybatisConfig
* @Description: Oracle mybatis
*/
@Configuration
@MapperScan(basePackages = "com.lancy.interfaces.*.dao")
//MapperScan Mapper
public class OracleMybatisConfig {
@Autowired
private Environment env;
/**
* @Desctiption
* @return DataSource
*/
@Bean
public DataSource lntDataSource() throws Exception {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(env.getProperty("jdbc1.driver"));
druidDataSource.setUrl(env.getProperty("jdbc1.url"));
druidDataSource.setUsername(env.getProperty("jdbc1.user"));
druidDataSource.setPassword(env.getProperty("jdbc1.pass"));
druidDataSource.setMaxActive(Integer.parseInt(env.getProperty("jdbc1.maxPoolSize")));
druidDataSource.setInitialSize(Integer.parseInt(env.getProperty("jdbc1.initialPoolSize")));
druidDataSource.setMaxWait(Integer.parseInt(env.getProperty("jdbc1.maxPoolSize")));
druidDataSource.setMinIdle(Integer.parseInt(env.getProperty("jdbc1.minPoolSize")));
druidDataSource.setRemoveAbandoned(true);
druidDataSource.setRemoveAbandonedTimeout(60);
druidDataSource.setLogAbandoned(true);
druidDataSource.setTestWhileIdle(true);
druidDataSource.setFilters(env.getProperty("jdbc1.filters"));
druidDataSource.setValidationQuery(env.getProperty("oracle.validationQuery"));
return druidDataSource;
}
/**
* @Desctiption
* @return DataSource
*/
@Bean
public DataSource yktDataSource() throws Exception {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(env.getProperty("jdbc2.driver"));
druidDataSource.setUrl(env.getProperty("jdbc2.url"));
druidDataSource.setUsername(env.getProperty("jdbc2.user"));
druidDataSource.setPassword(env.getProperty("jdbc2.pass"));
druidDataSource.setMaxActive(Integer.parseInt(env.getProperty("jdbc2.maxPoolSize")));
druidDataSource.setInitialSize(Integer.parseInt(env.getProperty("jdbc2.initialPoolSize")));
druidDataSource.setMaxWait(Integer.parseInt(env.getProperty("jdbc2.maxPoolSize")));
druidDataSource.setMinIdle(Integer.parseInt(env.getProperty("jdbc2.minPoolSize")));
druidDataSource.setRemoveAbandoned(true);
druidDataSource.setRemoveAbandonedTimeout(60);
druidDataSource.setLogAbandoned(true);
druidDataSource.setTestWhileIdle(true);
druidDataSource.setFilters(env.getProperty("jdbc2.filters"));
druidDataSource.setValidationQuery(env.getProperty("oracle.validationQuery"));
return druidDataSource;
}
/**
* @Primary , , @autowire
* @Qualifier , ( DataSource )
*/
@Bean
@Primary
public DataSourceRounting dynamicDataSource(@Qualifier("lntDataSource") DataSource lntDataSource,
@Qualifier("yktDataSource") DataSource yktDataSource) {
Map targetDataSources = new HashMap();
targetDataSources.put("lnt", lntDataSource);
targetDataSources.put("ykt", yktDataSource);
DataSourceRounting dynamicDataSource = new DataSourceRounting();
dynamicDataSource.setDefaultDataSourceKey("lnt");
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
/**
* @Desctiption Mybatis SqlSessionFactory
* @return SqlSessionFactory
*/
@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("lntDataSource") DataSource lntDataSource,
@Qualifier("yktDataSource") DataSource yktDataSource, PageHelper pageHelper) throws Exception {
SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
fb.setDataSource(this.dynamicDataSource(lntDataSource, yktDataSource));// ( , ), DataSourceRounting javax.sql.DataSource
// *.xml , xml ( ),
fb.setTypeAliasesPackage(env.getProperty("oracle.typeAliasesPackage"));//
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setJdbcTypeForNull(JdbcType.VARCHAR);
configuration.setCallSettersOnNulls(true); // map
fb.setConfiguration(configuration);
fb.setPlugins(new Interceptor[] { pageHelper });
fb.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources(env.getProperty("oracle.mapperLocations")));// xml ,
return fb.getObject();
}
@Bean
public PageHelper pageHelper() {
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
p.setProperty("dialect", "oracle");
pageHelper.setProperties(p);
return pageHelper;
}
}
4.ログ構成springbootのログ構成デフォルトはresourcesディレクトリの下でlogback.xmlまたはlogback-spring.xmlファイル
<configuration scan="false" debug="false">
<property name="LOG_HOME" value="E:/lnt/logs" />
<property name="appName" value="service">property>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debuglevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="fileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${appName}.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.logfileNamePattern>
<MaxHistory>365MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%npattern>
layout>
<append>trueappend>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>infolevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${appName}-error.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${appName}-error-%d{yyyy-MM-dd}-%i.logfileNamePattern>
<MaxHistory>365MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%npattern>
layout>
<append>trueappend>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>errorlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<logger name="com.ibatis" level="DEBUG" />
<logger name="com.ibatis.common.jdbc.SimpleDataSource" level="DEBUG" />
<logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG" />
<logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="DEBUG" />
<logger name="java.sql.Connection" level="DEBUG" />
<logger name="java.sql.Statement" level="DEBUG" />
<logger name="java.sql.PreparedStatement" level="DEBUG" />
<root level="DEBUG">
<appender-ref ref="fileError" />
<appender-ref ref="fileInfo" />
<appender-ref ref="stdout" />
root>
configuration>
ここまでspringboot統合mybatisでマルチデータソースプロジェクトの構成を実現すれば完了し、開発時にはビジネスロジックに注目する必要があり、一般的なcontrollerは以下の通りである.
@RestController
@RequestMapping(value = "/")
public class CardInfoAction {
@RequestMapping(value = "/test",method = RequestMethod.POST)
@ResponseBody
public Object getCardInfo(@RequestBody String cardId) {
Map resultMap = new HashMap();
resultMap.put("test","success")
return resultMap;
}
}
参照可能