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 对这个驱动进行了封装

相关内容

热门资讯

怎么解除订阅安卓系统,安卓系统... 你是不是也和我一样,手机里订阅了好多服务,结果现在想解除订阅,却一头雾水?别急,今天就来手把手教你如...
安卓系统停用怎么开启,轻松恢复... 亲爱的手机控们,你是否曾经遇到过安卓系统突然停用的情况,让你手忙脚乱,不知所措?别担心,今天就来教你...
安卓系统电池健康度,电池健康度... 你有没有发现,你的安卓手机最近是不是有点儿不给力了?电池续航能力大不如前,充电速度也慢了不少?别急,...
安卓系统按键怎么截图,安卓系统... 你是不是也和我一样,有时候想截个图分享给朋友,却发现安卓手机的截图功能有点神秘呢?别急,今天就来手把...
购票系统安卓源代码,架构设计与... 你有没有想过,那些我们每天离不开的购票系统,它们背后的秘密是什么呢?今天,就让我带你一探究竟,揭开购...
安卓手机系统后台测试,深度解析... 你有没有发现,你的安卓手机后台总是悄悄地忙碌着?别小看了这些后台程序,它们可是手机系统稳定运行的关键...
安卓系统重启的图标,解锁设备新... 手机突然重启,是不是心里有点慌?别急,今天就来和你聊聊安卓系统重启的图标,让你一眼就能认出它,再也不...
车载智慧屏安卓系统,智能出行新... 你有没有发现,现在的车载智慧屏越来越智能了?尤其是那些搭载了安卓系统的,简直就像是个移动的小电脑,不...
安卓系统连上网权限,解锁设备无... 你有没有发现,你的安卓手机里有些应用总是偷偷连上网?别小看这个小小的网络权限,它可是能影响你隐私、消...
安卓谷歌操作系统,探索安卓谷歌... 你知道吗?在智能手机的世界里,有一个操作系统可是无人不知、无人不晓,那就是安卓谷歌操作系统。它就像一...
安卓系统手写%怎样调出,具体实... 你有没有遇到过这种情况:在使用安卓手机的时候,突然想用手写输入法来记录一些灵感或者重要信息,可是怎么...
安卓手机重置 系统设置,轻松恢... 手机用久了是不是感觉卡顿得厉害?别急,今天就来教你怎么给安卓手机来个大变身——重置系统设置!想象你的...
win如何安装安卓系统,Win... 哇,你有没有想过,让你的Win系统也能玩转安卓应用?没错,就是那种在手机上轻松自如的安卓系统,现在也...
苹果qq和安卓系统,跨平台体验... 你有没有发现,现在手机市场上,苹果和安卓的较量可是越来越激烈了呢!咱们就来聊聊这个话题,看看苹果QQ...
显示最好的安卓系统,探索最新旗... 你有没有想过,为什么安卓系统那么受欢迎呢?它就像一个魔法盒子,里面装满了各种神奇的魔法。今天,就让我...
安卓app怎么降级系统,系统版... 你有没有发现,有时候安卓手机的系统更新后,新功能虽然炫酷,但老系统用起来更顺手呢?别急,今天就来教你...
雷军脱离安卓系统,引领科技变革... 你知道吗?最近科技圈可是炸开了锅,因为我们的雷军大大竟然宣布要脱离安卓系统,这可真是让人大跌眼镜啊!...
安卓系统自动开网络,安卓系统自... 你有没有发现,手机里的安卓系统有时候会自动开启网络连接,这可真是让人又爱又恨啊!有时候,你正专心致志...
安卓系统怎样控制后台,因为服务... 手机里的安卓系统是不是感觉越来越卡了?后台程序太多,不仅耗电还影响性能。别急,今天就来教你怎么巧妙地...
安卓系统打游戏推荐,一触即达! 你有没有发现,现在手机游戏越来越好玩了?不管是休闲小游戏还是大型MMORPG,都能在手机上畅玩。但是...