Mybatis操作多数据源的实现

Mybatis是一种优秀的ORM框架,对于开发人员来说,在数据库连接方面有许多选择,包括多数据源。在这里,我们将详细解释如何在Mybatis中实现多数据源。主要分为以下三个部分:

1.配置多数据源的文件

Mybatis可以配置多个数据源,需要在mybatis-config.xml中添加以下内容:

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
      <property name="driver" value="${jdbc.driver}"/>
      <property name="url" value="${jdbc.url}"/>
      <property name="username" value="${jdbc.username}"/>
      <property name="password" value="${jdbc.password}"/>
    </dataSource>
  </environment>
  <environment id="development2">
    ...
  </environment>
</environments>

其中,default属性指定默认的环境,可以在SqlSessionFactoryBuilderbuild()方法中指定使用哪个环境。environment元素定义了一个特定的环境,包含了数据库的链接信息。在每个environment中,可以定义一个或多个dataSource元素,分别指向不同的数据源。例如,在这里我们添加了两个数据源。

注意:在以上代码中,你需要把${jdbc.driver}${jdbc.url}等属性值替换成具体的值。

2.创建SqlSessionFactory对象

当多个environment中的dataSource元素指向不同的数据源,我们需要在运行时选择使用哪个数据源。为此,我们可以使用SqlSessionFactory的构造函数:

String environment = ...; // 选择要使用的环境id
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, environment);

上面的代码通过SqlSessionFactoryBuilderbuild()方法选择特定的数据源,返回一个SqlSessionFactory,后面我们就可以使用这个工厂来创建SqlSession,然后操作数据库。

3.注解@MapperScan

多数据源配置完后,需要在应用程序的入口处,注解@MapperScan才能扫描到多个Mapper,如下:

@SpringBootApplication
@MapperScan({"com.example.mapper1", "com.example.mapper2"})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

以上是多数据源实现的主要三个步骤。下面,我们来看两个具体的示例。

示例一

假设我们有两个数据库,一个是test1,另一个是test2。并且后面的操作是在Spring Boot上实现的。为了简化操作,在这里我们将使用默认的数据源test1来创建表和填充数据。然后,我们将使用test2,显式地将一个映射文件指向它,并且从它中查询一些数据。

首先,我们将使用默认的数据源创建表和填充数据,可以使用以下SQL语句:

-- 创建表
CREATE TABLE user (
  id BIGINT(20) PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(32) DEFAULT NULL,
  age INT(11) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;

-- 插入数据
INSERT INTO user (name, age) VALUES ('Tom', 20);
INSERT INTO user (name, age) VALUES ('Jerry', 18);
INSERT INTO user (name, age) VALUES ('Lucy', 25);

然后,我们需要在application.properties中指定两个数据源的相关信息:

# test1
spring.datasource.url=jdbc:mysql://localhost:3306/test1?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Hongkong
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# test2
test2.datasource.url=jdbc:mysql://localhost:3306/test2?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Hongkong
test2.datasource.username=root
test2.datasource.password=123456
test2.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

需要注意在test2数据源前加上test2.前缀。

接下来我们在test2数据源中,添加一个Mapper接口UserMapper,并在其中添加如下方法:

package com.example.mapper2;

import com.example.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * FROM user")
    List<User> queryAll();

}

接下来,在启动类中加入如下代码:

@Configuration
@MapperScan("com.example.mapper1")
public class MybatisConfig {

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

