zoukankan      html  css  js  c++  java
  • spring boot项目19:RDBMS连接池

    JAVA 8

    Spring Boot 2.5.3

    MySQL 5.7.21

    Druid 1.2.6(2021-5-5发布)

    ---

    目录

    1、序章

    2、使用默认HikariCP数据库

    操作数据库

    3、使用Druid

    访问/druid/*端点

    参考文档

    1、序章

    数据库连接池 使应用可以重复使用一个已经建立的数据库连接,从而提高操作数据库的性能。

    在Java开发中,常见的数据库连接池如下:来自博客园

    C3P0

    DBCP

    BoneCP

    HikariCP

    Druid

    本文展示在Spring Boot应用中使用下面2种数据库连接池:

    1)HikariCP、2)Druid

    其中,HikariCP是S.B.应用默认的数据库连接池。

    在S.B.官文的 4.11. Working with SQL Databases 中,提到支持的连接池如下:

    HikariCP、 Tomcat pooling DataSource、Commons DBCP2、Oracle UCP。

    首选HikariCP 是处于 性能和并发性(performance and concurrency) 的考虑。

    Spring Boot uses the following algorithm for choosing a specific implementation:
    1. We prefer HikariCP for its performance and concurrency. If HikariCP is available, we always
    choose it.
    2. Otherwise, if the Tomcat pooling DataSource is available, we use it.
    3. Otherwise, if Commons DBCP2 is available, we use it.
    4. If none of HikariCP, Tomcat, and DBCP2 are available and if Oracle UCP is available, we use it.

    注,本文操作的目标数据库为 MySQL 5.7.21来自博客园

    2、使用默认HikariCP数据库

    新建Web项目 dbpool-hello,端口9000,使用Spring Data JPA操作数据库。

    项目依赖:

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-test</artifactId>
    	<scope>test</scope>
    </dependency>
    
    <dependency>
    	<groupId>org.projectlombok</groupId>
    	<artifactId>lombok</artifactId>
    </dependency>
    <dependency>
    	<groupId>mysql</groupId>
    	<artifactId>mysql-connector-java</artifactId>
    	<scope>runtime</scope>
    </dependency>

    项目配置——MySQL数据库连接池部分,spring.datasource.*

    # MySQL on Ubuntu
    spring.datasource.url=jdbc:mysql://mylinux:3306/db_example?serverTimezone=Asia/Shanghai
    spring.datasource.username=springuser
    spring.datasource.password=ThePassword
    #spring.datasource.driver-class-name =com.mysql.jdbc.Driver # This is deprecated
    spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
    # 打开使用过程中执行的SQL语句
    spring.jpa.show-sql=true

    启动项目,可以看到Spring容器中有很多Bean有“DataSource”字符串:来自博客园

    name=org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari, bean=org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari@7bebcd65
    name=dataSource, bean=HikariDataSource (HikariPool-1)
    name=org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration$Hikari, bean=org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration$Hikari@1e00bfe2
    name=org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration, bean=org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration@4702e7a5
    name=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$PooledDataSourceConfiguration, bean=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$PooledDataSourceConfiguration@6a2d867d
    name=org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration, bean=org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration@e322ec9
    name=hikariPoolDataSourceMetadataProvider, bean=org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration$$Lambda$623/777970377@4d0753c9
    name=org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration, bean=org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration@73bb1337
    name=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, bean=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration@685f5d0d
    name=spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties, bean=org.springframework.boot.autoconfigure.jdbc.DataSourceProperties@21c7208d
    

    启动日志中,还有下面两行:表明建立了HikariDataSource对象

    com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
    com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.

    除了生产了 dataSource Bean,操作RDB时还生成了jdbcTemplate Bean,它会使用了 dataSource Bean。

    其中,名为dataSource 的Bean的类型为 HikariDataSource (HikariPool-1)。

    添加dataSource Bean检查接口:

    /ds/check/get 接口
    @RestController
    @RequestMapping(value="/ds/check")
    public class CheckDatasource {
    
    	private static Consumer<Object> cs = System.out::println;
    
    	@Autowired
    	private DataSource datasource;
    	
    	@GetMapping("/get")
    	public Boolean get() {
    		cs.accept("datasource=" + datasource);
    		cs.accept("datasource.class=" + datasource.getClass());
    		try {
    			cs.accept("datasource.getLoginTimeout=" + datasource.getLoginTimeout());
    		} catch (SQLException e) {
    			cs.accept("getLoginTimeout() SQLException e=" + e.getClass());
    		}
    		try {
    			Connection conn = datasource.getConnection();
    			cs.accept("conn=" + conn);
    			cs.accept("conn.Catalog=" + conn.getCatalog());
    			cs.accept("conn.NetworkTimeout=" + conn.getNetworkTimeout());
    			cs.accept("conn.Schema=" + conn.getSchema());
    			cs.accept("conn.TransactionIsolation=" + conn.getTransactionIsolation());
    			cs.accept("conn.ClientInfo=" + conn.getClientInfo());
    			DatabaseMetaData md = conn.getMetaData();
    			cs.accept("conn.md=" + md);
    			cs.accept("conn.md.DriverName=" + md.getDriverName());
    			cs.accept("conn.md.DriverVersion=" + md.getDriverVersion());
    			cs.accept("conn.md.DatabaseProductName=" + md.getDatabaseProductName());
    			cs.accept("conn.md.DatabaseProductVersion=" + md.getDatabaseProductVersion());
    		} catch (SQLException e) {
    			cs.accept("datasource.getConnection() SQLException e=" + e.getClass());
    		}
    		
    		return true;
    	}
    	
    }

    调用 /ds/check/get 接口,返回true。检查应用日志:接口输出下面的内容。来自博客园

    datasource=HikariDataSource (HikariPool-1)
    datasource.class=class com.zaxxer.hikari.HikariDataSource
    datasource.getLoginTimeout=30
    conn=HikariProxyConnection@2078797209 wrapping com.mysql.cj.jdbc.ConnectionImpl@6636c130
    conn.Catalog=db_example
    conn.NetworkTimeout=0
    conn.Schema=null
    conn.TransactionIsolation=4
    conn.ClientInfo={}
    conn.md=HikariProxyDatabaseMetaData@1524225169 wrapping com.mysql.cj.jdbc.DatabaseMetaData@5038dad0
    conn.md.DriverName=MySQL Connector/J
    conn.md.DriverVersion=mysql-connector-java-8.0.26 (Revision: 9aae1e450989d62c06616c1dcda3e404ef84df70)
    conn.md.DatabaseProductName=MySQL
    conn.md.DatabaseProductVersion=5.7.21-1ubuntu1

    操作数据库

    // 实体类 Country.java
    @Entity
    @Data
    public class Country {
        // ...省略
    }
    
    // DAO层 CountryDAO.java
    public interface CountryDAO extends CrudRepository<Country, Long> {
        // 暂无内容
    }
    
    // 省略了服务层Service
    
    // 接口层 CountryApi.java
    @RestController
    @RequestMapping(value="/api/country")
    @Slf4j
    public class CountryApi {
    
    	@Autowired
    	private CountryDAO countryDao;
        
        // ...省略
    }
    

    本项目源码

    新增接口:

    1)增加Country POST /api/country/add

    2)根据ID查找 GET /api/country/getById

    启动项目,此时,数据库建立好了数据表:来自博客园

    测试:

    调用 POST /api/country/add,添加成功。

    调用 GET /api/country/getById,查找成功。

    数据库中数据:

    country表数据
    mysql> select * from country;
    +----+---------+---------------------+-----------------------+--------------------------------+---------------------+
    | id | area    | create_time         | name_cn               | name_en                        | update_time         |
    +----+---------+---------------------+-----------------------+--------------------------------+---------------------+
    |  1 | 9600000 | 2021-09-28 18:13:24 | 中华人民共和国        | the People's Republic of China | 2021-09-28 18:13:24 |
    |  2 | 9600000 | 2021-09-28 18:18:00 | 中华人民共和国        | the People's Republic of China | 2021-09-28 18:18:00 |
    +----+---------+---------------------+-----------------------+--------------------------------+---------------------+
    2 rows in set (0.01 sec)
    

    使用MySQL的 show processlist; 命令,可以看到应用已和数据库建立了 多个连接(HikariCP 的  默认连接数是 10):查询时状态都为 sleep

    10个连接是否够用?怎么配置HikariCP连接池?请看S.B.官文,其中,连接池配置以 “spring.datasource.”开头,HikariCP的特别配置 以“spring.datasource.hikari.”开头。

    比如,修改下面的配置,可以变更默认连接数:

    # 最小空闲线程数(默认为 10)
    spring.datasource.hikari.minimum-idle=5

    效果:

    3、使用Druid

    S.B.官文没有介绍怎么用Druid。来自博客园

    Druid官网也没找到介绍。

    最后在 https://mvnrepository.com/ 找到下面两个依赖包:

    既然是S.B.使用,那就使用第二个 Druid Spring Boot Starter。

    添加依赖:

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.6</version>
    </dependency>

    包结构如下:

    使用Druid,需要做什么配置吗?

    先启动项目看看。

    启动成功。

    启动日志中没有前面HikariCP的任何内容了!

    下面两句显示启动了Druid连接池:

    c.a.d.s.b.a.DruidDataSourceAutoConfigure : Init DruidDataSource
    com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited

    dataSource Bean被替换了?调用 /ds/check/get 检查。结果如下:

    Druid连接池信息
    datasource={
    	CreateTime:"2021-09-28 21:37:07",
    	ActiveCount:0,
    	PoolingCount:1,
    	CreateCount:1,
    	DestroyCount:0,
    	CloseCount:2,
    	ConnectCount:2,
    	Connections:[
    		{ID:1695012953, ConnectTime:"2021-09-28 21:37:08", UseCount:2, LastActiveTime:"2021-09-28 21:37:09"}
    	]
    }
    datasource.class=class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper
    datasource.getLoginTimeout=0
    2021-09-28 21:40:34.004  WARN 24124 --- [nio-9000-exec-1] c.a.druid.pool.DruidAbstractDataSource   : discard long time none received connection. , jdbcUrl : jdbc:mysql://mylinux:3306/db_example?serverTimezone=Asia/Shanghai, version : 1.2.5, lastPacketReceivedIdleMillis : 204760
    conn=com.mysql.cj.jdbc.ConnectionImpl@3e87a374
    conn.Catalog=db_example
    conn.NetworkTimeout=0
    conn.Schema=null
    conn.TransactionIsolation=4
    conn.ClientInfo={}
    conn.md=com.mysql.cj.jdbc.DatabaseMetaData@156d104d
    conn.md.DriverName=MySQL Connector/J
    conn.md.DriverVersion=mysql-connector-java-8.0.26 (Revision: 9aae1e450989d62c06616c1dcda3e404ef84df70)
    conn.md.DatabaseProductName=MySQL
    conn.md.DatabaseProductVersion=5.7.21-1ubuntu1

    dataSource Bean已经变为 DruidDataSourceWrapper对象了。来自博客园

    检查MySQL的连接:默认只有一个连接

    怎么修改Druid的配置呢?请看Druid的GitHub文档,参考文档2 也有一些介绍。

    测试:

    调用 POST /api/country/add,添加成功。

    调用 GET /api/country/getById,查找成功。

    访问/druid/*端点

    参考文档2 提到,HikariCP的性能 要好于 Druid(作者为测试),但是,Druid 的功能更全面(sql拦截、统计数据等(TODO))。

    根据参考文档2,编写下面的程序实现:

    @Configuration
    public class DruidConfig {
    
    	@Bean
    	public ServletRegistrationBean statViewServlet( ) {
    		ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(
    				new StatViewServlet(), "/druid/*");
    		
    		servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
    		
    		servletRegistrationBean.addInitParameter("loginUsername", "root");
    		servletRegistrationBean.addInitParameter("loginPassword", "root");
    		
    		servletRegistrationBean.addInitParameter("resetEnable", "false");
    		
    		return servletRegistrationBean;
    	}
    	
    }

    再次,启动应用,访问 http://localhost:9000/druid ,提示登录,登录后进入页面:

    这个页面更多的功能,Druid更多的使用,还需再探索。

    》》》全文完《《《来自博客园

    HikariCP、Druid的性能怎么测试、比较?

    HikariCP的优势是什么?

    Druid的优势是什么?

    必须用Druid替代HikariCP?

    连接数如何设置才合理?

    在多个应用链接MySQL时,MySQL服务器允许的连接数不够了会怎样?来自博客园

    在dataSource Bean的信息(get函数)中,没有发现 连接timeout 等参数,哪里找?还是说,没有?

    继续探索...

    参考文档

    1、数据库连接池

    2、常见的几种数据库连接池的配置和使用

    3、GitHub druid-spring-boot-starter项目

    这里有更完善的Druid使用、配置介绍。

    第一手资料

    4、

  • 相关阅读:
    串口通信理论知识
    串口通信基础
    串口中断程序步骤及代码
    Django之CRM项目Day6-公私户转换问题解决 班主任功能
    Django之CRM项目Day5-跳转页面 跟进记录 报名记录
    Django之CRM项目Day4-编辑客户 公私户 模糊查询
    Django之CRM项目Day3-客户展示及分页
    Django的ModelForm
    Django相关面试题
    Django基础自测
  • 原文地址:https://www.cnblogs.com/luo630/p/15350409.html
Copyright © 2011-2022 走看看