前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【详解】JavaSpringMVC+MyBitis+多数据源切换

【详解】JavaSpringMVC+MyBitis+多数据源切换

原创
作者头像
大盘鸡拌面
发布2025-01-19 18:53:40
发布2025-01-19 18:53:40
10600
代码可运行
举报
运行总次数:0
代码可运行

Java Spring MVC + MyBatis + 多数据源切换

在企业级应用开发中,经常需要处理来自不同数据库的数据。为了满足这一需求,我们可以通过配置多个数据源来实现对不同数据库的访问。本文将介绍如何在Spring MVC框架下结合MyBatis实现多数据源的动态切换。

1. 环境准备

  • Java:1.8 或更高版本
  • Spring Boot:2.3.0.RELEASE
  • MyBatis:3.5.2
  • 数据库:MySQL(示例使用两个不同的数据库实例)

2. 添加依赖

首先,在​​pom.xml​​文件中添加必要的依赖:

代码语言:javascript
代码运行次数:0
复制
<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- MyBatis Spring Boot Starter -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>

    <!-- MySQL Connector -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Spring Boot Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3. 配置多数据源

在​​application.properties​​文件中配置两个数据源:

代码语言:javascript
代码运行次数:0
复制
# 数据源1
spring.datasource.datasource1.jdbc-url=jdbc:mysql://localhost:3306/db1?useSSL=false&serverTimezone=UTC
spring.datasource.datasource1.username=root
spring.datasource.datasource1.password=password
spring.datasource.datasource1.driver-class-name=com.mysql.cj.jdbc.Driver

# 数据源2
spring.datasource.datasource2.jdbc-url=jdbc:mysql://localhost:3306/db2?useSSL=false&serverTimezone=UTC
spring.datasource.datasource2.username=root
spring.datasource.datasource2.password=password
spring.datasource.datasource2.driver-class-name=com.mysql.cj.jdbc.Driver

4. 创建数据源配置类

创建一个配置类来管理多个数据源:

代码语言:javascript
代码运行次数:0
复制
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.example.mapper", sqlSessionFactoryRef = "sqlSessionFactory")
public class DataSourceConfig {

    @Bean(name = "datasource1")
    @ConfigurationProperties(prefix = "spring.datasource.datasource1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "datasource2")
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "sqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("datasource1") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return factoryBean.getObject();
    }

    @Bean(name = "transactionManager")
    @Primary
    public DataSourceTransactionManager transactionManager(@Qualifier("datasource1") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

5. 动态数据源切换

为了实现动态数据源切换,我们需要创建一个动态数据源类和一个切面来管理数据源的选择:

5.1 动态数据源类
代码语言:javascript
代码运行次数:0
复制
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceKey();
    }
}
5.2 数据源上下文持有者
代码语言:javascript
代码运行次数:0
复制
public class DynamicDataSourceContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceKey(String key) {
        contextHolder.set(key);
    }

    public static String getDataSourceKey() {
        return contextHolder.get();
    }

    public static void clearDataSourceKey() {
        contextHolder.remove();
    }
}
5.3 切面管理数据源选择
代码语言:javascript
代码运行次数:0
复制
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceAspect {

    @Before("@annotation(com.example.annotation.TargetDataSource)")
    public void switchDataSource(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        TargetDataSource targetDataSource = signature.getMethod().getAnnotation(TargetDataSource.class);
        if (targetDataSource != null) {
            String dataSource = targetDataSource.value();
            DynamicDataSourceContextHolder.setDataSourceKey(dataSource);
        }
    }
}
5.4 自定义注解
代码语言:javascript
代码运行次数:0
复制
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
    String value();
}

6. 使用示例

假设我们有两个数据库表​​user​​和​​order​​分别位于​​db1​​和​​db2​​中,我们可以这样编写DAO层:

6.1 UserMapper
代码语言:javascript
代码运行次数:0
复制
import com.example.entity.User;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {

    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserById(@Param("id") int id);
}
6.2 OrderMapper
代码语言:javascript
代码运行次数:0
复制
import com.example.entity.Order;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface OrderMapper {

    @Select("SELECT * FROM order WHERE id = #{id}")
    Order getOrderById(@Param("id") int id);
}
6.3 Service层
代码语言:javascript
代码运行次数:0
复制
import com.example.annotation.TargetDataSource;
import com.example.entity.User;
import com.example.entity.Order;
import com.example.mapper.UserMapper;
import com.example.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrderMapper orderMapper;

    @TargetDataSource("datasource1")
    public User getUserById(int id) {
        return userMapper.getUserById(id);
    }

    @TargetDataSource("datasource2")
    public Order getOrderById(int id) {
        return orderMapper.getOrderById(id);
    }
}

