Java 数据库连接与访问 - JDBC

一、持久化

持久化(persistence): 把数据保存到可调电式存储设备中以供之后使用。大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数据保存到硬盘上加以”固化”,而持久化的实现过程大多通过各种关系数据库来完成。就是将内存中的数据存储在关系型数据库中,实际上是保存到了文件系统中,所以也可以存储在磁盘文件、XML数据文件中。

而在 Java中,数据库数据存取只能通过 JDBC 来实现。第三方O/R Mapping工具,如 Hibernate, MyBatis 等技术都是对 JDBC 的封装。

二、JDBC 概述

JDBC(Java DataBase Connectivity)是一组独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(API),定义了用来访问数据库的标准Java类库(java.sql, javax.sql),使用这些类库可以以一种标准的方法、方便地访问数据库资源。

JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。JDBC 的目标是使 Java 程序员使用 JDBC 可以连接任何提供了 JDBC 实现(驱动程序)的数据库系统,这样就使得程序员无需对特定数据库系统有过多了解,从而大大简化和加快了开发进程。

image

简单来说,JDBC 本身是 Java 访问数据库的一个标准,是进行数据库连接的抽象层,由 Java 编写的一组类和接口组成,接口的实现由各个数据库厂商来完成。


基于 JDBC 的编码流程如下:

image

其中,ODBC(Open Database Connectivity,开放式数据库连接)是微软在Windows平台下推出的数据库驱动。使用者在程序中只需要调用 ODBC API,由 ODBC 驱动程序将调用转换成为对特定的数据库的调用请求。

三、数据库连接

加载(注册)驱动

Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。程序中不需要直接使用 Driver 接口的实现类,而是借助驱动程序管理器类(DriverManager)来获取数据库连接。

同 Driver 一样,DriverManger 是 Java 标准库 java.sql 下面的类,它提供了注册驱动的方法 registerDriver(Driver driver),Driver 实现类(由数据库厂商提供的驱动程序包含)一般会在静态代码块中调用该方法将自身注册到 DriverManager,类似如下:

static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException e) {
        throw new RuntimeException("Can't register driver!");
    }
}

注册过程通常分为两个步骤:

  1. 把 com.mysql.jdbc.Driver 这一份字节码加载进 JVM;
  2. 字节码被加载进JVM,执行其静态代码块,完成注册驱动工作,将驱动注册到DriverManger 中。

获取连接

上述将 Driver 注册到了 DriverManager之后,后续对 Driver 的管理以及如何通过 Driver 来获取数据库连接其实都是通过 DriverManager 来做的。


通过 DriverManager 来获取数据库连接:
// url:jdbc:mysql://localhost:3306/jdbcdemo
// username:root
// password:Bf*f&fx80
Connection conn = DriverManager.getConnection(url, username, password);

URL 详解

JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。

JDBC URL的标准由三部分组成(协议:子协议:子名称),各部分间用冒号分隔。

协议:JDBC URL中的协议总是jdbc(固定写法)。
子协议:子协议用于标识一个数据库驱动程序。
子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名。

url的常见写法:

jdbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=值&参数=值
jdbc:mysql://localhost:3306/atguigu
jdbc:mysql://localhost:3306/atguigu?useUnicode=true&characterEncoding=utf8(如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
jdbc:mysql://localhost:3306/atguigu?user=root&password=123456

四、DAO(Data Access Objects)数据访问对象

数据访问对象是一套面向对象的数据库接口。 顾名思义就是与数据库打交道,夹在业务逻辑与数据库资源中间,将所有对数据源的访问操作抽象封装在一个公共 API 中。程序书写就是建立一个个接口,接口中定义了此应用程序中将会用到的所有事务方法。DAO 中的主要操作: 增删改查(CRUD)。

DAO本质就是一个可以重复使用的组件,避免许多重复性代码,大大简化了开发工作。DAO 代码编写需要遵循一定的规范,这里不做赘述,有兴趣的可以在网上查一查。

中间还有如何使用 JDBC 进行 CRUD 操作,比如如何使用 Statement、PreparedStatement、ResultSet,数据库事务及 ACID 属性,事务隔离性及隔离级别等等。我们直接跳到下一节:数据库连接池。

五、连接池

产生原因

开发基于数据库的web程序时,传统的模式基本是按以下步骤:

  • 在主程序中建立数据库连接。
  • 进行sql操作。
  • 断开数据库连接

这种模式会存在几个很显著的问题:

普通的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将Connection 加载到内存中,再验证用户名和密码(得花费0.05s~1s的时间)。需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接。这样的方式将会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重复利用。若同时有几百人甚至几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃。

对于每一次数据库连接,使用完后都得断开,否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将导致重启数据库。

这种开发不能控制被创建的连接对象数,系统资源会被毫无顾忌的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

为解决传统开发中的数据库连接问题,我们可以采用数据库连接池技术。

数据库连接池的基本思想:就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

连接池的属性

基本属性:连接池存了连接对象,而连接对象依赖四要素,所以四要素(driverClassName,url,username,password)是基本要求。

其他属性:对连接对象做限制的配置

  1. 初始化连接数:在连接池中事先准备好初始化Connection对象。

  2. 最多连接数:在连接池中最多有一定数量的Connection对象,其他客户端进入等待状态。

  3. 最少连接数:在连接池中最少一定数量的Connection对象。

  4. 最长等待时间:使用一定时间来申请获取Connection对象,如果时间到还没有申请到,则提示,自动放弃。

  5. 最长超时时间:如果你在一定时间之内没有任何动作,则认为是自动放弃Connection对象。

分类

JDBC 的数据库连接池使用javax.sql.DataSource来表示,DataSource 只是一个接口,该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现:

DBCP是Apache提供的数据库连接池。tomcat 服务器自带dbcp数据库连接池。速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持。
C3P0是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以。hibernate官方推荐使用。
Proxool是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点。
BoneCP是一个开源组织提供的数据库连接池,速度快。
Druid是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不确定是否有BoneCP快。

DataSource 通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把 DataSource 称为连接池,DataSource 用来取代 DriverManager 来获取 Connection,获取速度快,同时可以大幅度提高数据库访问速度。

注意:

  • 数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。
  • 当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但 conn.close() 并没有关闭数据库的物理连接,它仅仅把数据库连接释放,归还给了数据库连接池。

举例 - 德鲁伊(Druid)

Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,可以说是目前最好的连接池之一。

package com.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;

/**
 * @author Xiao_Lin
 * @date 2021/1/3 19:47
 */
public class DruidUtils {
  static DataSource ds = null;
  private DruidUtils(){

  }

  static {
    InputStream stream = Thread.currentThread().getContextClassLoader()
        .getResourceAsStream("db.properties");
    Properties properties = new Properties();
    try {
      properties.load(stream);
      ds = DruidDataSourceFactory.createDataSource(properties);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static Connection getConnection(){
    try {
      return ds.getConnection();
    } catch (SQLException e) {
      e.printStackTrace();
    }
    return null;
  }
}
posted @ 2025-07-10 16:11  凉皮也是菜  阅读(23)  评论(0)    收藏  举报