mybatis中通过 SqlSessionFactory 来创建 SqlSession会话对象,一个会话commit一次,也即一个会话就是一个事务
动态数据源构建原理就是根据需要,添加需要的datasource来定制化 SqlSessionFactory,springboot中集成通过切面的形式来进行配置
mybatisplus 动态数据源整合
第一种部署
添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.2.2.RELEASE</version> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1.tmp</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>8.0.13</version> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency>
|
配置mybatisplus相关信息
pojo
1 2 3 4 5 6 7
| @Data @TableName(value = "dept") public class DeptPojo { Integer deptno; String deptname; String deptsource; }
|
mapper
1 2 3 4
| @Mapper public interface DeptMapper extends BaseMapper<DeptPojo> { }
|
service
1 2 3
| public interface TestService { List<DeptPojo> selectALL(); }
|
serviceimpl
1 2 3 4 5 6 7 8 9 10
| @Service public class TestServiceimpl implements TestService { @Autowired private DeptMapper deptMapper;
public List<DeptPojo> selectALL() { QueryWrapper<DeptPojo> queryWrapper = new QueryWrapper<DeptPojo>(); return deptMapper.selectList(queryWrapper); } }
|
controller
1 2 3 4 5 6 7 8 9 10 11
| @RestController public class TestController {
@Autowired private TestService testService;
@GetMapping("list_my") public List<DeptPojo> selectAll(){ return testService.selectALL(); } }
|
数据源的核心配置
数据源操作类
通过继承 AbstractRoutingDataSource类来构建多数据源然后放入线程中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<DataSource> CONTEXT_HOLDER = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); }
@Override protected Object determineCurrentLookupKey() { return getDataSource(); }
public static void setDataSource(DataSource dataSource) { CONTEXT_HOLDER.set(dataSource); }
public static void clearDataSource() { CONTEXT_HOLDER.remove(); }
public static DataSource getDataSource() { return CONTEXT_HOLDER.get(); }
}
|
application.yml配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #datasource配置 spring: datasource: primary: jdbc-url: jdbc:mysql: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 secondary: jdbc-url: jdbc:mysql: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456
#mybatis配置 mybatis-plus: global-config: db-config: id-type: auto field-strategy: not_empty table-underline: true db-type: mysql logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
server: port: 9669
|
读取配置文件信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| @Configuration @MapperScan(basePackages = "com.simplemw.mapper", sqlSessionFactoryRef = "SqlSessionFactory") public class DynamicDataSourceConfig {
@Primary @Bean(name = "PrimaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public static DataSource getDateSource1() { return DataSourceBuilder.create().build(); }
@Bean(name = "SecondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public static DataSource getDateSource2() { return DataSourceBuilder.create().build(); }
@Bean(name = "dynamicDataSource") public DynamicDataSource DataSource(@Qualifier("PrimaryDataSource") DataSource primaryDataSource,@Qualifier("SecondaryDataSource") DataSource secondaryDataSource) { Map<Object, Object> targetDataSource = new HashMap<>(); targetDataSource.put("primary", primaryDataSource); targetDataSource.put("secondary", secondaryDataSource); return new DynamicDataSource(primaryDataSource,targetDataSource); }
@Bean(name = "SqlSessionFactory") public SqlSessionFactory SqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dynamicDataSource); sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class); configuration.setJdbcTypeForNull(JdbcType.NULL); sqlSessionFactoryBean.setConfiguration(configuration); return sqlSessionFactoryBean.getObject(); }
}
|
配置启动类
1 2 3 4 5 6
| @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class,args); } }
|
xml形式配置
注:若mapper以xml的形式实现则使用下面的方式
1 2 3 4 5 6 7 8 9 10 11 12
| @Bean public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)throws Exception{ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dynamicDataSource); sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath*:/mapper/*.xml")); sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory()); return sqlSessionFactoryBean.getObject(); }
|
第二种部署
添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>2.5.7</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1.tmp</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>8.0.13</version> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency>
|
yml配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| spring: datasource: dynamic: primary: master datasource: master: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/ces?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC username: root password: 123456 secondary: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/ces2?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC username: root password: 123456
|
使用方式
1 2
| @DS("secondary") List<CesPojo> selectAll();
|
方法上加注解
补充:再整合druid
添加依赖
1 2 3 4 5 6
| <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>
|
yml配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| spring: autoconfigure: exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure datasource: type: com.alibaba.druid.pool.DruidDataSource dynamic: primary: master datasource: master: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/ces?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC username: root password: 123456 secondary: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/ces2?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC username: root password: 123456 druid: initialSize: 5 minIdle: 5 maxActive: 30 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 'x' testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxPoolPreparedStatementPerConnectionSize: 20 filters: stat,wall,slf4j,config useGlobalDataSourceStat: true stat: log-slow-sql: true merge-sql: true slow-sql-millis: 10000
|
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Configuration public class DruidConfig {
@Bean public ServletRegistrationBean statViewServlet(){ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); servletRegistrationBean.addInitParameter("allow", "172.16.106.156");
servletRegistrationBean.addInitParameter("loginUsername", "admin"); servletRegistrationBean.addInitParameter("loginPassword", "admin"); servletRegistrationBean.addInitParameter("resetEnable", "false"); return servletRegistrationBean; }
@Bean public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,*/druid/*"); return filterRegistrationBean; }
}
|
druid监控页面url
http://localhost:8080/druid/login.html