通过上述步骤,我们成功地在Spring MVC项目中实现了MyBatis的多数据源动态切换。这种方法不仅提高了系统的灵活性,还使得跨数据库操作变得更加简单和高效。希望这篇文章能对你有所帮助!

以上是一个关于在Spring MVC框架下结合MyBatis实现多数据源动态切换的技术博客文章。希望对你有所帮助!当然可以!下面是一个简单的示例,展示如何在Spring MVC项目中使用MyBatis实现多数据源切换。这个例子将包括以下几个部分:

  1. 配置文件:定义多个数据源和对应的SQLSessionFactory。
  2. 自定义数据源切换策略:通过一个注解来动态选择数据源。
  3. Service层:使用自定义注解来指定数据源。
  4. Controller层:调用Service层的方法。
1. 配置文件

首先,我们需要在​​applicationContext.xml​​中配置多个数据源和对应的SQLSessionFactory。

代码语言:javascript
代码运行次数:0
复制
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 数据源1 -->
    <bean id="dataSource1" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/db1"/>
        <property name="username" value="user1"/>
        <property name="password" value="password1"/>
    </bean>

    <!-- 数据源2 -->
    <bean id="dataSource2" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/db2"/>
        <property name="username" value="user2"/>
        <property name="password" value="password2"/>
    </bean>

    <!-- 动态数据源 -->
    <bean id="dynamicDataSource" class="com.example.config.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="dataSource1" value-ref="dataSource1"/>
                <entry key="dataSource2" value-ref="dataSource2"/>
            </map>
        </property>
        <property name="defaultTargetDataSource" ref="dataSource1"/>
    </bean>

    <!-- SQLSessionFactory1 -->
    <bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource1"/>
        <property name="mapperLocations" value="classpath:mapper/db1/*.xml"/>
    </bean>

    <!-- SQLSessionFactory2 -->
    <bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource2"/>
        <property name="mapperLocations" value="classpath:mapper/db2/*.xml"/>
    </bean>

    <!-- SqlSessionTemplate1 -->
    <bean id="sqlSessionTemplate1" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory1"/>
    </bean>

    <!-- SqlSessionTemplate2 -->
    <bean id="sqlSessionTemplate2" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory2"/>
    </bean>

    <!-- Transaction Manager -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dynamicDataSource"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 扫描Service层 -->
    <context:component-scan base-package="com.example.service"/>

</beans>
2. 自定义数据源切换策略

创建一个动态数据源类​​DynamicDataSource​​,并定义一个注解​​@TargetDataSource​​来指定数据源。

代码语言:javascript
代码运行次数:0
复制
package com.example.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

package com.example.config;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
    String value();
}

创建一个线程本地变量​​DataSourceContextHolder​​来保存当前的数据源。

代码语言:javascript
代码运行次数:0
复制
package com.example.config;

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }
}
3. Service层

在Service层中使用​​@TargetDataSource​​注解来指定数据源。

代码语言:javascript
代码运行次数:0
复制
package com.example.service;

import com.example.config.TargetDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    @TargetDataSource("dataSource1")
    public void addUserToDB1(User user) {
        userMapper.insertUser(user);
    }

    @Transactional
    @TargetDataSource("dataSource2")
    public void addUserToDB2(User user) {
        userMapper.insertUser(user);
    }
}
4. Controller层

在Controller层中调用Service层的方法。

代码语言:javascript
代码运行次数:0
复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/db1")
    public String addUserToDB1(@RequestBody User user) {
        userService.addUserToDB1(user);
        return "User added to DB1";
    }

    @PostMapping("/db2")
    public String addUserToDB2(@RequestBody User user) {
        userService.addUserToDB2(user);
        return "User added to DB2";
    }
}
5. Mapper接口和XML文件

定义Mapper接口和对应的XML文件。

代码语言:javascript
代码运行次数:0
复制
package com.example.mapper;

import com.example.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {

    @Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
    void insertUser(User user);
}

在​​src/main/resources/mapper/db1/UserMapper.xml​​和​​src/main/resources/mapper/db2/UserMapper.xml​​中定义SQL映射。

