MySQL 集群 (五) --------- 多数据源问题

本文详细介绍了在Spring和SpringBoot环境下,使用Mybatis实现多数据源配置的两种方案。方案一是基于Mapper包的隔离,每个Mapper操作不同数据库;方案二是基于动态数据源,运行时确定数据源。文章还涵盖了如何添加事务管理和测试,对于读写分离、数据库备份等场景提供了实用的实现策略。
摘要由CSDN通过智能技术生成


一、概述

多数据源问题是指在一个项目工程中,需要连接多个数据库。前几篇文章我们配置了数据库的主从,在实际开发中可能会有以下几种情况。

① 读写分离 : 项目中使用多数据源
② 项目中只操作主库 (读和写),从库只是起到了备份作用,程序员不需要关心主从结构

二、常见的多数据源技术选型模式

① JDBC
项目是JDBC开发,比较老。编写多个 getConnection 方法,分别连接不同的数据库即可

② Hibernate
项目是 SSH 框架开发,现在项目使用少一些
Spring + Hibernate
Springboot + Hibernate

③ Mybatis
项目是 SSM 框架开发
Spring + Mybatis
Springboot + Mybatis
Spring + JPA
Springboot + JPA

我们这里主要给大家介绍 Spring+Mybatis 和 SpringBoot+Mybatis 开发模式下的多数据源问题。

三、Spring + Mybatis 方案一实现步骤

核心思想 :基于 Mapper 包的隔离,每个 Mapper 包操作不同的数据库,每个 Mapper 包对应一个数据库

A、创建一个普通的 maven 项目

创建 maven 项目名为 :multi-datasource-spring

在这里插入图片描述
在这里插入图片描述

B、在 pom.xml 文件中添加相关的依赖

<!--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>

C、在 pom.xml 文件添加 resource,指定编译 MyBatis 映射文件

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

D、创建 MyBatis 整合多数据源的配置文件 applicationContext-mybatis.xml

在这里插入图片描述

E、创建 Spring 的核心配置文件 applicationContext.xml,引入 MyBatis 配置文件

在这里插入图片描述
F、在 applicationContext-mybatis.xml 配置 3307|3308|3309|3310 这四个数据源

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource3307" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="username" value="root"></property>
        <property name="password" value="aszhuo123"></property>
    </bean>

    <bean id="dataSource3308" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="username" value="root"></property>
        <property name="password" value="aszhuo123"></property>
    </bean>


    <bean id="dataSource3309" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="username" value="root"></property>
        <property name="password" value="aszhuo123"></property>
    </bean>


    <bean id="dataSource3310" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="username" value="root"></property>
        <property name="password" value="aszhuo123"></property>
    </bean>

</beans>

G、在 applicationContext-mybatis.xml 配置四个 sessionFactory,分别使用 3307|3308|3309|3310 这四个数据源

<!--3307数据库的 sessionFactory-->
<bean id="sessionFactory3307" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource3307"/>
</bean>

<!--3308数据库的 sessionFactory-->
<bean id="sessionFactory3308" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource3308"/>
</bean>

<!--3309数据库的 sessionFactory-->
<bean id="sessionFactory3309" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource3309"/>
</bean>

<!--3310数据库的 sessionFactory-->
<bean id="sessionFactory3310" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource3310"/>
</bean>

H、在 applicationContext-mybatis.xml 配置四个 Mapper 包的扫描,分别扫描 3307|3308|3309|3310

也就是说每个mapper下的接口只能操作一个数据库

<!--扫描3307库对应的mapper包,也就是说该Mapper下的接口操作的是3307数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sessionFactory3307"/>
    <property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3307"/>
</bean>

<!--扫描3308库对应的mapper包,也就是说该Mapper下的接口操作的是3308数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sessionFactory3308"/>
    <property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3308"/>
</bean>

<!--扫描3309库对应的mapper包,也就是说该Mapper下的接口操作的是3309数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sessionFactory3309"/>
    <property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3309"/>
</bean>

<!--扫描3310库对应的mapper包,也就是说该Mapper下的接口操作的是3310数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sessionFactory3310"/>
    <property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3310"/>
</bean>

I、在 pom.xml 文件中加入 MyBatis 逆向工程插件