    @Qualifier("test2")
    @Bean(name = "test2DataSource")
    @ConfigurationProperties(prefix = "test2.datasource")
    public DataSource test2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "routingDataSource")
    public AbstractRoutingDataSource routingDataSource(@Qualifier("test1DataSource") DataSource test1DataSource,
                                                       @Qualifier("test2DataSource") DataSource test2DataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.TEST1, test1DataSource);
        targetDataSources.put(DatabaseType.TEST2, test2DataSource);

        AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {
            @Override
            protected Object determineCurrentLookupKey() {
                return DatabaseContextHolder.getDatabaseType();
            }
        };

        routingDataSource.setDefaultTargetDataSource(test1DataSource);
        routingDataSource.setTargetDataSources(targetDataSources);

        DatabaseContextHolder.setDatabaseType(DatabaseType.TEST1);

        return routingDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("routingDataSource") AbstractRoutingDataSource routingDataSource) throws IOException {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(routingDataSource);
        sessionFactory.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath:com/example/mapper/**/*.xml"));
        return sessionFactory;
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

上面的配置,我们定义了两个数据源的Bean对象,通过AbstractRoutingDataSource对象实现路由功能,将不同的SQL语句发往不同的数据源。在此,我们使用了一个自定义的枚举类DatabaseType,如下:

public enum DatabaseType {
    TEST1, TEST2
}

还需要一个自定义的DatabaseContextHolder对象来保存当前数据源,如下:

public class DatabaseContextHolder {

    private static final ThreadLocal<DatabaseType> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDatabaseType(DatabaseType type) {
        CONTEXT_HOLDER.set(type);
    }

    public static DatabaseType getDatabaseType() {
        return CONTEXT_HOLDER.get();
    }

    public static void clearDatabaseType() {
        CONTEXT_HOLDER.remove();
    }

}

以上是此示例的全部内容。在此之后,我们就可以使用UserMapper查询test2数据源的user表:

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public List<User> queryAll() {
        DatabaseContextHolder.setDatabaseType(DatabaseType.TEST2);
        List<User> users = userMapper.queryAll();
        DatabaseContextHolder.clearDatabaseType();
        return users;
    }

}

注意,在这里我们使用了DatabaseContextHolder类来切换数据源。

示例二

下面,我们再看一个简化版的多数据源实现:假设我们有两个数据源:一个是test1数据源,包含一个名为user的表;另一个是test2数据源,包含一个名为customer的表。我们需要在这两个数据源中分别查询这两个表的数据。

与示例一不同的是,我们这里不需要在运行时切换数据源,因为我们知道要使用哪个数据源。因为我们不使用AbstractRoutingDataSource路由,而是手动创建两个SqlSessionFactoryBean对象,并为每个对象设置不同的DataSource

首先,需要在application.properties中为这两个数据源声明相关的属性:

spring.datasource.test1.url=jdbc:mysql://localhost:3306/test1?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Hongkong
spring.datasource.test1.username=root
spring.datasource.test1.password=123456
spring.datasource.test1.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.test2.url=jdbc:mysql://localhost:3306/test2?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Hongkong
spring.datasource.test2.username=root
spring.datasource.test2.password=123456
spring.datasource.test2.driver-class-name=com.mysql.cj.jdbc.Driver

创建两个SqlSessionFactoryBean后,就可以设置它们的DataSource属性。首先,我们来看test1数据源:

@Configuration
public class DataSource1Config {

    @Value("${spring.datasource.test1.url}")
    private String url;

    @Value("${spring.datasource.test1.username}")
    private String username;

    @Value("${spring.datasource.test1.password}")
    private String password;

    @Value("${spring.datasource.test1.driver-class-name}")
    private String driverClassName;

