diff --git a/src/main/java/com/zcloud/config/MasterDataSourceConfig.java b/src/main/java/com/zcloud/config/MasterDataSourceConfig.java index 1b236618..464b8bfe 100644 --- a/src/main/java/com/zcloud/config/MasterDataSourceConfig.java +++ b/src/main/java/com/zcloud/config/MasterDataSourceConfig.java @@ -2,6 +2,7 @@ package com.zcloud.config; import javax.sql.DataSource; +import com.zcloud.plugins.DynamicDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; @@ -16,6 +17,9 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager; import com.alibaba.druid.pool.DruidDataSource; +import java.util.HashMap; +import java.util.Map; + /** * 说明:第一数据源配置 * 作者:luoxiaobao @@ -29,21 +33,31 @@ public class MasterDataSourceConfig { static final String MAPPER_LOCATION = "classpath:mybatis/datasource/*/*.xml"; //扫描的 xml 目录 static final String CONFIG_LOCATION = "classpath:mybatis/datasource/mybatis-config.xml"; //自定义的mybatis config 文件位置 static final String TYPE_ALIASES_PACKAGE = "com.zcloud.entity"; //扫描的 实体类 目录 - + @Value("${datasource.no1.url}") private String url; - + @Value("${datasource.no1.username}") private String user; - + @Value("${datasource.no1.password}") private String password; - + @Value("${datasource.no1.driver-class-name}") private String driverClass; - + + + + @Value("${datasource.slave.no1.driver-class-name}") + private String no1DataSourceSlaveDriver; + @Value("${datasource.slave.no1.url}") + private String no1DataSourceSlaveUrl; + @Value("${datasource.slave.no1.username}") + private String no1DataSourceSlaveUser; + @Value("${datasource.slave.no1.password}") + private String no1DataSourceSlavePassword; + @Bean(name = "masterDataSource") - @Primary public DataSource masterDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driverClass); @@ -52,18 +66,37 @@ public class MasterDataSourceConfig { dataSource.setPassword(password); return dataSource; } - + @Bean(name = "masterDataSourceSlave") + public DataSource masterDataSourceSlave() { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setDriverClassName(no1DataSourceSlaveDriver); + dataSource.setUrl(no1DataSourceSlaveUrl); + dataSource.setUsername(no1DataSourceSlaveUser); + dataSource.setPassword(no1DataSourceSlavePassword); + return dataSource; + } @Bean(name = "masterTransactionManager") @Primary public DataSourceTransactionManager masterTransactionManager() { return new DataSourceTransactionManager(masterDataSource()); } - + @Bean(name = "dynamicDataSourceNo1") + public DataSource dynamicDataSource( + @Qualifier("masterDataSource") DataSource masterDataSource, + @Qualifier("masterDataSourceSlave") DataSource masterDataSourceSlave) { + DynamicDataSource dynamicDataSource = new DynamicDataSource(); + Map dataSourceMap = new HashMap<>(); + dataSourceMap.put("no1DataSource", masterDataSource); + dataSourceMap.put("no1DataSourceSlave", masterDataSourceSlave); + dynamicDataSource.setTargetDataSources(dataSourceMap); + dynamicDataSource.setDefaultTargetDataSource(masterDataSource); + return dynamicDataSource; + } @Bean(name = "masterSqlSessionFactory") @Primary - public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)throws Exception { + public SqlSessionFactory masterSqlSessionFactory(@Qualifier("dynamicDataSourceNo1") DataSource dynamicDataSource)throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); - sessionFactory.setDataSource(masterDataSource); + sessionFactory.setDataSource(dynamicDataSource); sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MasterDataSourceConfig.MAPPER_LOCATION)); sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(MasterDataSourceConfig.CONFIG_LOCATION)); sessionFactory.setTypeAliasesPackage(MasterDataSourceConfig.TYPE_ALIASES_PACKAGE); diff --git a/src/main/java/com/zcloud/config/No2DataSourceConfig.java b/src/main/java/com/zcloud/config/No2DataSourceConfig.java index d225f276..b6af39f2 100644 --- a/src/main/java/com/zcloud/config/No2DataSourceConfig.java +++ b/src/main/java/com/zcloud/config/No2DataSourceConfig.java @@ -2,6 +2,7 @@ package com.zcloud.config; import javax.sql.DataSource; +import com.zcloud.plugins.DynamicDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; @@ -15,6 +16,9 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager; import com.alibaba.druid.pool.DruidDataSource; +import java.util.HashMap; +import java.util.Map; + /** * 说明:第二数据源配置 * 作者:luoxiaobao @@ -28,19 +32,27 @@ public class No2DataSourceConfig { static final String MAPPER_LOCATION = "classpath:mybatis/dsno2/*/*.xml"; //扫描的 xml 目录 static final String CONFIG_LOCATION = "classpath:mybatis/dsno2/mybatis-config.xml"; //自定义的mybatis config 文件位置 static final String TYPE_ALIASES_PACKAGE = "ocom.zcloud.entity"; //扫描的 实体类 目录 - + @Value("${datasource.no2.url}") private String url; - + @Value("${datasource.no2.username}") private String user; - + @Value("${datasource.no2.password}") private String password; - + @Value("${datasource.no2.driver-class-name}") private String driverClass; - + @Value("${datasource.slave.no2.driver-class-name}") + private String no2DataSourceSlaveDriver; + @Value("${datasource.slave.no2.url}") + private String no2DataSourceSlaveUrl; + @Value("${datasource.slave.no2.username}") + private String no2DataSourceSlaveUser; + @Value("${datasource.slave.no2.password}") + private String no2DataSourceSlavePassword; + @Bean(name = "no2DataSource") public DataSource no2DataSource() { DruidDataSource dataSource = new DruidDataSource(); @@ -50,19 +62,41 @@ public class No2DataSourceConfig { dataSource.setPassword(password); return dataSource; } - + @Bean(name = "no2DataSourceSlave") + public DataSource no2DataSourceSlave() { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setDriverClassName(no2DataSourceSlaveDriver); + dataSource.setUrl(no2DataSourceSlaveUrl); + dataSource.setUsername(no2DataSourceSlaveUser); + dataSource.setPassword(no2DataSourceSlavePassword); + return dataSource; + } @Bean(name = "no2TransactionManager") public DataSourceTransactionManager no2TransactionManager() { return new DataSourceTransactionManager(no2DataSource()); } - + @Bean(name = "dynamicDataSourceNo2") + public DataSource dynamicDataSource( + @Qualifier("no2DataSource") DataSource no2DataSource, + @Qualifier("no2DataSourceSlave") DataSource no2DataSourceSlave) { + DynamicDataSource dynamicDataSource = new DynamicDataSource(); + Map dataSourceMap = new HashMap<>(); + dataSourceMap.put("no2DataSource", no2DataSource); + dataSourceMap.put("no2DataSourceSlave", no2DataSourceSlave); + dynamicDataSource.setTargetDataSources(dataSourceMap); + dynamicDataSource.setDefaultTargetDataSource(no2DataSource); + return dynamicDataSource; + } @Bean(name = "no2SqlSessionFactory") - public SqlSessionFactory no2SqlSessionFactory(@Qualifier("no2DataSource") DataSource no2DataSource)throws Exception { + public SqlSessionFactory no2SqlSessionFactory(@Qualifier("dynamicDataSourceNo2") DataSource dynamicDataSource)throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); - sessionFactory.setDataSource(no2DataSource); + sessionFactory.setDataSource(dynamicDataSource); +// sessionFactory.setPlugins(new Interceptor[]{new SeparationN2Plugin()}); sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(No2DataSourceConfig.MAPPER_LOCATION)); sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(No2DataSourceConfig.CONFIG_LOCATION)); sessionFactory.setTypeAliasesPackage(No2DataSourceConfig.TYPE_ALIASES_PACKAGE); return sessionFactory.getObject(); } + + } diff --git a/src/main/java/com/zcloud/plugins/DataSourceContextHolder.java b/src/main/java/com/zcloud/plugins/DataSourceContextHolder.java new file mode 100644 index 00000000..01772d83 --- /dev/null +++ b/src/main/java/com/zcloud/plugins/DataSourceContextHolder.java @@ -0,0 +1,22 @@ +package com.zcloud.plugins; + +/** + * 说明:TODO + * 作者:wangxuan + * 官网:www.zcloudchina.com + */ +public class DataSourceContextHolder { + private static final ThreadLocal contextHolder = new ThreadLocal<>(); + + public static void setDataSourceType(String dataSourceType) { + contextHolder.set(dataSourceType); + } + + public static String getDataSourceType() { + return contextHolder.get(); + } + + public static void clearDataSourceType() { + contextHolder.remove(); + } +} diff --git a/src/main/java/com/zcloud/plugins/DynamicDataSource.java b/src/main/java/com/zcloud/plugins/DynamicDataSource.java new file mode 100644 index 00000000..618ccb61 --- /dev/null +++ b/src/main/java/com/zcloud/plugins/DynamicDataSource.java @@ -0,0 +1,15 @@ +package com.zcloud.plugins; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * 说明:动态数据源 + * 作者:wangxuan + * 官网:www.zcloudchina.com + */ +public class DynamicDataSource extends AbstractRoutingDataSource { + @Override + protected Object determineCurrentLookupKey() { + return DataSourceContextHolder.getDataSourceType(); + } +} diff --git a/src/main/java/com/zcloud/plugins/SeparationN1Plugin.java b/src/main/java/com/zcloud/plugins/SeparationN1Plugin.java new file mode 100644 index 00000000..65cd994e --- /dev/null +++ b/src/main/java/com/zcloud/plugins/SeparationN1Plugin.java @@ -0,0 +1,75 @@ +package com.zcloud.plugins; + +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.util.Properties; + +/** + * 说明:分页插件 + * 作者:luoxiaobao + * 官网:www.qdkjchina.com + */ +@Intercepts( + { +// @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}), + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) + }) +public class SeparationN1Plugin implements Interceptor { + + + @Override + public Object intercept(Invocation invocation) throws Throwable { +// if (invocation.getMethod().getName().equals("prepare")) { +// StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); +// MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); +// MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); +// SqlCommandType sqlCommandType = ms.getSqlCommandType(); +// if (sqlCommandType == SqlCommandType.SELECT) { +// DataSourceContextHolder.setDataSourceType("no2DataSourceSlave"); +// } +// } + if (invocation.getMethod().getName().equals("query")) { + boolean isReadOnly = isReadOnlySql(invocation.getArgs()); + if (isReadOnly) { + DataSourceContextHolder.setDataSourceType("no1DataSourceSlave"); + } else { + DataSourceContextHolder.setDataSourceType("no1DataSource"); + } + } +// return invocation.proceed(); +// boolean isReadOnly = isReadOnlySql(invocation.getArgs()); +// if (isReadOnly) { +// DataSourceContextHolder.setDataSourceType("no2DataSourceSlave"); +// } else { +// DataSourceContextHolder.setDataSourceType("no2DataSource"); +// } + try { + return invocation.proceed(); + } finally { + DataSourceContextHolder.clearDataSourceType(); + } + } + + private boolean isReadOnlySql(Object[] args) { + // 获取 SQL 语句 + MappedStatement ms = (MappedStatement) args[0]; + SqlCommandType sqlCommandType = ms.getSqlCommandType(); + // 判断是否为查询操作 + return sqlCommandType == SqlCommandType.SELECT; + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } +} diff --git a/src/main/java/com/zcloud/plugins/SeparationN2Plugin.java b/src/main/java/com/zcloud/plugins/SeparationN2Plugin.java new file mode 100644 index 00000000..ab952f2d --- /dev/null +++ b/src/main/java/com/zcloud/plugins/SeparationN2Plugin.java @@ -0,0 +1,79 @@ +package com.zcloud.plugins; + +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.*; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.reflection.DefaultReflectorFactory; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.sql.Connection; +import java.util.Properties; + +/** + * 说明:分页插件 + * 作者:luoxiaobao + * 官网:www.qdkjchina.com + */ +@Intercepts( + { +// @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}), + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) + }) +public class SeparationN2Plugin implements Interceptor { + + + @Override + public Object intercept(Invocation invocation) throws Throwable { +// if (invocation.getMethod().getName().equals("prepare")) { +// StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); +// MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); +// MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); +// SqlCommandType sqlCommandType = ms.getSqlCommandType(); +// if (sqlCommandType == SqlCommandType.SELECT) { +// DataSourceContextHolder.setDataSourceType("no2DataSourceSlave"); +// } +// } + if (invocation.getMethod().getName().equals("query")) { + boolean isReadOnly = isReadOnlySql(invocation.getArgs()); + if (isReadOnly) { + DataSourceContextHolder.setDataSourceType("no2DataSourceSlave"); + } else { + DataSourceContextHolder.setDataSourceType("no2DataSource"); + } + } +// return invocation.proceed(); +// boolean isReadOnly = isReadOnlySql(invocation.getArgs()); +// if (isReadOnly) { +// DataSourceContextHolder.setDataSourceType("no2DataSourceSlave"); +// } else { +// DataSourceContextHolder.setDataSourceType("no2DataSource"); +// } + try { + return invocation.proceed(); + } finally { + DataSourceContextHolder.clearDataSourceType(); + } + } + + private boolean isReadOnlySql(Object[] args) { + // 获取 SQL 语句 + MappedStatement ms = (MappedStatement) args[0]; + SqlCommandType sqlCommandType = ms.getSqlCommandType(); + // 判断是否为查询操作 + return sqlCommandType == SqlCommandType.SELECT; + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } +} diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 5bb49ecc..2537b4c2 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,5 +1,4 @@ - - +#主库 datasource.no1.driver-class-name: com.mysql.cj.jdbc.Driver datasource.no1.url=jdbc:mysql://39.101.130.96:33068/qa-gwj-prevention?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8 datasource.no1.username=root @@ -8,6 +7,16 @@ datasource.no2.driver-class-name: com.mysql.cj.jdbc.Driver datasource.no2.url=jdbc:mysql://39.101.130.96:33068/qa-gwj-regulatory?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8 datasource.no2.username=root datasource.no2.password=Mysql@zcloud88888 +#从库 +datasource.slave.no1.driver-class-name: com.mysql.cj.jdbc.Driver +datasource.slave.no1.url=jdbc:mysql://192.168.0.17:3306/qa-gwj-prevention?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8 +datasource.slave.no1.username=root +datasource.slave.no1.password=root +datasource.slave.no2.driver-class-name: com.mysql.cj.jdbc.Driver +datasource.slave.no2.url=jdbc:mysql://192.168.0.17:3306/qa-gwj-regulatory?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8 +datasource.slave.no2.username=root +datasource.slave.no2.password=root + #druid??? diff --git a/src/main/resources/mybatis/datasource/mybatis-config.xml b/src/main/resources/mybatis/datasource/mybatis-config.xml index a35bce8f..6f910719 100644 --- a/src/main/resources/mybatis/datasource/mybatis-config.xml +++ b/src/main/resources/mybatis/datasource/mybatis-config.xml @@ -1,5 +1,5 @@ - @@ -11,17 +11,18 @@ - + - + - + + - - - \ No newline at end of file + + + diff --git a/src/main/resources/mybatis/dsno2/mybatis-config.xml b/src/main/resources/mybatis/dsno2/mybatis-config.xml index 32e0a8c7..6c231cd3 100644 --- a/src/main/resources/mybatis/dsno2/mybatis-config.xml +++ b/src/main/resources/mybatis/dsno2/mybatis-config.xml @@ -1,5 +1,5 @@ - @@ -10,16 +10,18 @@ - + - + - + + + - - \ No newline at end of file + +