Spring配置多数据库(采用数据连接池管理)

news2024/11/24 22:49:12

一,前言

大家在开发过程中,如果项目大一点就会遇到一种情况,同一个项目中可能会用到很多个数据源,那么这篇文章,博主为大家分享在spring应用中如何采用数据库连接池的方式配置配置多数据源。

本篇文章采用大家用的最多也是最受欢迎的HikariCP进行示范。

二,数据库连接池

数据库连接池是一个管理数据库连接的工具,它允许应用程序通过连接池来获取数据库连接,而不是每次需要时都重新创建连接。连接池通过维护一组预先创建好的数据库连接,以及管理连接的分配和释放,可以提高应用程序对数据库的访问性能和效率。

我们可以利用数据库连接池取实现连接的细节化配置。如最大连接数,最大空闲时间,最大连接等待时间等,这些方便了我们操作数据库,更可以有效避免过长等待导致程序卡死的情况。

常见的数据库连接池包括 HikariCP、Tomcat JDBC Pool、Apache Commons DBCP、C3P0、Druid等等。

三,实际应用

1,准备数据库以及表和基本数据

本文测试多库的情况,所以我们需要创建最少两个库进行测试。数据库sql我就不提供了,各位根据自己方便手动去创建吧。我这里简单创建两个库和三张表。如下图所示

2,基本框架准备(启动类就不展示了,有需要请看博主其它文档)

2.1 pom依赖
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.5.4</version>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.20</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.12.0</version> <!-- 这里是最新版本 -->
    </dependency>
<!--    日志框架-->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.5</version> <!-- 你可以替换为其他版本 -->
    </dependency>

    <!-- mysql 连接 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
      <version>2.5.4</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.17</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.0</version>
    </dependency>
2.2 application.properties

这里密码采用了加密的方式,运行时会自动解密,如果不知道怎么做的请查看SpringBoot启动自动解密加密配置项_springboot environment 配置项解密-CSDN博客

spring.profiles.active=dev,database
#mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
datasource1.url=jdbc:mysql://localhost:3306/rojertest?serverTimezone=Asia/Tokyo
datasource1.username=root
datasource1.password={decrypt}bGoxMDA0MDE4Mjc3

datasource2.url=jdbc:mysql://localhost:3306/roejrtest?serverTimezone=Asia/Tokyo
datasource2.username=root
datasource2.password={decrypt}bGoxMDA0MDE4Mjc3
2.3 HikariCP配置
#HikariCP 配置信息
#连接超时时间,指连接数据库时最大等待时间,单位是毫秒
spring.datasource.hikari.connection-timeout=3000
#连接空闲超时时间,指连接在连接池中保持空闲状态的最大时间,超过此时间连接将被释放,单位是毫秒
spring.datasource.hikari.idle-timeout=3000
#连接池的最大连接数,指连接池中允许的最大连接数量
spring.datasource.hikari.maximum-pool-size=10
#连接池的最小空闲连接数,指连接池中保持的最小空闲连接数量。
spring.datasource.hikari.minimum-idle=5
#设置连接的事务隔离级别
#1,DEFAULT:使用数据库系统的默认隔离级别。
#2,READ_UNCOMMITTED:允许事务读取未提交的数据更改。这是最低的隔离级别,它允许事务读取未提交的更改,可能会导致脏读、不可重复读和幻读等问题。
#3,READ_COMMITTED:确保一个事务只能读取到已经提交的数据更改。在这个级别下,事务不会读取到其他事务未提交的更改,可以避免脏读,但仍可能存在不可重复读和幻读的问题。
#4,REPEATABLE_READ:确保一个事务可以多次读取相同的数据而不受其他事务的影响。在这个级别下,事务不会读取到其他事务已提交的更改,可以避免脏读和不可重复读,但仍可能存在幻读的问题。
#5,SERIALIZABLE:最高的隔离级别,确保事务之间完全隔离,每个事务都像是在独立运行。在这个级别下,事务不会读取到其他事务已提交或未提交的更改,可以避免脏读、不可重复读和幻读,但是会降低并发性能。
spring.datasource.hikari.transaction-isolation=DEFAULT
#连接验证超时时间,指连接在被取出后最大等待数据库验证的时间,单位是毫秒
spring.datasource.hikari.validation-timeout=3000
#用于测试连接的 SQL 查询语句
spring.datasource.hikari.connection-test-query=SHOW TABLES
2.3 日志输出配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 定义输出到控制台的日志记录器 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 设置日志输出格式 -->
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--打印数据库连接池日志信息-->
    <logger name="com.zaxxer.hikari" level="DEBUG"/>
    <!--打印sql信息-->
    <logger name="com.luojie.dao" level="DEBUG"/>

    <!-- 设置根日志级别为 INFO -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/> <!-- 将日志输出到控制台 -->
    </root>

