Algún resumen del grupo de conexiones de la base de datos

¡Continúe creando, acelere el crecimiento! Este es el cuarto día de mi participación en el "Nuevo plan diario de Nuggets · Desafío de actualización de junio", [Haga clic para ver los detalles del evento]

¿Qué es el grupo de conexiones?

El conjunto de conexiones de la base de datos es para crear una cierta cantidad de objetos de conexión de la base de datos cuando se inicializa el programa y guardarlos en un área de memoria, lo que permite que la aplicación reutilice una conexión de base de datos existente en lugar de restablecerla ; libere el tiempo de inactividad que exceda el tiempo máximo de inactividad Conexiones de base de datos cronometradas para evitar perder conexiones de base de datos debido a que no se liberan conexiones de base de datos.

¿Por qué utilizar la agrupación de conexiones?

De hecho, cuando el volumen de negocios no es grande y la concurrencia no es grande, por ejemplo, si escribimos nuestros propios experimentos, la conexión se puede establecer temporalmente. Sin embargo, en la empresa tenemos una gran cantidad de concurrencia, llegando a niveles de 100 o 1000. Las operaciones de establecimiento y cierre de conexiones causarán cuellos de botella en el rendimiento, por lo que se deben considerar los pools de conexiones para optimizar las operaciones:

  1. Saque la conexión (cuando se inicie el servicio empresarial, inicialice varias conexiones y colóquelas en el almacenamiento de conexiones)
  2. Enviar una solicitud (cuando haya una solicitud, obténgala de la tienda de conexión)
  3. Vuelva a colocar la conexión (después de la ejecución, la conexión se vuelve a colocar en el almacén de conexiones)

Aquí, la estructura de datos del almacenamiento de la conexión y el mantenimiento de la conexión es el conjunto de conexiones.

La idea de poner en común la tecnología es principalmente reducir el consumo de recursos adquiridos cada vez y mejorar la utilización de los recursos.

Acerca de commons-dbutils

Después de aprender la arquitectura de tres niveles , sabemos que para el método general  de adición, eliminaciónexecute(String sql ,Object[] os) y modificación  , siempre que se pasen el parámetro sql y el parámetro de reemplazo os, se puede realizar la función correspondiente de adición, eliminación y modificación; pero para el método de consulta  query(String sql, Object[] os) , para poder ser universal , solo se puede encapsular en el conjunto de resultados  ResultSet , pero no puede seguir encapsulándose en tipos como objetos o colecciones.

Para resolver el problema de [encapsulación completa de adiciones, eliminaciones, cambios o verificación ], tenemos que usar una  commons-dbutils biblioteca de clases para implementarlo.

commons-dbutils 是 Apache 组织提供的一个 JDBC 工具类库,极大地简化了 JDBC 的代码量,并且不会影响程序的性能。

commons-dbutils 类库主要包含了两个类和一个接口,如下表:

全 名 类 或 接 口
org.apache.commons.dbutils.DbUtils class
org.apache.commons.dbutils.QueryRunner class
org.apache.commons.dbutils.ResultSetHandler intereface

DbUtils 类

DbUtils 是一个工具类,提供了关闭连接、事务提交/回滚、注册 JDBC 驱动程序等常用方法。DbUtils 类中的方法都是 public static 修饰的(除了构造方法),常用方法如下图所示。

图片描述

QueryRunner 类

QueryRunner 类主要用于执行增删改查等 SQL 语句。特别的,如果执行的是查询 SQL,还需要结合 ResultSetHandler 接口来处理结果集。QueryRunner 类的常用方法如下图所示。

图片描述

ResultSetHandler 接口及其实现类

ResultSetHandler 接口用于处理 ResultSet 结果集,它可以将结果集中的数据封装成单个对象、数组、List、Map 等不同形式。

ResultSetHandler 接口有很多不同的实现类,如下图所示。

图片描述

这里我们介绍一下事务

在学习事务管理之前,我们有必要了解一下 ThreadLocal<T> 类。

ThreadLocal 可以为变量在每个线程中都创建一个副本,每个线程都可以访问自己内部的副本变量。因此,ThreadLocal 被称为线程本地变量(或线程本地存储)。

观察下面的代码,思考哪些地方可能会引发的线程安全问题?

public class ConnectionManager {
    private static Connection conn = null;
    public static Connection getConnection() throws /*…*/    {
        if(conn == null)    {
               conn = DriverManager.getConnection(/*...*/);
           }
           return conn;
    }

    public static void closeConnection() throws /*…*/{
        if(conn!=null)
            conn.close();
    }
}
复制代码

多线程场景下引发的问题分析:

  1. 因为 conn 是静态全局变量(用于共享),那么就有可能在一个线程使用 conn 操作数据库时,另外一个线程也同时调用 closeConnection() 关闭连接。
  2. 如果多个线程同时进入 getConnection() 方法的 if 语句,那么就会多次创建 conn 对象。

关于上述问题,你可能会想到使用“线程同步”来解决:将 conn 变量、getConnection() 和 closeConnection() 使用 synchronized 进行同步处理。以上面的代码为例,“线程同步”虽然可以解决问题,但会造成极大的性能影响:因为使用了线程同步后,当一个线程正在使用 conn 访问数据库时,其它线程只能等待。

