Upd:读写数据分离

master
duLingLing 5 years ago
parent 638cbfd595
commit 64d2467891

@ -90,6 +90,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
@ -194,6 +199,13 @@
<artifactId>taobao-sdk-java-auto</artifactId>
<version>1502853394064-20180710</version>
</dependency>
<!-- multi data source-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>

@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
@ -22,9 +23,13 @@ import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@SpringBootApplication(scanBasePackages = {"au.com.royalpay.payment", "cn.yixblog"})
/**
* exclude = {DataSourceAutoConfiguration.class}
* springbootapplication.properties
*/
@SpringBootApplication(scanBasePackages = {"au.com.royalpay.payment", "cn.yixblog"},exclude = {DataSourceAutoConfiguration.class})
@EnableScheduling
@EnableCaching
@EnableCaching( proxyTargetClass=true )
public class PaymentManageApplication {
public static void main(String[] args) {

@ -0,0 +1,35 @@
package au.com.royalpay.payment.manage.pos.datasource;
import org.springframework.beans.factory.annotation.Value;
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.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
*
* Created by Dulingling on 2019/8/7
*/
@Configuration
@EnableTransactionManagement
public class DataSourceConfiguration {
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Bean(name = "masterDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource(){
return DataSourceBuilder.create().type(dataSourceType).build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource1(){
return DataSourceBuilder.create().type(dataSourceType).build();
}
}

@ -0,0 +1,28 @@
package au.com.royalpay.payment.manage.pos.datasource;
/**
* Created by Dulingling on 2019/8/7
*/
public class DbContextHolder {
public enum DbType{
MASTER,SLAVE
}
private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();
public static void setDbType(DbType dbType){
if(dbType==null)throw new NullPointerException();
contextHolder.set(dbType);
}
public static DbType getDbType(){
DbType dbType = contextHolder.get();
return dbType ==null? DbType.MASTER: dbType;
}
public static void clearDbType(){
contextHolder.remove();
}
}

@ -0,0 +1,63 @@
package au.com.royalpay.payment.manage.pos.datasource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.aspectj.apache.bcel.util.ClassLoaderRepository;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
/**
* Created by Dulingling on 2019/8/7
*/
@Configuration
@AutoConfigureAfter({DataSourceConfiguration.class})
public class MybatisConfiguration extends MybatisAutoConfiguration {
private static Log logger = LogFactory.getLog(MybatisConfiguration.class);
@Resource(name = "masterDataSource")
private DataSource masterDataSource;
@Resource(name = "slaveDataSource")
private DataSource slaveDataSource;
public MybatisConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
super(properties, interceptorsProvider, resourceLoader, databaseIdProvider, configurationCustomizersProvider);
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
return super.sqlSessionFactory(roundRobinDataSouceProxy());
}
public AbstractRoutingDataSource roundRobinDataSouceProxy(){
ReadWriteSplitRoutingDataSource proxy = new ReadWriteSplitRoutingDataSource();
Map<Object,Object> targetDataResources = new ClassLoaderRepository.SoftHashMap();
targetDataResources.put(DbContextHolder.DbType.MASTER,masterDataSource);
targetDataResources.put(DbContextHolder.DbType.SLAVE,slaveDataSource);
proxy.setDefaultTargetDataSource(masterDataSource);//默认源
proxy.setTargetDataSources(targetDataResources);
return proxy;
}
public void test(){
}
}

@ -0,0 +1,15 @@
package au.com.royalpay.payment.manage.pos.datasource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* serviceslaves
* Created by Dulingling on 2019/8/7
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyConnection {
}

@ -0,0 +1,40 @@
package au.com.royalpay.payment.manage.pos.datasource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
/**
* Created by Dulingling on 2019/8/7
*/
@Aspect
@Component
public class ReadOnlyConnectionInterceptor implements Ordered {
public static final Logger logger = LoggerFactory.getLogger(ReadOnlyConnectionInterceptor.class);
@Around("@annotation(readOnlyConnection)")
public Object proceed(ProceedingJoinPoint proceedingJoinPoint,ReadOnlyConnection readOnlyConnection) throws Throwable {
try {
logger.info("set database connection to read only");
DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE);
Object result = proceedingJoinPoint.proceed();
return result;
}finally {
DbContextHolder.clearDbType();
logger.info("restore database connection");
}
}
@Override
public int getOrder() {
return 0;
}
}

@ -0,0 +1,20 @@
package au.com.royalpay.payment.manage.pos.datasource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* Created by Dulingling on 2019/8/7
*/
public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Object determineCurrentLookupKey() {
DbContextHolder.DbType dataSource = DbContextHolder.getDbType();
logger.error("------------------当前数据源:{}---------------------",dataSource);
return dataSource;
}
}
Loading…
Cancel
Save