</configuration>
2.4 datasourceConfig 编写(重要)
package com.luojie.config;

import com.zaxxer.hikari.HikariDataSource;
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.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.luojie.dao.mapper1", sqlSessionFactoryRef = "sqlSessionFactory1")
public class DataSource1Config {

    @Value("${datasource1.url}")
    private String url;
    @Value("${datasource1.username}")
    private String username;
    @Value("${datasource1.password}")
    private String password;

    @Bean(name = "dataSource1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create()
                .url(url)
                .username(username)
                .password(password)
                // 使用HikariCP数据连接池管理
                .type(HikariDataSource.class)
                .build();
    }

    @Bean(name = "sqlSessionFactory1")
    public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:rojerTestMapper/mapper1/*.xml"));
        return sessionFactoryBean.getObject();
    }
}
package com.luojie.config;

import com.zaxxer.hikari.HikariDataSource;
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.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.luojie.dao.mapper2", sqlSessionFactoryRef = "sqlSessionFactory2")
public class DataSource2Config {

    @Value("${datasource2.url}")
    private String url;
    @Value("${datasource2.username}")
    private String username;
    @Value("${datasource2.password}")
    private String password;

    @Bean(name = "dataSource2")
    public DataSource dataSource1() {
        return DataSourceBuilder.create()
                .url(url)
                .username(username)
                .password(password)
                // 使用HikariCP数据连接池管理
                .type(HikariDataSource.class)
                .build();
    }

    @Bean(name = "sqlSessionFactory2")
    public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource2") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:rojerTestMapper/mapper2/*.xml"));
        return sessionFactoryBean.getObject();
    }

}

3. 业务代码编写

3.1 controller 
package com.luojie.controller;

import com.luojie.controImpl.DatabaseTestImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DatabaseTestController {

    @Autowired
    DatabaseTestImpl test;

    @GetMapping("/database/test")
    public void test1() {
        test.add();
    }
}
3.2 impl
package com.luojie.controImpl;

import com.luojie.dao.mapper1.Mapper1;
import com.luojie.dao.mapper2.Mapper2;
import com.luojie.moudle.LibraryModel;
import com.luojie.moudle.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DatabaseTestImpl {

    @Autowired
    private Mapper1 mapper1;

    @Autowired
    private Mapper2 mapper2;

    public void add() {
        UserModel userModel = new UserModel();
        userModel.setUsername("Rojer");
        userModel.setSex("男");
        userModel.setUserid("007");
        userModel.setRoles("admin,member");
        userModel.setMoney("10");

        LibraryModel libraryModel = new LibraryModel();
        libraryModel.setId(1);
        libraryModel.setAmount(1);
        mapper2.addLibrary(libraryModel);
        mapper2.addUserBalance(userModel);
        mapper1.addUser(userModel);
    }
}
3.3 model文件
package com.luojie.moudle;

import lombok.Data;

@Data
public class UserModel {

    private String username;

    private String money;

    private String sex;

    private String roles;

    private String userid;
}
package com.luojie.moudle;

import lombok.Data;

import java.math.BigDecimal;

@Data
public class LibraryModel {

    private String name;

    private BigDecimal price;

    private int amount;

    private int id;
}
3.4 mapper接口

注意这里放的位置一定要与前面config中配置的一致

package com.luojie.dao.mapper1;

import com.luojie.moudle.UserModel;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface Mapper1 {
    void addUser(UserModel userModel);
}
package com.luojie.dao.mapper2;

import com.luojie.moudle.LibraryModel;
import com.luojie.moudle.UserModel;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface Mapper2 {

    void addUserBalance(UserModel model);

    void addLibrary(LibraryModel model);
}
3.5 mapper.xml
<?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> 标签用于定义 Mapper XML 文件。-->
<!--namespace 属性指定了该 Mapper XML 文件对应的 Mapper 接口的类路径。-->
<mapper namespace="com.luojie.dao.mapper1.Mapper1">

    <select id="addUser">
        insert into userpro (`userid`, `roles`, `username`) values (#{userid}, #{roles}, #{username})
    </select>
</mapper>
<?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> 标签用于定义 Mapper XML 文件。-->
<!--namespace 属性指定了该 Mapper XML 文件对应的 Mapper 接口的类路径。-->
<mapper namespace="com.luojie.dao.mapper2.Mapper2">

    <update id="addUserBalance" parameterType="com.luojie.moudle.UserModel">
        update user set money = money + #{money} where userid = #{userid}
    </update>

    <update id="addLibrary" parameterType="com.luojie.moudle.LibraryModel">
        update library set amount = amount + #{amount} where id = #{id}
    </update>
</mapper>

四,代码测试

sql和连接池都是正常打印日志的

整体执行ok

希望对各位大佬有帮助。麻烦加个关注点个赞谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1806991.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【PLG洞察】| 飞书成功之路:关键在分销裂变

引言 随着企业服务市场的发展&#xff0c;Product-Led Growth&#xff08;PLG&#xff0c;产品驱动增长&#xff09;模式逐渐成为众多SaaS企业的首选战略。在这个背景下&#xff0c;字节跳动旗下的企业协作与管理平台——飞书&#xff0c;凭借其独特的分销裂变策略&#xff0c…

【教程】让小爱音箱Play增强版接入Mi-GPT

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 项目地址&#xff1a;https://github.com/idootop/mi-gpt MiIOT&#xff1a;小米小爱音箱Play 增强版 - 产品规格 - Xiaomi Miot Spec 实现效果图&…

ABC 357 G Stair-like Grid

link 其实是我之前写的一篇博客的推广 大意&#xff1a; 一个阶梯型&#xff0c;第 i i i行有 ⌈ i / 2 ⌉ ∗ 2 \left \lceil i/2 \right \rceil*2 ⌈i/2⌉∗2个方块&#xff0c;总共有n行。在其中给定 m m m个点无法经过&#xff0c;求从左上角到右下角的方案数。其中每次移…

macOS优化工具CleanMyMac2024免费版电脑性能提升 存储空间释放 电脑维护 高效易用 延长电脑使用寿命

【CleanMyMac】是一款专为macOS系统设计的优化和清理软件&#xff0c;它的核心特性就是帮助我们提升电脑性能&#xff0c;释放存储空间。&#x1f680; CleanMyMac绿色免费版下载如下&#xff1a;记得保存哈&#xff0c;以防失效&#xff1a; https://pan.quark.cn/s/9b08114…

【电机控制】FOC算法验证步骤

【电机控制】FOC算法验证步骤 文章目录 前言一、PWM——不接电机1、PWMA-H-50%2、PWMB-H-25%3、PWMC-H-0%4、PWMA-L-50%5、PWMB-L-75%6、PWMC-L-100% 二、ADC——不接电机1.电流零点稳定性、ADC读取的OFFSET2.电流钳准备3.运放电路分析1.电路OFFSET2.AOP3.采样电路的采样值范围…

Spring03-依赖注入(DI)

依赖注入 概念 依赖注入&#xff08;Dependency Injection,DI&#xff09;。 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 . 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 . 构造器注入 前面已经介绍过&#xff0c;参考4、IOC创建对象的方式 Set方…

2024最新华为OD机试-C/D卷 - 在线OJ使用说明

文章目录 &#x1fa90;在线 OJ 入口&#x1f3a7;申请OD使用权限&#x1f353;在线 OJ 的使用说明OJ主界面专题系列语言支持评测结果 &#x1fa90;在线 OJ 入口 &#x1f517; 2024最新华为OD机试 - 在线OJ入 &#x1f3a7;申请OD使用权限 本专栏配套 OJ 的为了配合考友更高…

Vue数据动态代理机制的实现

Object.defineProperty() &#xff08;1&#xff09;这个方法是ES5新增的 &#xff08;2&#xff09;这个方法的作用是&#xff1a;给对象新增属性&#xff0c;或者设置对象原有的属性 &#xff08;3&#xff09;用法&#xff1a;Object.defineProperty(给哪个对象新增属性,‘…

【简单介绍下DALL-E2,什么是DALL-E2?】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

Functional ALV系列 (09) - 双击跳转到另外一个ALV

在查看数据的时候&#xff0c;不总是只有一个界面&#xff0c;为了让用户更方便地查看数据&#xff0c;需要根据当前的数据跳转到另外的界面中&#xff0c;比如查看明细等。本文演示 ALV 比较实用的功能&#xff1a;双击 ALV 单元格跳转到另外一个 ALV 中。 要实现的业务场景&…

Diffusers代码学习: 多个Adapter

T2I Adapter也是可组合的&#xff0c;允许您使用多个适配器对图像施加多个控制条件。例如&#xff0c;可以使用姿势贴图提供结构控制&#xff0c;使用深度贴图进行深度控制。这是由[MultiAdapter]类启用的。 让我们用姿势和深度适配器来调节文本到图像的模型。创建深度和姿势图…

树状数组的基础

树状数组1 树状数组可以解决什么问题呢&#xff1f; 可以解决大部分区间上面的修改以及查询的问题&#xff0c;例如1.单点修改&#xff0c;单点查询&#xff0c;2.区间修改&#xff0c;单点查询&#xff0c;3.区间查询&#xff0c;区间修改&#xff0c;换言之&#xff0c;线段…

大模型应用工程化过程

近年来&#xff0c;以人工智能为代表的新一代信息技术加速应用&#xff0c;特 别是基于大模型、大数据、大算力的 ChatGPT 的发布&#xff0c;标志着人 工智能技术取得里程碑式突破&#xff0c;推动科技创新进入新阶段。随着 大模型技术的迅猛发展和场景价值的不断涌现&#xf…

React:Expected property name or ‘}‘ in JSON at position 1

代码&#xff1a; import { Form, Input, Button } from antd export default function FormCom() {function onFinish(a, b, c, d) {console.log(a, b, c, d)}const describe "{tip:请输入用户名}"return (<><Form onFinish{onFinish}><Form.Itemn…

C++面试八股文:static和const的关键字有哪些用法?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C工程师开发岗位第7面&#xff1a; 面试官&#xff1a;C中&#xff0c;static和const的关键字有哪些用法? 二师兄&#xff1a;satic关键字主要用在以下三个方面&#xff1a;1.用在全局作用域&#xff0c;修饰的变量或者…

嵌入式学习——Linux高级编程复习(进程)——day39

1. 进程 进程是计算机科学中的一个核心概念&#xff0c;它是操作系统进行资源分配和调度的基本单位&#xff0c;代表了一个正在执行中的程序实例。当一个程序被加载到内存并开始执行时&#xff0c;它就变成了一个进程。 1. 程序&#xff1a;存放在外存中的一段代码的集合 2. 进…

HTML标签 label for 还是 htmlFor

文章目录 问题结论更多 问题 HTML标签&#xff1a; label 的属性 for 还是 htmlFor&#xff1f; MDN文档&#xff1a;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label 结论 for 和 htmlFor 都可以使用&#xff0c;都是对的。在部分情况中&#xff0c;只能…

window wsl2的ubuntu如何配置代理获取docker image

最近两天&#xff0c;docker pull一直下不来docker image, 研究了下可以通过代理pull, 我的是window电脑下的linux子系统wsl2, 装的是ubuntu跑docker. # 创建/etc/systemd/system/docker.service.d路径 sudo mkdir -p /etc/systemd/system/docker.service.d # 创建 http-proxy…

C++设计模式-中介者模式,游戏对象之间的碰撞检测

运行在VS2022&#xff0c;x86&#xff0c;Debug下。 31. 中介者模式 中介者模式允许对象之间通过一个中介者对象进行交互&#xff0c;而不是直接相互引用。可以减少对象之间的直接耦合&#xff0c;同时集中化管理复杂的交互。应用&#xff1a;如在游戏开发中&#xff0c;可以使…

BERT+PET方式数据处理

基于BERTPET方式数据预处理介绍 BERTPET方式数据预处理&#x1f43e; 本项目中对数据部分的预处理步骤如下: 查看项目数据集编写Config类项目文件配置代码编写数据处理相关代码 1 查看项目数据集&#x1f43e; 数据存放位置&#xff1a;/Users/***/PycharmProjects/llm/prom…