Mysql之处理多数据源
一 Sring+Mybatis处理动态数据源
1 创建一个普通maven项目,在pom文件中添加相关依赖
<!--Spring相关的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<!--Mybatis相关依赖-->
<!--Mybatis框架依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--Mybatis与Spring整合依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--MySQL数据库连接驱动 版本不要过高-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.43</version>
</dependency>
<!--JDBC 数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.1</version>
</dependency>
2 在pom文件中添加resource,指定编译Mybatis映射文件
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
3 创建Mybatis整合多数据源的配置文件,applicationContext-mybatis.xml
4 创建Spring的核心配置文件applicationContext.xml,引入Mybatis配置文件
5 在applicationContext-mybatis.xml配置3307|3308|3309|3310这四个数据源
<bean id="dataSource3307" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3307/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="dataSource3308" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3308/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="dataSource3309" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3309/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="dataSource3310" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3310/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
6 在applicationContext-mybatis.xml配置一个sessionFactory,引用动态的数据源
动态数据源就是在运行的时候决定采用哪个数据源,在配置文件中不能写死
<!--数据库的sessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
7 5.4.8 在com.multi.dynamic包下创建DynamicDataSource类继承AbstractRoutingDataSource
(1) 设计的思路是将所有数据源放到一个map集合中,通过指定map集合的key,可以动态获取不同的数据源
(2) 该类中有个抽象方法determineCurrentLookupKey需要实现
protected Object determineCurrentLookupKey() {
return null;
}
(3) 定义几个常量,作为动态数据源对应的key
public static final String DATASOURCE_KEY_3307 = "3307";
public static final String DATASOURCE_KEY_3308 = "3308";
public static final String DATASOURCE_KEY_3309 = "3309";
public static final String DATASOURCE_KEY_3310 = "3310";
(4) 如何将指定的key和不同的数据源放到map集合中呢?
在applicationContext-mybatis.xml对动态数据源DynamicDataSource类进行配置
<!--动态数据源-->
<bean id="dynamicDataSource" class="com.bjpowernode.multi.dynamic.DynamicDataSource">
<property name="targetDataSources">
<map>
<entry key="3307" value-ref="dataSource3307"/>
<entry key="3308" value-ref="dataSource3308"/>
<entry key="3309" value-ref="dataSource3309"/>
<entry key="3310" value-ref="dataSource3310"/>
</map>
</property>
</bean>
(5) 如何为determineCurrentLookupKey()动态的指定key呢
在进行数据库操作前,我们提前设置使用哪个数据库,然后在指定的数据源的时候,会自动调用这个determineCurrentLookupKey()方法,得到指定的值。
直观的想法,可能是定义一个静态变量,但是静态变量存在线程安全问题,所以我们需要为每一个线程都维护一个变量,用于指定连接的数据库是哪个,所以我们这里使用线程的副本ThreadLocal类
(6) 在com.multi.dynamic包下创建ThreadLocalHolder类
public class ThreadLocalHolder {
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
/**
* 向当前线程变量的副本中放一个数据源的key
*/
public static void setDataSourceKey(String dataSourceKey){
holder.set(dataSourceKey);
}
/**
* 从当前线程变量的副本中取出放入数据源的key
*/
public static String getDataSourceKey(){
return holder.get();
}
}
(7) 对DynamicDataSource类中的方法进行实现
protected Object determineCurrentLookupKey() {
//在操作数据库前要确定是哪个数据源的key返回
return ThreadLocalHolder.getDataSourceKey();
}
8 在applicationContext-mybatis.xml配置Mapper包扫描器,直接扫描mapper包即可
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper"/>
</bean>
9 接口及映射
10 service、model及Test
11 在applicationContext.xml文件中扫描impl包
<context:component-scan base-package="com.multi.service.impl"/>
12 运行测试类,获取不同数据源用户
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = context.getBean("userServiceImpl",UserService.class);
ThreadLocalHolder.setDataSourceKey("3307");
System.out.println("3307数据库:" +userService.getUserByIdFrom3307(4).getName());
ThreadLocalHolder.setDataSourceKey("3308");
System.out.println("3308数据库:" +userService.getUserByIdFrom3308(3).getName());
ThreadLocalHolder.setDataSourceKey("3309");
System.out.println("3309数据库:" +userService.getUserByIdFrom3309(4).getName());
ThreadLocalHolder.setDataSourceKey("3310");
System.out.println("3310数据库:" +userService.getUserByIdFrom3310(4).getName());
}
}
二 SpringBoot+Mybatis处理动态数据源
1创建一个springBoot工程,在pom文件中添加依赖
<!-- 加载mybatis整合springboot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<!--在springboot的父工程中没有指定版本,我们需要手动指定-->
<version>1.3.2</version>
</dependency>
<!-- MySQL的jdbc驱动包 -->
<dependency>
<groupId>mysql</groupId>
<!--在springboot的父工程中指定了版本,我们就不需要手动指定了-->
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--JDBC 数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.1</version>
</dependency>
2 在pom文件中添加resource,对mybatis映射文件编译
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
3 在SpringBoot的核心配置文件中,配置连接信息
那么这里我们涉及多数据源,所以需要配置多个连接信息,如果配置多个,SpringBoot会报错,所以我们只能对使用自定义配置,然后在程序中获取
#3307数据库的连接配置信息
spring.datasource.username3307=root
spring.datasource.password3307=123456
spring.datasource.driver3307=com.mysql.cj.jdbc.Driver
spring.datasource.url3307=jdbc:mysql://192.168.235.128:3307/test?useUnicode=true&characterEncoding=utf8&useSSL=false
#3308数据库的连接配置信息
spring.datasource.username3308=root
spring.datasource.password3308=123456
spring.datasource.driver3308=com.mysql.cj.jdbc.Driver
spring.datasource.url3308=jdbc:mysql://192.168.235.128:3308/test?useUnicode=true&characterEncoding=utf8&useSSL=false
#3309数据库的连接配置信息
spring.datasource.username3309=root
spring.datasource.password3309=123456
spring.datasource.driver3309=com.mysql.cj.jdbc.Driver
spring.datasource.url3309=jdbc:mysql://192.168.235.128:3309/test?useUnicode=true&characterEncoding=utf8&useSSL=false
#3310数据库的连接配置信息
spring.datasource.username3310=root
spring.datasource.password3310=123456
spring.datasource.driver3310=com.mysql.cj.jdbc.Driver
spring.datasource.url3310=jdbc:mysql://192.168.235.128:3310/test?useUnicode=true&characterEncoding=utf8&useSSL=false
4 在com.multi.config包下定义一个映射核心文件中自定义信息的实体类DataSourceConfigInfo
@Component
@ConfigurationProperties(prefix ="spring.datasource")
public class DataSourceConfigInfo {
private String username3307;
private String password3307;
private String driver3307;
private String url3307;
private String username3308;
private String password3308;
private String driver3308;
private String url3308;
private String username3309;
private String password3309;
private String driver3309;
private String url3309;
private String username3310;
private String password3310;
private String driver3310;
private String url3310;
//省略get|set
}
5 在自定义属性映射文件出现的警告处理
点击红色圈的链接,到SpringBoot官网上,拷贝如下依赖到pom.xml文件中,这个警告不处理也不会影响程序的运行
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
6 将Spring+Mybatis实现中的applicationContext-mybatis.xml配置信息用SpringBoot注解替换
(1) 因为是基于动态数据源的,所以先将我们前面定义的动态数据源DynamicDataSource类以及ThreadLocal类拷贝到工程中
(2) 在com.bjpowernode.multi.config下创建MyDataSource类
@Configuration //相当于一个xml文件
@MapperScan(basePackages="com.bjpowernode.multi.mapper",sqlSessionTemplateRef = "sqlSessionTemplate")
public class MyDataSource {
@Autowired//注入我们自定义属性的映射类
private DataSourceConfigInfo dataSourceConfigInfo;
/**
<bean id="dataSource3307" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3307/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3307(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3307());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3307());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3307());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3307());
return druidDataSource;
}
/**
<bean id="dataSource3308" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3308/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3308(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3308());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3308());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3308());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3308());
return druidDataSource;
}
/**
<bean id="dataSource3309" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3309/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3309(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3309());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3309());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3309());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3309());
return druidDataSource;
}
/**
<bean id="dataSource3310" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3310/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3310(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3310());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3310());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3310());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3310());
return druidDataSource;
}
/**
* <!--数据库的sessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
*/
@Bean
public SqlSessionFactoryBean sessionFactory(){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
return sqlSessionFactoryBean;
}
/**
* <!--动态数据源-->
<bean id="dynamicDataSource" class="com.bjpowernode.multi.dynamic.DynamicDataSource">
<property name="targetDataSources">
<map>
<entry key="3307" value-ref="dataSource3307"/>
<entry key="3308" value-ref="dataSource3308"/>
<entry key="3309" value-ref="dataSource3309"/>
<entry key="3310" value-ref="dataSource3310"/>
</map>
</property>
</bean>
*/
@Bean
public DynamicDataSource dynamicDataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new ConcurrentHashMap<Object,Object>();
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3307,dataSource3307());
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3308,dataSource3308());
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3309,dataSource3309());
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3310,dataSource3310());
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
/**
* <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper"/>
</bean>
注意:
在SpringBoot下,不能简单的配置MapperScannerConfigurer这个bean
在SpringBoot下,需要SqlSessionTemplate + @MapperScan注解 配合实现原来xml的功能
*/
@Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception{
SqlSessionTemplate sqlSessionTemplate =new SqlSessionTemplate(sessionFactory().getObject());
return sqlSessionTemplate;
}
}
7 mapper、service、model
8 在Application添加测试代码进行测试
注意:操作数据库前需要指定数据源
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
UserService userService = context.getBean("userServiceImpl",UserService.class);
ThreadLocalHolder.setDataSourceKey(DynamicDataSource.DATASOURCE_KEY_3307);
System.out.println("3307数据库:" +userService.getUserByIdFrom3307(4).getName());
ThreadLocalHolder.setDataSourceKey(DynamicDataSource.DATASOURCE_KEY_3308);
System.out.println("3308数据库:" +userService.getUserByIdFrom3308(3).getName());
ThreadLocalHolder.setDataSourceKey(DynamicDataSource.DATASOURCE_KEY_3309);
System.out.println("3309数据库:" +userService.getUserByIdFrom3309(4).getName());
ThreadLocalHolder.setDataSourceKey(DynamicDataSource.DATASOURCE_KEY_3310);
System.out.println("3310数据库:" +userService.getUserByIdFrom3310(4).getName());
}
}