JavaJDBC:连接池
admin
2024-03-31 04:33:34
0

本篇内容包括:数据库连接池概述、JDBC 连接池原理、JDBC 连接池 Demo(addBatch demo、获取主键 demo、查看数据库的元数据 demo等)以及其他类型数据库连接池的介绍(比如 Druid)。

一、数据库连接池

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。

连接池优点:

  • 减少连接创建时间:虽然与其它数据库相比 GBase 提供了较为快速连接功能,但是创建新的 JDBC 连接仍会招致网络和 JDBC 驱动的开销。如果这类连接是“循环”使用的,使用该方式这些花销就可避免
  • 简化的编程模式:当使用连接池时,每一个单独的线程能够像创建了一个自己的 JDBC 连接一样操作,允许用户直接使用JDBC编程技术。
  • 受控的资源使用:如果用户不使用连接池,而是每当线程需要时创建一个新的连接,那么用户的应用程序的资源使用会产生非常大的浪费并且可能会导致高负载下的异常发生。连接池能够使性能最大化,同时还能将资源利用控制在一定的水平之下,如果超过该水平,应用程序将崩溃而不仅仅是变慢。

二、JDBC 连接池原理

JDBC 连接池的基本原理:

  1. 建立数据库连接池对象(服务器启动)。
  2. 按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。
  3. 对于一个数据库的访问请求,直接从连接池中得到一个连接,如果数据库连接池对象中有空闲连接则直接使用、若没有空闲的链接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接来处理该请求,如果没有空闲连接并且达到最大活跃值则进行等待其它的链接释放再进行该请求的处理。
  4. 存取数据库。
  5. 关闭数据库,释放所有数据库连接(此时福安比数据库连接,并非真正的关闭,而是将其放入空闲队列中。如果实际空闲连接数大于初始空闲连接数则释放连接)。
  6. 释放数据库连接池对象(在服务器停止、维护期间,真正的释放数据库连接池对象,并释放所有资源)。

三、JDBC 连接池 Demo

1、添加 Maven 依赖

        commons-dbcpcommons-dbcp1.4

2、添加一个配置文件 src/resources/jdbc.properties

# 配置数据库的连接信息
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/databaseName
username=userName
password=password

3、添加 DbUtils2 类

public class DbUtils2 {private static String driver;private static String url;private static String username;private static String password;/*** 声明数据源,用于配置数据库的链接信息*/private static BasicDataSource dataSource;static {Properties prop = new Properties();InputStream ips = DbUtils2.class.getClassLoader().getResourceAsStream("jdbc.properties");try {//加载配置文件prop.load(ips);//获取我们在配置文件中配置的driver等信息driver = prop.getProperty("driver");url = prop.getProperty("url");username = prop.getProperty("username");password = prop.getProperty("password");//创建数据源dataSource = new BasicDataSource();//设置数据库的连接信息:dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);//设置初始连接数量dataSource.setInitialSize(3);//设置最大连接数量dataSource.setMaxActive(3);} catch (IOException e) {e.printStackTrace();} finally {try {//关闭资源ips.close();} catch (IOException e) {e.printStackTrace();}}}public static Connection getConn() throws Exception {// 从连接池中获取连接Connection conn = dataSource.getConnection();return conn;}public static void close(Connection conn, Statement stat, ResultSet rs) {try {if (rs != null) {rs.close();}} catch (SQLException e) {e.printStackTrace();}try {if (stat != null) {stat.close();}} catch (SQLException e) {e.printStackTrace();}try {if (conn != null) {//打开自动提交conn.setAutoCommit(true);conn.close();}} catch (SQLException e) {e.printStackTrace();}}
}

4、使用 PrepareStatement 来实现登陆验证(可以避免SQL注入):