<!--mybatis代码自动生成插件-->
<plugin>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.3.7</version>
    <configuration>
        <!--配置文件的位置-->
        <configurationFile>GeneratorMapper.xml</configurationFile>
        <verbose>true</verbose>
        <overwrite>true</overwrite>
    </configuration>
</plugin>

J、拷贝配置文件并进行代码反向生成

在这里插入图片描述

在这里插入图片描述
K、在 mapper 包下,分别创建子包 mapper3307 | mapper3308 | mapper3309 | mapper3310,并将生成的代码拷贝到不同的这几个子包下,然后删除掉 mapper 包下的生成的接口及 xml 文件

在这里插入图片描述
L、在 service 包下创建 UserService 接口

在接口中提供 getUserByIdFrom3307|3308|3309|3310 方法

public interface UserService {
   User getUserByIdForm3307(Integer id);
   User getUserByIdForm3308(Integer id);
   User getUserByIdForm3309(Integer id);
   User getUserByIdForm3310(Integer id);
}

M、创建 UserServiceImpl 实现类,并实现接口中的方法

因为我们现在4个数据库都是相同的表(实际不会存在这种情况),所以在 service 实现类中注入 Mapper 接口的时候,需要使用全限定名进行区分,并且变量名也不能一样。

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private com.fancy.multi.mapper.mapper3307.UserMapper userMapper3307;

    @Autowired
    private com.fancy.multi.mapper.mapper3308.UserMapper userMapper3308;

    @Autowired
    private com.fancy.multi.mapper.mapper3309.UserMapper userMapper3309;

    @Autowired
    private com.fancy.multi.mapper.mapper3310.UserMapper userMapper3310;

    public User getUserByIdFrom3307(Integer id) {
        return userMapper3307.selectByPrimaryKey(id);
    }

    public User getUserByIdFrom3308(Integer id) {
        return userMapper3308.selectByPrimaryKey(id);
    }

    public User getUserByIdFrom3309(Integer id) {
        return userMapper3309.selectByPrimaryKey(id);
    }

    public User getUserByIdFrom3310(Integer id) {
        return userMapper3310.selectByPrimaryKey(id);
    }
}

N、在 mapper 3307 | 3308 | 3309 | 3310 包下接口上的加 @Component(“userMapper3307|3308|3309|3310”)

因为默认情况下,Spring 容器创建的 Mapper 接口的代理对象名是接口名首字母小写,因为我们现在操作相同的表,所以接口名一样,默认生成的代理对象的名字也一样,会冲突,需要我们改一下,名字可以随意取,只要不冲突就行,因为@Autowired 是根据类型注入的。

在这里插入图片描述

O、在 applicationContext.xml 文件中扫描 impl 包

<context:component-scan base-package="com.fancy.multi.service.impl"/>

P、创建测试类,在 main 方法获取获取 service,调用方法

为了区分效果,可以讲从库的名字修改一下

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        UserService userService = context.getBean("userServiceImpl",UserService.class);
        System.out.println("3307数据库:" +userService.getUserByIdFrom3307(4).getName());
        System.out.println("3308数据库:" +userService.getUserByIdFrom3308(3).getName());
        System.out.println("3309数据库:" +userService.getUserByIdFrom3309(4).getName());
        System.out.println("3310数据库:" +userService.getUserByIdFrom3310(4).getName());
    }
}

四、Spring + Mybatis 方案一加事务管理

A、在 applicationContext-mybatis.xml 文件中为每一个数据源加事务管理器,并开启事务注解

<!--事务管理器-->
<bean id="transactionManager3307" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource3307"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3307"/>

<bean id="transactionManager3308" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource3308"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3308"/>

<bean id="transactionManager3309" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource3309"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3309"/>

<bean id="transactionManager3310" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource3310"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3310"/>

B、在 UserService 接口上加更新用户方法

int updateUserFrom3307(User user);
int updateUserFrom3308(User user);
int updateUserFrom3309(User user);
int updateUserFrom3310(User user);

C、在 UserServiceImpl 实现类中实现更新用户方法,并在该方法上加事务注解

@Transactional(transactionManager = "transactionManager3307")
public int updateUserFrom3307(User user) {
    int updateRow = userMapper3307.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/a;
    return updateRow;
}

@Transactional(transactionManager = "transactionManager3308")
public int updateUserFrom3308(User user) {
    int updateRow = userMapper3308.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/0;
    return updateRow;
}

