如何在单个Boot应用中配置多数据库

如何在单个Boot应用中配置多数据库,第1张

为什么需要多数据库

默认情况下,Spring Boot使用的是单数据库配置(通过spring.datasource.*配置具体数据库连接信息)。

对于绝大多数Spring Boot应用,这是符合其使用场景的,因为Spring Boot提倡的是微服务理念,每个应用对应一个单独的业务领域。但在某些特殊情况下,一个应用对应多个数据库又是无法避免的,例如实施数据库分库后原本单个数据库变为多个数据库。本文就结合实际代码介绍如何在单个Boot应用中配置多数据库,以及与之相关的Druid,jOOQ,Flyway等数据服务框架的配置改造。

配置示例

DB1,DB2: 两个示例数据库

ServiceA, ServiceB: 分别使用DB1和DB2的服务类

连接池Druid

Druid是阿里巴巴开源的数据库连接池,提供了强大的监控支持,号称Java语言中最好的连接池。

创建两个配置类分别注册对应DB1和DB2的DataSource Bean和TransactionManager Bean。以DB1为例:

Tip: 可以把其中一个配置类中注册的DataSource Bean和DataSourceTransactionManager Bean加上@Primary注解,作为默认装配实例。

// DB1

@Configuration

public class Db1Config {

@Bean(initMethod = "init", destroyMethod = "close")

@ConfigurationProperties(prefix = "db.db1")

public DataSource dataSource1() {

return new DruidDataSource()

}

@Bean

public DataSourceTransactionManager transactionManager1() {

DataSourceTransactionManager transactionManager = new DataSourceTransactionManager()

transactionManager.setDataSource(dataSource1())

return transactionManager

}

}

application.conf中的配置:

# DB1

db.db1.url=jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true

db.db1.username=root

db.db1.password=

ORM框架jOOQ

jOOQ是一个开源ORM框架,最大特点是提供类型安全的流式API,支持代码生成。

参照Boot自带的JooqAutoConfiguration,不难写出如下配置类:

@Configuration

public class JooqConfig {

// DB1

@Bean

public DataSourceConnectionProvider dataSourceConnectionProvider1(

@Qualifier("dataSource1") DataSource dataSource1) {

return new DataSourceConnectionProvider(

new TransactionAwareDataSourceProxy(dataSource1))

}

@Bean

public SpringTransactionProvider transactionProvider1(

@Qualifier("transactionManager1") DataSourceTransactionManager txManager1) {

return new SpringTransactionProvider(txManager1)

}

// DB2

// ...

@Configuration

public static class DslContextConfig {

@Autowired(required = false)

private RecordMapperProvider recordMapperProvider

@Autowired(required = false)

private Settings settings

@Autowired(required = false)

private RecordListenerProvider[] recordListenerProviders

@Autowired

private ExecuteListenerProvider[] executeListenerProviders

@Autowired(required = false)

private VisitListenerProvider[] visitListenerProviders

// DSLContext for DB1

@Bean

public DefaultDSLContext dslContext1(@Qualifier("dataSourceConnectionProvider1") DataSourceConnectionProvider connectionProvider1,

@Qualifier("transactionProvider1") SpringTransactionProvider transactionProvider1) {

return new DefaultDSLContext(configuration(connectionProvider1, transactionProvider1))

}

// DSLContext for DB2

// ...

private DefaultConfiguration configuration(ConnectionProvider connectionProvider, TransactionProvider transactionProvider) {

DefaultConfiguration configuration = new DefaultConfiguration()

configuration.setSQLDialect(SQLDialect.MYSQL)

configuration.set(connectionProvider)

configuration.set(transactionProvider)

if (this.recordMapperProvider != null) {

configuration.set(this.recordMapperProvider)

}

if (this.settings != null) {

configuration.set(this.settings)

}

configuration.set(this.recordListenerProviders)

configuration.set(this.executeListenerProviders)

configuration.set(this.visitListenerProviders)

return configuration

}

}

}

服务类

配置好DataSource,TransacationManager和DSLContext之后,服务类的配置就比较简单了,直接引用即可。注意由于存在多套Beans,需要通过@Qualifier注解指定装配实例。

@Transactional("TransactionManager1")//每个事务指定 tx

public class ServiceA {

@Autowired

@Qualifier("dslContext1")

protected DSLContext dsl

}

数据库迁移框架Flyway

Flyway是一个轻量级的开源数据库迁移框架,使用非常广泛。

参照Boot自带的FlywayAutoConfiguration,同样可以写出如下配置类:

@Configuration