    @Bean(name = "test1DataSource")
    public DataSource test1DataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean(name = "test1SqlSessionFactory")
    public SqlSessionFactoryBean test1SqlSessionFactory(@Qualifier("test1DataSource") DataSource test1DataSource) throws IOException {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(test1DataSource);
        sessionFactory.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath:com/example/mapper/test1/*.xml"));
        return sessionFactory;
    }

    @Bean(name = "test1SqlSessionTemplate")
    public SqlSessionTemplate test1SqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

上面代码中,我们需要通过属性文件获取各种连接参数的值,然后创建DriverManagerDataSource对象。

接下来,我们看一下test2数据源的配置:

@Configuration
public class DataSource2Config {

    @Value("${spring.datasource.test2.url}")
    private String url;

    @Value("${spring.datasource.test2.username}")
    private String username;

    @Value("${spring.datasource.test2.password}")
    private String password;

    @Value("${spring.datasource.test2.driver-class-name}")
    private String driverClassName;

    @Bean(name = "test2DataSource")
    public DataSource test2DataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean(name = "test2SqlSessionFactory")
    public SqlSessionFactoryBean test2SqlSessionFactory(@Qualifier("test2DataSource") DataSource test2DataSource) throws IOException {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(test2DataSource);
        sessionFactory.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath:com/example/mapper/test2/*.xml"));
        return sessionFactory;
    }

    @Bean(name = "test2SqlSessionTemplate")
    public SqlSessionTemplate test2SqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

以上是这个简化版示例的全部内容。在这里,我们使用两个不同的SqlSessionFactoryBean对象,为每个对象设置不同的数据源和Mapper文件位置即可。

至此,我们已经讲解了Mybatis操作多数据源的实现攻略。希望可以帮助你更好地理解和应用多数据源。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Mybatis操作多数据源的实现 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • java自己手动控制kafka的offset操作

    当使用kafka作为消费者时,消费者往往需要对消费的offset进行管理,以确保以后能够正确地读取数据。我们通常使用kafka内置的自动提交offset机制,但有时候我们也需要手动控制offset。 下面是一些步骤和示例,让你更好地了解如何手动控制kafka的offset操作: 步骤1:创建kafka消费者 首先,我们需要创建kafka消费者。以下是创建一个…

    Java 2023年5月20日
    00
  • springboot整合 beatlsql的实例代码

    下面我将为您详细讲解如何将Spring Boot与BeetlSQL整合。 一、Spring Boot集成BeetlSQL的前置条件 在开始整合前,请确保您拥有以下环境和工具: JDK1.8及以上版本 Maven3.0及以上版本 Spring Boot 2.0.0及以上版本 BeetlSQL 2.x版本(本示例使用的是2.8.2版本) 二、创建Spring B…

    Java 2023年5月20日
    00
  • Spring Data JPA注解Entity使用示例详解

    Spring Data JPA注解Entity使用示例详解 本文将详细介绍Spring Data JPA注解Entity的使用方法,包括如何定义实体类、如何使用注解配置实体类以及实现一些基本的CRUD操作。下文将通过两个示例演示Spring Data JPA注解Entity的使用方法。 示例一:定义实体类 定义实体类是Spring Data JPA的第一步,…

    Java 2023年6月2日
    00
  • java操作gaussDB数据库的实现示例

    让我来为您详细讲解如何使用Java操作GaussDB数据库的完整攻略。 首先,我们需要在Java程序中导入GaussDB数据库的驱动程序(GaussDB JDBC driver),然后创建数据库连接对象(Connection),通过连接对象创建SQL语句执行对象(Statement)或预编译语句对象(PreparedStatement),最后执行SQL语句并…

    Java 2023年5月19日
    00
  • netty中pipeline异常事件分析

    请允许我对“netty中pipeline异常事件分析”的攻略进行详细说明。 1. 理解pipeline异常事件 在Netty中,ChannelPipeline是消息处理的管道,消息在这条管道中流转,每个节点都可以做一些特定的处理。 在应用程序的运行过程中,有可能会发生一些异常情况,比如消息处理节点出错了,网络连接中断等。为了保证应用程序的健壮性,Netty提…

    Java 2023年5月25日
    00
  • java生成图片验证码功能

    下面是详细讲解”Java生成图片验证码功能”的完整攻略: 1. 确定需求 首先,我们需要明确这个功能的需求,即在Java Web应用中生成一个随机的图片验证码,以用于用户填写和校验,防止机器人攻击或恶意提交。 2. 添加依赖 接下来,我们需要添加相关的依赖。Java中生成图片验证码需要用到jcaptcha这个开源工具包,我们可以在pom.xml中添加它的依赖…

    Java 2023年6月15日
    00
  • 页面的缓存与不缓存设置及html页面中meta的作用

    页面缓存是浏览器缓存方式之一,也是提高网站性能的重要手段之一。Web页面中通过使用HTTP头,让浏览器在本地缓存页面,以避免重复网络请求。本文将对页面缓存和不缓存设置进行详细讲解,并介绍HTML页面中meta标签的作用。 页面缓存的作用 页面缓存是将网站的静态资源如CSS、JS、图片等文件保存在本地,下次打开同样的页面,在一段时间内可以直接从缓存中读取,从而…

    Java 2023年6月16日
    00
  • Java日常练习题,每天进步一点点(2)

    下面我来详细讲解一下“Java日常练习题,每天进步一点点(2)”的完整攻略。 1. 确定练习题类型 第一步,需要先确定练习题类型。根据题目要求和难度来确定需要练习什么类型的题目,比如说数据结构、算法、面向对象编程等。不同类型的题目需要掌握不同的知识点和解法,因此在选择练习题时需要慎重考虑。 2. 分析题目需求和边界条件 第二步,需要详细分析题目要求和边界条件…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部