@Transactional(transactionManager = "transactionManager3309")
public int updateUserFrom3309(User user) {
    int updateRow = userMapper3309.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/0;
    return updateRow;
}

@Transactional(transactionManager = "transactionManager3310")
public int updateUserFrom3310(User user) {
    int updateRow = userMapper3310.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/0;
    return updateRow;
}

D、在 Test 类中进行测试

为了避免同步,我们这里拿从库进行测试

User user = new User();
user.setId(3);
user.setName("update-3309");
userService.updateUserFrom3309(user);

发生除 0 异常,事务回滚,更新失败。
如果将实现类的方法注解注释,虽然发生异常,依然可以更新成功。

//@Transactional(transactionManager = "transactionManager3309")

五、Spring + MyBatis 方案二实现步骤

核心思想:基于动态数据源,在运行的时候才知道要是用哪个数据源

A、在方案一配置 sessionFactory时,引用动态数据源

动态数据源就是在运行的时候决定采用哪个数据源,在配置文件中不能写死

<!--数据库的sessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dynamicDataSource"/>
</bean>

注意:我们现在只引用了 dynamicDataSource ,但是这个类里具体内容是什么还不知道

B、在com.fancy.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.fancy.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();
}

C、在 applicationContext-mybatis.xml 配置 Mapper 包扫描器,直接扫描mapper 包即可

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
    <property name="basePackage" value="com.fancy.multi.mapper"/>
</bean>

之后进行测试即可

六、Spring + Mybatis 方案二加事务管理

A、在 applicationContext-mybatis.xml 添加事务管理器

并开启事务注解

如果只有一个事务管理器,那么开启事务注解的时候,transaction-manager 属性可以省略

<!--事务管理器 对动态数据源进行管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dynamicDataSource"/>
</bean>
<tx:annotation-driven/>

B、修改 UserServiceImpl 更新用户方法上加的事务注解

@Transactional
public int updateUserFrom3307(User user) {
    int updateRow = userMapper3307.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/0;
    return updateRow;
}
@Transactional
public int updateUserFrom3308(User user) {
    int updateRow = userMapper3308.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/0;
    return updateRow;
}
@Transactional
public int updateUserFrom3309(User user) {
    int updateRow = userMapper3309.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/0;
    return updateRow;
}
@Transactional
public int updateUserFrom3310(User user) {
    int updateRow = userMapper3310.updateByPrimaryKeySelective(user);
    System.out.println(updateRow);
    int a = 10/0;
    return updateRow;
}

C、在 Test 类进行测试

进行数据库操作前,需要先指定数据源

七、SpringBoot + Mybatis 方案一实现步骤

核心思想:基于 Mapper 包的隔离,每个 Mapper 包操作不同的数据库,每个 Mapper 包对应一个数据库

A、创建一个 SpringBoot 的 java 项目

名为 multi-datasource-springboot

在这里插入图片描述
不需要添加任何依赖就普通 Java 工程即可
在这里插入图片描述

C、在 pom.xml 文件中添加 MyBatis 的依赖

<!-- 加载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>

D、在 pom.xml 文件中指定 resource,对 MyBatis 映射文件编译

<resources>
	<resource>
		<directory>src/main/java</directory>
		<includes>
			<include>**/*.xml</include>
		</includes>
	</resource>
</resources>

E、在 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

F、在 com.fancy.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
}

G、在自定义属性映射文件出现的警告处理

点击红色圈的链接,到 SpringBoot 官网上,拷贝如下依赖到 pom.xml 文件中,这个警告不处理也不会影响程序的运行

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-configuration-processor</artifactId>
   <optional>true</optional>
</dependency>

H、将 Spring + Mybatis 方案一实现中的 applicationContext-mybatis.xml 配置信息用 SpringBoot 注解替换

因为我们这里有多个数据源,所有每个数据源对应一个配置类,在com.fancy.multi.config 下创建 MyDataSource3307 类

注意:

  • 在SpringBoot下,不能简单的配置 MapperScannerConfigurer这个 bean
  • 在SpringBoot下,需要 SqlSessionTemplate + @MapperScan 注解 配合实现原来 xml 的功能

@Configuration //相当于一个xml文件
@MapperScan(basePackages="com.fancy.multi.mapper.mapper3307"
        ,sqlSessionTemplateRef = "sqlSessionTemplate3307")
public class MyDataSource3307 {

    @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;
    }

    /**
     *  <!--3307数据库的sessionFactory-->
        <bean id="sessionFactory3307" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource3307"/>
        </bean>
     */
    @Bean
    public SqlSessionFactoryBean sessionFactory3307(){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource3307());
        return sqlSessionFactoryBean;
    }

    /**
     *  <!--扫描3307库对应的mapper包,也就是说该Mapper下的接口操作的是3307数据库-->
         <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="sqlSessionFactoryBeanName" value="sessionFactory3307"/>
             <property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3307"/>
         </bean>
        注意:
            在SpringBoot下,不能简单的配置MapperScannerConfigurer这个bean
            在SpringBoot下,需要SqlSessionTemplate + @MapperScan注解 配合实现原来xml的功能
     */
    @Bean
    public SqlSessionTemplate sqlSessionTemplate3307() throws Exception{
        //sessionFactory3307()方法返回SqlSessionFactoryBean,需要调用getObject返回SqlSessionFactory
        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sessionFactory3307().getObject());
        return sqlSessionTemplate;
    }
}