以上面代码为例,引发线程安全问题的实质是因为 conn 变量、getConnection() 和 closeConnection() 都是共享的 static 变量(或方法)而造成的。实际上,一个线程只需要维护自己的 conn 变量,而不需要关心其它线程是否对各自的 conn 进行了修改。因此,不用 static 修饰也是可以的,如下:

public class ConnectionManager {
    // 没有 static 修饰
    private Connection conn = null;
    // 没有 static 修饰
    public Connection getConnection() throws SQLException {
        if (conn == null) {
            conn = DriverManager.getConnection(/*...*/);
        }
        return conn;
    }
    // 没有 static 修饰
    public void closeConnection() throws SQLException {
        if (conn != null)
            conn.close();
    }
}
class Dao{
       public void insert() throws SQLException {
           // 将 connectionManager 和 conn 定义为局部变量
        ConnectionManager connectionManager = new ConnectionManager();
        Connection conn = connectionManager.getConnection();
        // 使用 conn 访问数据库...
        connectionManager.closeConnection();
    }
}
复制代码

以上代码,将 conn 及相关方法的 static 修饰符去掉,然后在每个使用 conn 的方法中(如 insert())都创建局部变量 conn。这样一来,因为每次都是在方法内部创建的连接,那么线程之间自然不存在线程安全问题。但是,由于在方法中的 conn 变量会在方法结束时自动释放空间,因此频繁的方法调用就会频繁地开启和关闭数据库连接,从而严重影响程序执行性能。

ThreadLocal<T> 可以在每个线程中对该变量创建一个副本,即每个线程内部都会有一个该变量的副本,该副本在线程内部任何地方都可以共享使用,但不同线程的副本之间互不影响。

ThreadLocal<T> 类中有以下几个常用方法,如表所示:

方 法 简 介
public T get() 获取 ThreadLocal 在当前线程中保存的变量副本。
public void set(T value) 设置当前线程中变量的副本。
public void remove() 移除当前线程中变量的副本。
protected T initialValue() 延迟加载的方法,一般在使用时重写该方法。

连接池和 DbUtils 这个工具类主要有以下重点:

  • 数据库连接池可以分配、管理及释放数据库连接,可以使得应用程序重复地使用一个已有的数据库连接,而不再是重新建立一个。
  • 常用的数据源包括 Tomcat 内置数据源(Apache dbcp)、DBCP 数据源和 C3P0 数据源等,并且很多数据源都有基于配置文件和纯编码两种使用方式。
  • DbUtils 是一个工具类,提供了关闭连接、事务提交/回滚、注册 JDBC 驱动程序等常用方法。
  • QueryRunner 类主要用于执行增删改查等 SQL 语句。特别的,如果执行的是查询 SQL,还需要结合 ResultSetHandler 接口来处理结果集。
  • ResultSetHandler 接口用于处理 ResultSet 结果集,它可以将结果集中的数据封装成单个对象、数组、List 、Map 等不同形式。
  • ArrayHandler 类可以把结果集中的第一行数据封装成 Object[] 。
  • ArrayListHandler 类可以把结果集中的每行数据都封装成一个 Object[] 对象,然后再将所有的 Object[] 组装成一个 List 对象。
  • BeanHandler<T> 类可以把结果集中的第一行数据封装成 JavaBean 。
  • BeanListHandler<T> 类可以把结果集中的每行数据都封装成一个 JavaBean 对象,然后再将所有的 JavaBean 对象组装成一个 List 对象。
  • MapHandler 可以将结果集中的第一条数据封装到 Map 对象中,并且 key 是字段名,value 是字段值。
  • MapListHandler 可以将结果集中的每条数据都封装到 Map 对象中,然后再将所有的 Map 对象组装成一个 List 对象。
  • ColumnListHandler <T> 可以把结果集中某一列的值封装到 List 集合中。
  • ScalarHandler<T> 类用于封装单值结果。

图片描述

  • 使用 JNDI 定义的变量(通过 context.xml 中的 Environment 元素定义),可以在同一个 Tomcat 中的任意一个 Web 项目中使用。
  • 连接池减少连接创建时间。连接池中的连接已准备好的,可重复使用的,获取后可以直接使用访问数据库,因此减少了连接创建的次数和时间。
  • 连接池简化编程模式。当使用连接池时,每一个单独的线程能够创建一个自己的 JDBC 连接一样操作,允许用户直接使用 JDBC 编程技术。
  • 连接池控制资源的使用。如果不使用连接池,每次访问访问数据库都需要创建一个连接,这样系统的稳定性受系统连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使用性能最大化,将资源利用控制在一定的水平之下。连接池能控制池中的连接数量,增强了新系统在大量用户应用时的稳定性。
  • ThreadLocal<T> 可以在每个线程中为变量创建一个副本,即每个线程内部都会有一个该变量的副本,该副本在线程内部任何地方都可以共享使用,但不同线程的副本之间互不影响。

写在最后

其实本文对连接池的理解还是比较片面,希望大家在看了以后还是好好深入理解一下。

Supongo que te gusta

Origin juejin.im/post/7102609261204602893
Recomendado
Clasificación