文章目录
- 1.单数据源
- 1.1 application.properties 配置参考
- 1.2应用类参考配置
- 2.多数据源(主从)
- 2.1 application.properteis 如下配置
- 2.2 主从数据源的配置
- 2.3 Mybatis 配置动态数据源
- 2.4 动态数据源线程安全处理
- 2.5 获取动态数据源
- 2.6 AOP 配置,在 DAO 层切入,根据方法名进行主从切换
Springboot 集成 MyBatis,在纯血 Springboot 项目中增加如下依赖配置
${mybatis-starter-version} 是你要用的版本,自行替换
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis-starter-version}</version>
</dependency>
1.单数据源
此处默认采用的数据源连接池为 HikariDataSource(据说性能很好) 。它是springboot 默认的连接池之一(Hikari、tomcat、dbcp2),具体参见
org.springframework.boot.jdbc.DataSourceBuilder
1.1 application.properties 配置参考
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://ip:port/mytest?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
spring.datasource.username=xxxx
spring.datasource.password=xxx
spring.datasource.initial-size=2
spring.datasource.min-idle=2
spring.datasource.max-active=500
spring.datasource.max-wait=6000
spring.datasource.time-between-eviction-runs-millis=60000
spring.datasource.min-evictable-idle-time-millis=300000
spring.datasource.validation-query=select 1
spring.datasource.test-while-idle=true
spring.datasource.test-on-borrow=true
spring.datasource.test-on-return=true
spring.datasource.pool-prepared-statements=true
spring.datasource.max-open-prepared-statements=20
# mybatis 配置:实体及 mapper.xml 这里的配置类似 spring 与 mybatis 的集成,只是放到这里配置了
mybatis.type-aliases-package=com.test.app.dao.*.entity
mybatis.config-location=classpath:mybatis/mapper.xml
1.2应用类参考配置
- 关键配置 @MapperScan(“com.test.app.dao.**.mapper”)
@Configuration
@SpringBootApplication
@MapperScan("com.test.app.dao.**.mapper")
public class DAOTestApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(DAOTestApplication.class, args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {logger.info("DAO test Application is starting");return builder.sources(DAOTestApplication.class);}
}
2.多数据源(主从)
2.1 application.properteis 如下配置
# master
spring.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.master.jdbcUrl=jdbc:mysql://192.168.10.1:3306/mytest?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
spring.datasource.master.username=mysql
spring.datasource.master.password=******
spring.datasource.master.minimum-idle=5
spring.datasource.master.maximum-pool-size=200
spring.datasource.master.idle-timeout=30000
spring.datasource.master.max-lifetime=1800000
spring.datasource.master.connection-timeout=30000
spring.datasource.master.connection-test-query=SELECT 1# slave
spring.datasource.slave.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.slave.jdbcUrl=jdbc:mysql://192.168.10.2:3306/mytest?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
spring.datasource.slave.username=mysql
spring.datasource.slave.password=******
spring.datasource.slave.minimum-idle=5
spring.datasource.slave.maximum-pool-size=200
spring.datasource.slave.idle-timeout=30000
spring.datasource.slave.max-lifetime=1800000
spring.datasource.slave.connection-timeout=30000
spring.datasource.slave.connection-test-query=SELECT 1
spring.datasource.slave.read-only=true
2.2 主从数据源的配置
@Configuration
@EnableTransactionManagement
public class MultiDataSourceConfiguration {@Primary@Bean(name = "masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}
}
2.3 Mybatis 配置动态数据源
@Configuration
@AutoConfigureAfter({MultiDataSourceConfiguration.class})
public class MyBatisConfiguration extends MybatisAutoConfiguration {public MyBatisConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider,ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider,ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {super(properties, interceptorsProvider, resourceLoader, databaseIdProvider, configurationCustomizersProvider);}@Resource(name = "masterDataSource")private DataSource masterDataSource;@Resource(name = "slaveDataSource")private DataSource slaveDataSource;@Beanpublic SqlSessionFactory sqlSessionFactory() throws Exception {return super.sqlSessionFactory(routingDataSource());}public AbstractRoutingDataSource routingDataSource() {DynamicDataSource dynamicDataSource = new DynamicDataSource();Map<Object, Object> targetDataSources = new ClassLoaderRepository.SoftHashMap();targetDataSources.put(DynamicDataSourceHolder.MASTER, masterDataSource);targetDataSources.put(DynamicDataSourceHolder.SLAVE, slaveDataSource);dynamicDataSource.setDefaultTargetDataSource(masterDataSource);dynamicDataSource.setTargetDataSources(targetDataSources);return dynamicDataSource;}
}
2.4 动态数据源线程安全处理
public class DynamicDataSourceHolder {public static final String MASTER = "master";public static final String SLAVE = "slave";public static final ThreadLocal<String> holder = new ThreadLocal<String>();public static void setDataSource(String name) {holder.set(name);}public static String getDataSource() {return holder.get();}
}
2.5 获取动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceHolder.getDataSource();}
}
2.6 AOP 配置,在 DAO 层切入,根据方法名进行主从切换
@Component
@Aspect
public class DataSourceMethodInterceptor {private static final Logger logger = LoggerFactory.getLogger(DataSourceMethodInterceptor.class);@Before("execution(* com.test.app.dao.*.mapper.*.*(..))")public void dynamicSetDataSoruce(JoinPoint joinPoint) throws Exception {String methodName = joinPoint.getSignature().getName();// 查询使用从库if (methodName.startsWith("select") || methodName.startsWith("load") || methodName.startsWith("get")|| methodName.startsWith("count") || methodName.startsWith("is") || methodName.startsWith("query")|| methodName.startsWith("search")) {logger.debug("methodName:{}, execute slave", methodName);DynamicDataSourceHolder.setDataSource("slave");} else { // 其它使用主库logger.debug("methodName:{}, execute master", methodName);DynamicDataSourceHolder.setDataSource("master");}}
}