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
属性指定默认的环境,可以在SqlSessionFactoryBuilder
的build()
方法中指定使用哪个环境。environment
元素定义了一个特定的环境,包含了数据库的链接信息。在每个environment
中,可以定义一个或多个dataSource
元素,分别指向不同的数据源。例如,在这里我们添加了两个数据源。
注意:在以上代码中,你需要把${jdbc.driver}
、${jdbc.url}
等属性值替换成具体的值。
2.创建SqlSessionFactory对象
当多个environment
中的dataSource
元素指向不同的数据源,我们需要在运行时选择使用哪个数据源。为此,我们可以使用SqlSessionFactory
的构造函数:
String environment = ...; // 选择要使用的环境id
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, environment);
上面的代码通过SqlSessionFactoryBuilder
的build()
方法选择特定的数据源,返回一个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技术站