    public static void main(String[] args) {Scanner scan = new Scanner(System.in);System.out.println("请输入用户名");String username = scan.nextLine();Scanner scr = new Scanner(System.in);System.out.println("请输入密码");String password = scr.nextLine();boolean b = login(username, password);if (b) {System.out.println("登陆成功");} else {System.out.println("登录失败");}}private static boolean login(String username, String password) {String sql = "select count(*) from table_user where username=? and password=?";Connection conn = null;PreparedStatement stat = null;ResultSet rs = null;try {conn = DbUtils2.getConn();stat = conn.prepareStatement(sql);stat.setString(1, username);stat.setString(2, password);rs = stat.executeQuery();while (rs.next()) {//得到查询的数量int count = rs.getInt(1);if (count > 0) {return true;}}} catch (Exception e) {e.printStackTrace();} finally {DbUtils2.close(conn, stat, rs);}return false;}

5、addBatch 批量操作 demo(使用Statement对象)

    @Testpublic void testAddBatch01() {String sql1 = "insert into table_user values(null,'悟空','aaa')";String sql2 = "insert into table_user values(null,'八戒','bbb')";String sql3 = "insert into table_user values(null,'沙僧','ccc')";Connection conn = null;Statement stat = null;ResultSet rs = null;try {conn = DbUtils2.getConn();stat = conn.createStatement();stat.addBatch(sql1);stat.addBatch(sql2);stat.addBatch(sql3);//执行批量操作stat.executeBatch();} catch (Exception e) {e.printStackTrace();} finally {DbUtils2.close(conn, stat, rs);}}

6、addBatch 批量操作 demo(使用PrepareStatement对象)

    @Testpublic void testAddBatch02() {String sql = "insert into table_user values(null,?,?)";Connection conn = null;PreparedStatement stat = null;ResultSet rs = null;try {conn = DbUtils2.getConn();stat = conn.prepareStatement(sql);stat.setString(1, "刘备");stat.setString(2, "aaa");//添加到批量处理stat.addBatch();stat.setString(1, "关羽");stat.setString(2, "bbb");stat.addBatch();stat.setString(1, "张飞");stat.setString(2, "ccc");stat.addBatch();stat.executeBatch();} catch (Exception e) {e.printStackTrace();} finally {DbUtils2.close(conn, stat, rs);}}

7、addBatch 批量操作 demo(避免内存溢出)

    @Testpublic void testAddBatch03() {String sql = "insert into table_user values(null,?,?)";Connection conn = null;PreparedStatement stat = null;ResultSet rs = null;try {conn = DbUtils2.getConn();stat = conn.prepareStatement(sql);for (int i = 0; i < 100; i++) {stat.setString(1, "name" + i);stat.setString(2, "admin");stat.addBatch();//下面写法可以避免内存溢出if (i % 20 == 0) {stat.executeBatch();//清除批处理内容stat.clearBatch();}}stat.executeBatch();} catch (Exception e) {e.printStackTrace();} finally {DbUtils2.close(conn, stat, rs);}}

8、获取主键 demo

    @Testpublic void testPrimaryKey() {Connection conn = null;Statement stat = null;ResultSet rs = null;try {conn = DbUtils2.getConn();stat = conn.createStatement();String sql = "insert into table_user values(null,'小明','abc')";//执行SQL并且制定需要获取自增主键值stat.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);//获取返回的主键值rs = stat.getGeneratedKeys();while (rs.next()) {int id = rs.getInt(1);System.out.println("自增主键" + id);}} catch (Exception e) {e.printStackTrace();} finally {DbUtils2.close(conn, stat, rs);}}

9、查看数据库的元数据 demo

    @Testpublic void testMetadata() {Connection conn = null;Statement stat = null;ResultSet rs = null;try {conn = DbUtils2.getConn();stat = conn.createStatement();//得到数据库的元数据DatabaseMetaData dbData = conn.getMetaData();System.out.println("驱动版本:" + dbData.getDriverMajorVersion());System.out.println("用户名:" + dbData.getUserName());System.out.println("链接地址:" + dbData.getURL());System.out.println("数据库名称:" + dbData.getDatabaseProductName());//获取表相关的元数据rs = stat.executeQuery("select * from table_user");ResultSetMetaData rsData = rs.getMetaData();//得到表字段的数量int count = rsData.getColumnCount();for (int i = 0; i < count; i++) {String name = rsData.getColumnName(i + 1);String type = rsData.getColumnTypeName(i + 1);System.out.println(name + ":" + type);}} catch (Exception e) {e.printStackTrace();} finally {DbUtils2.close(conn, stat, rs);}}

四、其他类型数据库连接池

在 Java 程序中,开源的数据库连接池有以下几种 :

  1. C3P0:是一个开放源代码的 JDBC 连接池,它在 lib 目录中与 Hibernate 一起发布,包括了实现 jdbc3 和 jdbc2 扩展规范说明的 Connection 和 Statement 池的 DataSources 对象
  2. Proxool:是一个 Java SQL Driver 动程序,提供了对选择的其它类型的驱动程序的连接池封装。可以非常简单的移植到现存的代码中,完全可配置,快速、成熟、健壮。可以透明地为现存的JDBC驱动程序增加连接池功能。
  3. Jakarta DBCP:DBCP 是一个依赖 Jakarta commons-pool 对象池机制的数据库连接池。DBCP 可以直接的在应用程序中使用
  4. DDConnectionBroker:是一个简单、轻量级的数据库连接池
  5. DBPool:是一个高效、易配置的数据库连接池。它除了支持连接池应有的功能之外,还包括了一个对象池,使用户能够开发一个满足自己需求的数据库连接池
  6. XAPool:是一个 XA 数据库连接池。它实现了 javax.sql.XADataSource 并提供了连接池工具
  7. rimrose:是一个 Java 开发的数据库连接池。当前支持的容器包括 Tomcat4&5、Resin3 与J Boss3。它同样也有一个独立的版本,可以在应用程序中使用而不必运行在容器中。Primrose 通过一个 Web 接口来控制 SQL 处理的追踪、配置,以及动态池管理。在重负荷的情况下可进行连接请求队列处理
  8. SmartPool:是一个连接池组件,它模仿应用服务器对象池的特性。SmartPool 能够解决一些临界问题如连接泄漏(connection leaks)、连接阻塞、打开的 JDBC 对象(如Statements、PreparedStatements)等
  9. MiniConnectionPoolManager:是一个轻量级 JDBC 数据库连接池。它只需要 Java1.5(或更高)并且没有依赖第三方包
  10. BoneCP:是一个快速、开源的数据库连接池。帮用户管理数据连接,让应用程序能更快速地访问数据库。比C3P0/DBCP连接池速度快25倍
  11. Druid(推荐):Druid 不仅是一个数据库连接池,还包含一个 ProxyDriver、一系列内置的 JDBC 组件库、一个 SQL Parser,Druid 支持所有JDBC兼容的数据库,包括 Oracle、MySql、Derby、Postgresql、SQL Server、H2 等。 Druid 针对 Oracle 和 MySql 做了特别优化,比如:
    • Oracle 的 PS Cache 内存占用优化
    • MySql 的 ping检测优化
    • Druid 提供了 MySql、Oracle、Postgresql、SQL-92 的 SQL 的完整支持,这是一个手写的高性能 SQL Parser,支持 Visitor 模式,使得分析 SQL 的抽象语法树很方便。
    • 简单 SQL 语句用时 10 微秒以内,复杂 SQL 用时 30 微秒。
    • 通过 Druid 提供的 SQL Parser 可以在 JDBC 层拦截 SQL 做相应处理,比如说分库分表、审计等。Druid 防御SQL注入攻击的 WallFilter,就是通过 Druid 的 SQL Parser 分析语义实现的

这些池底层都是对 driver-class-name=com.mysql.jdbc.Driver 对这个驱动进行了封装

相关内容

热门资讯

【MySQL】锁 锁 文章目录锁全局锁表级锁表锁元数据锁(MDL)意向锁AUTO-INC锁...
【内网安全】 隧道搭建穿透上线... 文章目录内网穿透-Ngrok-入门-上线1、服务端配置:2、客户端连接服务端ÿ...
GCN的几种模型复现笔记 引言 本篇笔记紧接上文,主要是上一篇看写了快2w字,再去接入代码感觉有点...
数据分页展示逻辑 import java.util.Arrays;import java.util.List;impo...
Redis为什么选择单线程?R... 目录专栏导读一、Redis版本迭代二、Redis4.0之前为什么一直采用单线程?三、R...
【已解决】ERROR: Cou... 正确指令: pip install pyyaml
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
Lock 接口解读 前置知识点Synchronized synchronized 是 Java 中的关键字,...
Win7 专业版安装中文包、汉... 参考资料:http://www.metsky.com/archives/350.htm...
3 ROS1通讯编程提高(1) 3 ROS1通讯编程提高3.1 使用VS Code编译ROS13.1.1 VS Code的安装和配置...
大模型未来趋势 大模型是人工智能领域的重要发展趋势之一,未来有着广阔的应用前景和发展空间。以下是大模型未来的趋势和展...
python实战应用讲解-【n... 目录 如何在Python中计算残余的平方和 方法1:使用其Base公式 方法2:使用statsmod...
学习u-boot 需要了解的m... 一、常用函数 1. origin 函数 origin 函数的返回值就是变量来源。使用格式如下...
常用python爬虫库介绍与简... 通用 urllib -网络库(stdlib)。 requests -网络库。 grab – 网络库&...
药品批准文号查询|药融云-中国... 药品批文是国家食品药品监督管理局(NMPA)对药品的审评和批准的证明文件...
【2023-03-22】SRS... 【2023-03-22】SRS推流搭配FFmpeg实现目标检测 说明: 外侧测试使用SRS播放器测...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
初级算法-哈希表 主要记录算法和数据结构学习笔记,新的一年更上一层楼! 初级算法-哈希表...
进程间通信【Linux】 1. 进程间通信 1.1 什么是进程间通信 在 Linux 系统中,进程间通信...
【Docker】P3 Dock... Docker数据卷、宿主机与挂载数据卷的概念及作用挂载宿主机配置数据卷挂载操作示例一个容器挂载多个目...