复制 MyDataSource3307 类为 3308|3309|3310 ,并改变类中的内容为对应的数据源编号

在这里插入图片描述

I、从 multi-datasource-spring 中拷贝 model、service 到当前 multi-datasource-springboot 中

在这里插入图片描述

J、在 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);
        System.out.println("3307数据库:" +userService.getUserByIdFrom3307(4).getName());
        System.out.println("3308数据库:" +userService.getUserByIdFrom3308(3).getName());
        System.out.println("3309数据库:" +userService.getUserByIdFrom3309(4).getName());
        System.out.println("3310数据库:" +userService.getUserByIdFrom3310(4).getName());
   }
}

八、SpringBoot + Mybatis 方案一加事务管理

A、在 MyDataSource3307 类中添加对事物的处理

/**
 *   <bean id="transactionManager3307" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource3307"/>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager3307"/>
 */
@Bean("transactionManager3307")
public DataSourceTransactionManager transactionManager3307(){
    DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
    dataSourceTransactionManager.setDataSource(dataSource3307());
    return dataSourceTransactionManager;
}

B、在 MyDataSource3308|3309|3310 类中同样添加对事物的处理

C、在 UserServiceImpl 实现类中需要控制事务的方法上添加事务注解

例如
在这里插入图片描述

D、在 Application 类中编写代码测试

User user = new User();
user.setId(3);
user.setName("boot-3309123");
userService.updateUserFrom3309(user);

九、SpringBoot + Mybatis 方案二实现步骤

核心思想:基于动态数据源,在运行的时候才知道要是用哪个数据源

A、将 Spring + Mybatis 方案二实现中的 applicationContext -mybatis.xml 配置信息用 SpringBoot 注解替换

因为方案二是基于动态数据源的,所以先将我们前面multi-datasource-spring 中定义的动态数据源DynamicDataSource 类以及 ThreadLocal 类拷贝到 multi-datasource-springboot 中

在这里插入图片描述
在 com.fancy.multi.config 下创建 MyDataSource 类

@Configuration //相当于一个xml文件
@MapperScan(basePackages="com.fancy.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;
    }
}

之后测试同样根据上面的步骤来即可。

十、SpringBoot + Mybatis 方案二加事务管理

A、在 MyDataSource 类中添加如下配置

/**
 *  <!--事务管理器 对动态数据源进行管理-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dynamicDataSource"/>
    </bean>
     <tx:annotation-driven/>
 */
@Bean
public DataSourceTransactionManager transactionManager(){
    DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
    dataSourceTransactionManager.setDataSource(dynamicDataSource());
    return dataSourceTransactionManager;
}

B、在 Application 类上添加事务注解驱动,并测试

注意:操作数据库前需要指定数据源

@SpringBootApplication
@EnableTransactionManagement
public class Application {
   public static void main(String[] args) {
      ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
      UserService userService = context.getBean("userServiceImpl",UserService.class);
      User user = new User();
      user.setId(3);
      user.setName("boot-123");
      ThreadLocalHolder.setDataSourceKey(DynamicDataSource.DATASOURCE_KEY_3309);
      userService.updateUserFrom3309(user);
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在森林中麋了鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值