Skip to content

03-JDBC 与数据库连接池

对应原始资料:数据库_day04数据库阶段_day06

一、JDBC 概述

JDBC(Java Database Connectivity)是 Java 操作关系型数据库的一套规范/接口,各数据库厂商提供实现(驱动)。

Java 程序 → JDBC 接口 → 驱动(厂商) → 数据库

二、JDBC 快速入门

1. 步骤

  1. 导入驱动 jar(mysql-connector-java)。
  2. 注册驱动(JDK 6 后可省略,SPI 自动加载)。
  3. 获取连接。
  4. 定义 SQL。
  5. 获取执行对象 Statement。
  6. 执行 SQL。
  7. 处理结果。
  8. 释放资源。

2. 代码

java
// 1. 导入 jar(pom 中引入 mysql-connector-java)

// 2. 注册驱动(可省)
Class.forName("com.mysql.cj.jdbc.Driver");

// 3. 获取连接
String url = "jdbc:mysql://localhost:3306/db1?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";
Connection conn = DriverManager.getConnection(url, "root", "123456");

// 4. SQL
String sql = "SELECT * FROM emp WHERE id = ?";

// 5. PreparedStatement(防 SQL 注入)
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 1);

// 6. 执行
ResultSet rs = ps.executeQuery();    // 查询
// int i = ps.executeUpdate();       // 增删改,返回影响行数

// 7. 处理结果
while (rs.next()) {
    int id = rs.getInt("id");
    String name = rs.getString("name");
    System.out.println(id + " " + name);
}

// 8. 释放资源(倒序关)
rs.close();
ps.close();
conn.close();

三、PreparedStatement vs Statement

维度StatementPreparedStatement
SQL 注入有风险预编译防注入
性能每次编译可缓存执行计划
参数拼字符串? 占位

永远用 PreparedStatement,不要拼字符串。

四、JDBC 事务管理

默认每条 SQL 自动提交。手动事务:

java
try {
    conn.setAutoCommit(false);
    ps1.executeUpdate();
    ps2.executeUpdate();
    conn.commit();
} catch (Exception e) {
    conn.rollback();
    e.printStackTrace();
} finally {
    conn.setAutoCommit(true);
    // 关资源
}

五、ResultSet 元数据

java
ResultSetMetaData md = rs.getMetaData();
int count = md.getColumnCount();
for (int i = 1; i <= count; i++) {
    String name = md.getColumnName(i);
    String type = md.getColumnTypeName(i);
}

可用于通用查询(把结果集映射成 Map / 对象)。

六、数据库连接池(重点)

1. 为什么用连接池

  • 每次新建/关闭连接很耗时。
  • 预先创建一批连接放在池里,复用,提升性能。

2. 常见连接池

  • Druid(阿里巴巴):监控强、性能好,国内主流。
  • HikariCP:SpringBoot 默认,号称最快。
  • C3P0:老牌(资料中有补充)。

3. Druid 使用

java
Properties props = new Properties();
props.load(new FileInputStream("druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(props);

try (Connection conn = ds.getConnection()) {
    // 用 conn
}

druid.properties

properties
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db1
username=root
password=123456
initialSize=5
maxActive=20
maxWait=3000

连接池 = DataSource(数据源),由它统一管理 Connection。

七、JDBC 工具类封装

把重复代码抽成工具类:

java
public class JDBCUtil {
    private static final DataSource DS;
    static {
        try {
            Properties p = new Properties();
            p.load(JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
            DS = DruidDataSourceFactory.createDataSource(p);
        } catch (Exception e) { throw new RuntimeException(e); }
    }
    public static Connection getConnection() throws SQLException { return DS.getConnection(); }
    public static DataSource getDataSource() { return DS; }

    public static void close(Connection c, Statement s, ResultSet r) {
        if (r != null) try { r.close(); } catch (Exception e) {}
        if (s != null) try { s.close(); } catch (Exception e) {}
        if (c != null) try { c.close(); } catch (Exception e) {}
    }
}

八、Apache DbUtils(了解)

Apache Commons DbUtils 简化了结果集处理:

java
QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());
List<Emp> list = qr.query("SELECT * FROM emp",
        new BeanListHandler<>(Emp.class));

练习建议

  1. 用 JDBC 完成 emp 表的 CRUD。
  2. 用 PreparedStatement 实现登录验证(体会 SQL 注入防护)。
  3. 用 Druid 改造上面的程序,对比连接耗时。
  4. 封装一个通用查询方法:传入 SQL 和参数,返回 List<Map>
  5. 完成「黑马商城」资料中的登录注册(基于 JDBC)。