代码语言:javascript
代码运行次数:0
复制
<!-- src/main/resources/mapper/db1/UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <insert id="insertUser" parameterType="com.example.entity.User">
        INSERT INTO users (name, email) VALUES (#{name}, #{email})
    </insert>
</mapper>

<!-- src/main/resources/mapper/db2/UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <insert id="insertUser" parameterType="com.example.entity.User">
        INSERT INTO users (name, email) VALUES (#{name}, #{email})
    </insert>
</mapper>
6. 实体类

定义一个简单的实体类​​User​​。

代码语言:javascript
代码运行次数:0
复制
package com.example.entity;

public class User {
    private String name;
    private String email;

    // Getters and Setters
}

以上代码展示了如何在Spring MVC项目中使用MyBatis实现多数据源切换。通过自定义注解和动态数据源类,可以在运行时根据需要切换不同的数据源。希望这个示例对你有帮助!如果有任何问题或需要进一步的帮助,请随时告诉我。在Java项目中使用Spring MVC框架结合MyBatis进行开发时,如果需要处理多个数据库的数据源切换,可以通过配置Spring的​​AbstractRoutingDataSource​​来实现。以下是一个详细的步骤和示例代码,展示如何在一个Spring MVC + MyBatis项目中实现多数据源切换。

1. 添加依赖

首先,在你的​​pom.xml​​文件中添加Spring、MyBatis及相关依赖:

代码语言:javascript
代码运行次数:0
复制
<dependencies>
    <!-- Spring MVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.10</version>
    </dependency>

    <!-- MyBatis -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>

    <!-- MySQL Connector -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.23</version>
    </dependency>

    <!-- HikariCP Connection Pool -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>4.0.3</version>
    </dependency>
</dependencies>
2. 配置数据源

创建一个配置类来定义多个数据源,并通过​​AbstractRoutingDataSource​​实现数据源的动态切换。

代码语言:javascript
代码运行次数:0
复制
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
@MapperScan("com.example.mapper")
public class DataSourceConfig {

    @Bean
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("dataSource1", dataSource1());
        targetDataSources.put("dataSource2", dataSource2());
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
        return dynamicDataSource;
    }

    @Bean
    public DataSource dataSource1() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db1");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }

    @Bean
    public DataSource dataSource2() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db2");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        return factoryBean.getObject();
    }

    @Bean
    public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}
3. 实现动态数据源切换

创建一个继承自​​AbstractRoutingDataSource​​的类来管理数据源的切换逻辑。

代码语言:javascript
代码运行次数:0
复制
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey();
    }
}
4. 数据源上下文管理

创建一个线程安全的上下文管理器来保存当前线程使用的数据源键。

代码语言:javascript
代码运行次数:0
复制
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceKey(String key) {
        contextHolder.set(key);
    }

    public static String getDataSourceKey() {
        return contextHolder.get();
    }

    public static void clearDataSourceKey() {
        contextHolder.remove();
    }
}
5. 切换数据源

在需要切换数据源的地方,调用​​DataSourceContextHolder​​的方法来设置当前线程使用的数据源。

代码语言:javascript
代码运行次数:0
复制
@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @GetMapping("/users1")
    public List<User> getUsersFromDataSource1() {
        DataSourceContextHolder.setDataSourceKey("dataSource1");
        List<User> users = userMapper.selectAll();
        DataSourceContextHolder.clearDataSourceKey();
        return users;
    }

    @GetMapping("/users2")
    public List<User> getUsersFromDataSource2() {
        DataSourceContextHolder.setDataSourceKey("dataSource2");
        List<User> users = userMapper.selectAll();
        DataSourceContextHolder.clearDataSourceKey();
        return users;
    }
}
6. Mapper接口

定义MyBatis的Mapper接口,用于访问数据库。

代码语言:javascript
代码运行次数:0
复制
public interface UserMapper {
    List<User> selectAll();
}
7. XML映射文件

在​​resources/mapper​​目录下创建XML映射文件,例如​​UserMapper.xml​​。

代码语言:javascript
代码运行次数:0
复制
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectAll" resultType="com.example.model.User">
        SELECT * FROM user
    </select>
</mapper>

以上步骤展示了如何在Spring MVC + MyBatis项目中实现多数据源切换。通过这种方式,你可以在不同的请求或业务逻辑中灵活地切换数据源。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java Spring MVC + MyBatis + 多数据源切换
    • 1. 环境准备
    • 2. 添加依赖
    • 3. 配置多数据源
    • 4. 创建数据源配置类
    • 5. 动态数据源切换
      • 5.1 动态数据源类
      • 5.2 数据源上下文持有者
      • 5.3 切面管理数据源选择
      • 5.4 自定义注解
    • 6. 使用示例
      • 6.1 UserMapper
      • 6.2 OrderMapper
      • 6.3 Service层
      • 1. 配置文件
      • 2. 自定义数据源切换策略
      • 3. Service层
      • 4. Controller层
      • 5. Mapper接口和XML文件
      • 6. 实体类
      • 1. 添加依赖
      • 2. 配置数据源
      • 3. 实现动态数据源切换
      • 4. 数据源上下文管理
      • 5. 切换数据源
      • 6. Mapper接口
      • 7. XML映射文件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档