public class FlywayConfig {

@Bean(initMethod = "migrate")

@ConfigurationProperties(prefix = "fw.db1")

public Flyway flyway(@Qualifier("dataSource1") DataSource dataSource1) {

Flyway clinic = new Flyway()

clinic.setDataSource(dataSource1)

return clinic

}

// DB2

// ...

/**

* @see FlywayAutoConfiguration

*/

@Bean

@ConfigurationPropertiesBinding

public StringOrNumberToMigrationVersionConverter stringOrNumberMigrationVersionConverter() {

return new StringOrNumberToMigrationVersionConverter()

}

/**

* Convert a String or Number to a {@link MigrationVersion}.

* @see FlywayAutoConfiguration

*/

private static class StringOrNumberToMigrationVersionConverter

implements GenericConverter {

private static final Set<ConvertiblePair>CONVERTIBLE_TYPES

static {

Set<ConvertiblePair>types = new HashSet<ConvertiblePair>(2)

types.add(new ConvertiblePair(String.class, MigrationVersion.class))

types.add(new ConvertiblePair(Number.class, MigrationVersion.class))

CONVERTIBLE_TYPES = Collections.unmodifiableSet(types)

}

@Override

public Set<ConvertiblePair>getConvertibleTypes() {

return CONVERTIBLE_TYPES

}

@Override

public Object convert(Object source, TypeDescriptor sourceType,

TypeDescriptor targetType) {

String value = ObjectUtils.nullSafeToString(source)

return MigrationVersion.fromVersion(value)

}

}

}

application.conf中的配置:

# DB1

fw.db1.enabled=true

同一个项目有时会涉及到多个数据库,这时我们就要配置多个数据源。配置多数据源的常见情况有以下两种:

1)同一个项目中涉及两个或多个业务数据库,它们之间相互独立,这种情况也可以作为两个或多个项目来开发

2)两个或多个数据库之间是主从关系,主库负责写,从库负责读

1、pom.xml配置

在pom.xml中增加MyBatis-Plus多数据源依赖:

2、配置文件配置

在配置文件application.yml中配置我们需要连接的数据库:blog和user,默认为blog

3、启动类配置

在@SpringBootApplication注解上增加exclude = DruidDataSourceAutoConfigure.class配置:

这个配置的作用是去掉对DruidDataSourceAutoConfigure的自动配置,否则程序会报错:

原因:

DruidDataSourceAutoConfigure在DynamicDataSourceAutoConfiguration之前,其会注入一个DataSourceWrapper,会在原生的spring.datasource下找url, username, password等,而我们动态数据源的配置路径是变化的。

4、实体类和dao层配置

在po文件夹下创建blog和user文件夹,分别用于存储blog数据库和user数据库的实体:

注解:

@TableName: 表名注解,标识实体类对应的表

@TableId: 主键注解,当type = IdType.AUTO时,表示这个主键是自增主键

在dao文件夹下创建blog和user文件夹,分别用于存储blog和user的dao:

注解:

@Repository: 将数据访问层(DAO层)的类标识为Spring Bean

@DS: 配置非默认数据源,本示例中blog为默认数据源,user为非默认数据源,在使用@DS注解时,有如下注意事项:

1)不能使用事务,否则数据源不会切换,使用的还是第一次加载的数据源

2)第一次加载数据源之后,第二次,第三次…… *** 作其他数据源,如果数据源不存在,使用的还是第一次加载的数据源

3)数据源名称不要包含下划线,否则不能切换

5、测试验证

编写ArticleController和UserInfoController:

注 : 业务逻辑复杂时,Controller和Mapper中间会有Service层来处理业务逻辑,现在我们就简单的测试一下多数据源,所以直接使用Controller调用Mapper了

1、配置分页插件

2、分页方法

1)使用MyBatis-Plus的selectPage方法

使用MyBatis-Plus的selectPage方法,返回了IPage,示例:

2)sql分页

有时候有些分页需要关联多张表,使用LambdaQueryWrapper不太方便,这时候可以自己写sql来实现分页,主要有两种:纯sql自己实现分页和使用IPage实现分页

注 : 这里的sql示例就使用单表查询了,具体的可根据业务场景使用多表查询

A、纯sql自己实现分页

分页的数据list和总条数单独调用方法返回 :

B、使用IPage实现分页(常用)

返回IPage,返回值的数据结构见“ 1)使用MyBatis-Plus的selectPage方法

本文简单介绍了一下MyBatis-Plus的多数据源和分页,本文示例代码, 详见https://gitee.com/tunan222/spring-boot-demo

若您觉得还可以,请帮忙点个 “赞” ,谢谢

'DB_TYPE' =>'mysql',// 数据库类型

'DB_HOST' =>'127.0.0.1',// 数据库服务器址

'DB_NAME' =>'thinkphp',// 数据库名称

'DB_USER' =>'root',// 数据库用户名

'DB_PWD' =>'123',// 数据库密码

'DB_PREFIX' =>'tp_',// 数据表前缀

'DB_CHARSET' =>'utf8',// 网站编码

'DB_PORT' =>'3306',// 数据库端口

'APP_DEBUG' => false,// 启调试模式


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/6423601.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-21
下一篇 2023-03-21

发表评论

登录后才能评论

评论列表(0条)

保存