JDBC全套核心知识点整理(从入门到封装)

前言

本文是JDBC的全套核心知识点梳理,从JDBC基础概念到实际开发中的封装、连接池、事务处理等核心内容全覆盖,代码示例可直接运行,适合Java初学者入门学习,也可作为开发中的速查手册。

一、JDBC基础认知

1.1 什么是JDBC

JDBC(Java DataBase Connectivity)即Java数据库连接,是SUN公司提供的一套操作数据库的标准接口,通过Java语言向数据库发送SQL语句,实现程序与数据库的自动化交互(替代Navicat等手动操作方式)。

1.2 JDBC的核心原理

  • SUN只提供JDBC接口,不提供具体实现;

  • 各数据库厂商遵循JDBC规范,提供各自的数据库驱动(接口的实现类);

  • 程序通过JDBC接口调用驱动,实现对不同数据库的统一操作,屏蔽数据库底层差异。

1.3 JDBC核心API

JDBC的核心能力是:建立连接→发送SQL→处理结果,核心接口/类如下:

接口/类

核心作用

DriverManager

管理数据库驱动,获取数据库连接Connection

Connection

代表数据库物理连接,是操作数据库的入口

Statement

发送执行SQL语句(简单SQL,有注入风险)

PreparedStatement

Statement子类,预编译SQL,解决注入问题

ResultSet

保存SQL查询的结果集,提供数据读取方法

二、JDBC操作数据库的通用步骤

JDBC操作增删改查的基础步骤统一,仅执行SQL的方法和结果处理不同,核心五步:

步骤1:加载数据库驱动

通过Class.forName()加载驱动类,不同数据库驱动类不同,核心区别:

// MySQL5
Class.forName("com.mysql.jdbc.Driver");
// MySQL8(推荐)
Class.forName("com.mysql.cj.jdbc.Driver");

步骤2:创建数据库连接

通过DriverManager.getConnection()获取Connection,需指定URL、用户名、密码

String url = "jdbc:mysql://localhost:3306/jdbc_db?useSSL=false&characterEncoding=UTF8";
String user = "root";
String pwd = "123456";
Connection conn = DriverManager.getConnection(url, user, pwd);

URL格式详解协议://主机:端口/数据库名?参数1&参数2

  • 协议:jdbc:mysql(固定)

  • 主机:本地为localhost,远程为服务器IP

  • 端口:MySQL默认3306

  • 参数:useSSL=false(关闭SSL)、characterEncoding=UTF8(设置编码)

步骤3:创建Statement/PreparedStatement,发送SQL

  • 简单SQL用Statement

  • 带参数SQL用PreparedStatement(预编译,推荐)。

步骤4:处理执行结果

  • 增/删/改:返回受影响行数(int),判断是否执行成功;

  • 查:返回ResultSet结果集,遍历获取数据。

步骤5:关闭数据库资源

关闭顺序:ResultSet → Statement/PreparedStatement → Connection(与创建顺序相反),避免资源泄漏。

三、JDBC核心操作实现(增删改查)

以下示例基于student表,数据库为jdbc_db,驱动使用MySQL5,所有代码均为可运行完整代码。

3.1 新增操作(INSERT)

package com.hg.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class AddTest {
    // 配置常量
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/jdbc_db?useSSL=false&characterEncoding=UTF8";
    private static final String USER = "root";
    private static final String PWD = "1111";
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1.加载驱动
        Class.forName(DRIVER);
        // 2.创建连接
        Connection conn = DriverManager.getConnection(URL, USER, PWD);
        // 3.创建Statement
        Statement stmt = conn.createStatement();
        // 4.执行SQL,获取受影响行数
        String sql = "insert into student values(1,'小刚',32,'男','湖北省武汉市')";
        int n = stmt.executeUpdate(sql);
        // 5.处理结果
        if (n > 0) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }
        // 6.关闭资源
        stmt.close();
        conn.close();
    }
}

3.2 修改操作(UPDATE)

核心:executeUpdate(sql)执行更新SQL,逻辑与新增一致,仅SQL语句不同:

String sql = "update student set name='小明',age=23 where id=1";
int res = stat.executeUpdate(sql);
if(res>0){
    System.out.println("修改成功");
}

3.3 删除操作(DELETE)

注意:删除必须加WHERE条件,否则删除全表数据!

package com.hg.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class DeleteTest {
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/jdbc_db?useSSL=false&characterEncoding=UTF8";
    private static final String USER = "root";
    private static final String PWD = "1111";
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName(DRIVER);
        Connection conn = DriverManager.getConnection(URL, USER, PWD);
        Statement stat = conn.createStatement();
        // 带WHERE条件,删除指定ID数据
        String sql = "delete from student where id=1";
        int res = stat.executeUpdate(sql);
        if (res > 0) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }
        stat.close();
        conn.close();
    }
}

3.4 查询操作(SELECT)

核心:executeQuery(sql)返回ResultSet,通过next()遍历,getXXX()获取列数据:

package com.hg.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class QueryTest {
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/jdbc_db?useSSL=false&characterEncoding=UTF8";
    private static final String USER = "root";
    private static final String PWD = "1111";
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName(DRIVER);
        Connection conn = DriverManager.getConnection(URL, USER, PWD);
        Statement stmt = conn.createStatement();
        // 执行查询SQL
        String sql = "select * from student";
        ResultSet rs = stmt.executeQuery(sql);
        // 遍历结果集
        while (rs.next()) {
            int id = rs.getInt(1); // 通过列索引获取(从1开始)
            String name = rs.getString("name"); // 通过列名获取(推荐)
            int age = rs.getInt("age");
            System.out.println(id + "  " + name + "  " + age);
        }
        // 关闭资源(包含ResultSet)
        rs.close();
        stmt.close();
        conn.close();
    }
}

ResultSet数据读取技巧

  • getInt(index/name):读取整型

  • getString(index/name):读取字符串

  • getObject(name):通用方法,读取任意类型

3.5 分页查询

MySQL分页使用limit 起始索引,每页条数起始索引=(页码-1)每页条数*:

// 分页参数
int pageNum = 2; // 第2页
int pageSize = 5; // 每页5条
// 拼接分页SQL
String sql = "select * from student limit " + (pageNum-1)*pageSize + "," + pageSize;
ResultSet rs = stmt.executeQuery(sql);

四、JDBC核心问题:SQL注入及解决

4.1 什么是SQL注入

通过拼接用户输入的恶意字符串,篡改原始SQL逻辑,导致非授权访问或数据泄露。

示例:登录功能中,用户输入username='1' or '1'='1',密码任意,拼接后的SQL为:

select * from sys_user where username='1' or '1'='1' and password='xxx'

该SQL恒成立,无需正确密码即可登录。

4.2 解决方法:使用PreparedStatement(预编译)

PreparedStatement是Statement的子类,核心特性:

  1. SQL语句预编译,占位符?接收参数,避免字符串拼接;

  2. 执行效率更高(多次执行同一SQL时,无需重复编译);

  3. 从根本上解决SQL注入问题。

4.3 预编译实现登录(防注入)

package com.hg.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
public class LoginTest {
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/jdbc_db?useSSL=false&characterEncoding=UTF8";
    private static final String USER = "root";
    private static final String PWD = "1111";
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = scanner.nextLine();
        System.out.println("请输入密码:");
        String password = scanner.nextLine();
        Class.forName(DRIVER);
        Connection conn = DriverManager.getConnection(URL, USER, PWD);
        // 1.预编译SQL,用?作为占位符
        String sql = "select * from sys_user where username=? and password=?";
        PreparedStatement pstmt = conn.prepareStatement(sql);
        // 2.为占位符赋值(索引从1开始)
        pstmt.setString(1, username);
        pstmt.setString(2, password);
        // 3.执行SQL,无需传入参数
        ResultSet rs = pstmt.executeQuery();
        if (rs.next()) {
            System.out.println("登录成功!");
        } else {
            System.out.println("用户名或密码错误!");
        }
        // 关闭资源
        rs.close();
        pstmt.close();
        conn.close();
    }
}

核心方法setXxx(int index, Xxx value),根据参数类型选择对应方法(如setIntsetString)。

五、JDBC工具类封装(DBUtils)

原始JDBC代码中,加载驱动、创建连接、关闭资源的代码重复率极高,需封装为通用工具类DBUtils,简化开发。

5.1 第一步:创建配置文件(db.properties)

将数据库配置抽离为配置文件,避免硬编码,便于后期修改,放在src目录下:

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc_db?useSSL=false&characterEncoding=UTF8
username=root
password=1111

5.2 第二步:实现DBUtils工具类

核心功能:加载配置+获取连接+通用关闭资源

package com.hg.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class DBUtils {
    // 配置变量
    private static String DRIVER;
    private static String URL;
    private static String USER;
    private static String PWD;
    // 静态代码块:加载配置+注册驱动(只执行一次)
    static {
        try {
            // 读取配置文件
            InputStream is = DBUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties prop = new Properties();
            prop.load(is);
            // 为变量赋值
            DRIVER = prop.getProperty("driverClass");
            URL = prop.getProperty("url");
            USER = prop.getProperty("username");
            PWD = prop.getProperty("password");
            // 注册驱动
            Class.forName(DRIVER);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 获取数据库连接
    public static Connection getConn() {
        try {
            return DriverManager.getConnection(URL, USER, PWD);
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("创建连接失败!");
            return null;
        }
    }
    // 通用关闭资源方法(AutoCloseable为Connection/Statement/ResultSet的父接口)
    public static void close(AutoCloseable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.3 工具类使用示例(简化新增操作)

package com.hg.jdbc;
import com.hg.utils.DBUtils;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
public class AddTestByDBUtils {
    public static void main(String[] args) throws SQLException {
        // 1.获取连接(一行代码)
        Connection conn = DBUtils.getConn();
        Statement stmt = conn.createStatement();
        // 2.执行SQL
        String sql = "insert into student values(2,'小红',28,'女','湖南省长沙市')";
        int n = stmt.executeUpdate(sql);
        if (n > 0) {
            System.out.println("添加成功");
        }
        // 3.关闭资源(一行代码,无需逐个关闭)
        DBUtils.close(stmt);
        DBUtils.close(conn);
    }
}

六、JDBC事务处理

6.1 事务的概念

事务是数据库操作的最小工作单元,一组操作要么全部执行成功,要么全部回滚,保证数据一致性。

6.2 事务的四大特性(ACID)

  • 原子性(Atomicity):操作不可分割,要么全做,要么全不做;

  • 一致性(Consistency):事务执行后,数据库从一个一致状态到另一个一致状态;

  • 隔离性(Isolation):多个事务并发执行,互不干扰;

  • 持久性(Durability):事务提交后,修改永久生效,不会因故障丢失。

6.3 JDBC事务实现(以转账为例)

JDBC默认自动提交事务(每执行一条SQL自动提交),实现手动事务需三步:

  1. 关闭自动提交:conn.setAutoCommit(false)

  2. 执行完所有SQL后,手动提交:conn.commit()

  3. 出现异常时,回滚事务:conn.rollback()

转账案例代码实现
package com.hg.jdbc;
import com.hg.utils.DBUtils;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
public class TransactionTest {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try {
            // 1.获取连接
            conn = DBUtils.getConn();
            // 2.关闭自动提交,开启手动事务
            conn.setAutoCommit(false);
            // 3.执行转账SQL(扣钱+加钱)
            stmt = conn.createStatement();
            String sql1 = "update account set amount = amount-1000 where aid=1"; // 账户1扣1000
            String sql2 = "update account set amount = amount+1000 where aid=2"; // 账户2加1000
            stmt.executeUpdate(sql1);
            // 模拟异常:int i = 1/0;
            stmt.executeUpdate(sql2);
            // 4.无异常,提交事务
            conn.commit();
            System.out.println("转账成功!");
        } catch (Exception e) {
            e.printStackTrace();
            // 5.有异常,回滚事务
            try {
                if (conn != null) {
                    conn.rollback();
                    System.out.println("转账失败,事务回滚!");
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            // 6.关闭资源
            DBUtils.close(stmt);
            DBUtils.close(conn);
        }
    }
}

测试:在sql1sql2之间添加int i = 1/0;模拟异常,会触发事务回滚,两个账户的金额不会发生变化。

七、高级封装:BaseDAO(通用数据访问层)

在DBUtils基础上,结合反射+泛型封装BaseDAO,实现通用增删改查,无需为每个实体类重复编写DAO代码,模拟ORM框架的核心思想。

7.1 BaseDAO核心功能

  1. 通用查询列表:selectList(sql, Class<T>, params)

  2. 通用查询单个对象:selectOne(sql, Class<T>, params)

  3. 通用增删改:update(sql, params)

  4. 通用分页查询:selectPage(sql, Class<T>, page, limit)

7.2 BaseDAO完整代码

package com.hg.dao;
import com.hg.utils.DBUtils;
import com.hg.common.PageInfo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class BaseDao {
    /**
     * 通用查询列表
     * @param sql SQL语句
     * @param clss 实体类字节码
     * @param params SQL占位符参数
     * @return 实体类列表
     */
    public <T> List<T> selectList(String sql, Class<T> clss, Object... params) {
        List<T> data = new ArrayList<>();
        Connection conn = DBUtils.getConn();
        PreparedStatement prep = null;
        ResultSet rs = null;
        try {
            prep = conn.prepareStatement(sql);
            // 为占位符赋值
            for (int i = 0; i < params.length; i++) {
                prep.setObject(i + 1, params[i]);
            }
            // 执行查询
            rs = prep.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            // 遍历结果集,通过反射封装实体类
            while (rs.next()) {
                T t = clss.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    // 获取列别名(与实体类属性名一致)
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    // 获取列值
                    Object columnValue = rs.getObject(columnLabel);
                    // 反射获取实体类属性,赋值
                    Field field = clss.getDeclaredField(columnLabel);
                    field.setAccessible(true); // 突破私有属性访问限制
                    field.set(t, columnValue);
                }
                data.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtils.close(rs);
            DBUtils.close(prep);
            DBUtils.close(conn);
        }
        return data;
    }
    /**
     * 通用查询单个对象
     */
    public <T> T selectOne(String sql, Class<T> clss, Object... params) {
        List<T> list = selectList(sql, clss, params);
        if (!list.isEmpty() && list.size() == 1) {
            return list.get(0);
        }
        return null;
    }
    /**
     * 通用增删改操作
     * @return 执行成功返回true,失败返回false
     */
    public boolean update(String sql, Object... params) {
        Connection conn = DBUtils.getConn();
        PreparedStatement prep = null;
        try {
            prep = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                prep.setObject(i + 1, params[i]);
            }
            int m = prep.executeUpdate();
            return m >= 1;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtils.close(prep);
            DBUtils.close(conn);
        }
        return false;
    }
    /**
     * 通用分页查询
     * @param page 页码
     * @param limit 每页条数
     * @return 分页结果对象(数据+总条数)
     */
    protected <T> PageInfo<T> selectPage(String sql, Class<T> cls, String page, String limit) {
        Integer pageNo = (Integer.parseInt(page) - 1) * Integer.parseInt(limit);
        // 分页SQL
        String listSql = sql + " limit " + pageNo + "," + limit;
        // 查询列表数据
        List<T> data = selectList(listSql, cls);
        // 查询总条数
        Long count = getCount(sql);
        // 封装分页结果
        PageInfo<T> pageInfo = new PageInfo<>();
        pageInfo.setData(data);
        pageInfo.setCount(count);
        return pageInfo;
    }
    /**
     * 查询总条数
     */
    private Long getCount(String sql) {
        String countSql = "select count(1) from (" + sql + ") rs";
        Connection conn = DBUtils.getConn();
        PreparedStatement prep = null;
        ResultSet rs = null;
        try {
            prep = conn.prepareStatement(countSql);
            rs = prep.executeQuery();
            rs.next();
            return rs.getLong(1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtils.close(rs);
            DBUtils.close(prep);
            DBUtils.close(conn);
        }
        return 0L;
    }
}

7.3 分页结果封装类(PageInfo)

package com.hg.common;
import java.util.List;
public class PageInfo<T> {
    private List<T> data; // 分页数据列表
    private Long count;   // 符合条件的总条数
    // getter/setter
    public List<T> getData() {
        return data;
    }
    public void setData(List<T> data) {
        this.data = data;
    }
    public Long getCount() {
        return count;
    }
    public void setCount(Long count) {
        this.count = count;
    }
}

7.4 BaseDAO使用示例

创建UserDao继承BaseDAO,无需编写底层JDBC代码,直接调用父类方法:

package com.hg.dao.impl;
import com.hg.dao.BaseDao;
import com.hg.pojo.User;
public class UserDao extends BaseDao {
    /**
     * 根据用户名和密码查询用户
     */
    public User selectUser(String username, String password) {
        String sql = "select id, username, password, realname from user where username=? and password=?";
        return super.selectOne(sql, User.class, username, password);
    }
    /**
     * 修改用户状态
     */
    public boolean updateUserState(String id, Integer deleted) {
        String sql = "update user set deleted=?, deleted_time=now() where id=?";
        return super.update(sql, deleted, id);
    }
}

八、数据库连接池(DataSource)

8.1 为什么需要连接池

  • 原始DriverManager每次获取连接都新建物理连接,创建/销毁连接耗时耗资源;

  • 连接池在服务器初始化时创建一批连接,放入内存缓冲池,程序需要时从池子里取,使用完归还,连接复用,大幅提升性能;

  • 连接池可配置最大连接数、最小空闲连接数等,避免数据库连接耗尽。

8.2 DriverManager vs DataSource

特性

DriverManager

DataSource

类型

工具类

JDBC标准接口

连接方式

新建物理连接

从连接池获取复用连接

性能

低(频繁创建/销毁)

高(连接复用)

连接池支持

不支持

天然支持

使用场景

学习/测试/小Demo

企业项目/正式开发

8.3 主流连接池

  • Druid:阿里开源,功能强大(监控、防注入、配置灵活),国内企业首选;

  • HikariCP:SpringBoot官方推荐,轻量、速度最快;

  • c3p0/DBCP:老牌连接池,功能老旧,逐步被淘汰。

8.4 Druid连接池使用(整合DBUtils)

步骤1:引入Druid依赖
<!-- Maven依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.16</version>
</dependency>
步骤2:修改DBUtils,整合Druid

将原始的DriverManager获取连接替换为Druid连接池:

package com.hg.utils;
import com.alibaba.druid.pool.DruidDataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class DBUtils {
    private static DruidDataSource ds; // Druid连接池对象
    static {
        try {
            // 读取配置文件
            InputStream is = DBUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties prop = new Properties();
            prop.load(is);
            // 初始化Druid连接池
            ds = new DruidDataSource();
            ds.setDriverClassName(prop.getProperty("driverClass"));
            ds.setUrl(prop.getProperty("url"));
            ds.setUsername(prop.getProperty("username"));
            ds.setPassword(prop.getProperty("password"));
            // 连接池配置
            ds.setInitialSize(2); // 初始连接数
            ds.setMaxActive(5);   // 最大活跃连接数
            ds.setMinIdle(1);     // 最小空闲连接数
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 从连接池获取连接
    public static Connection getConn() {
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("从连接池获取连接失败!");
            return null;
        }
    }
    // 通用关闭资源(Druid的close()是归还连接,不是销毁)
    public static void close(AutoCloseable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意:Druid重写了Connection的close()方法,调用close()并非销毁连接,而是将连接归还到连接池

九、JDBC批处理(批量操作)

当需要执行大量相同结构的SQL(如批量插入1000条数据),使用批处理可大幅提升效率,核心通过addBatch()添加SQL,executeBatch()执行批量操作。

批处理示例(批量插入学生数据)

package com.hg.jdbc;
import com.hg.utils.DBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;
public class BatchTest {
    public static void main(String[] args) throws SQLException {
        Connection conn = DBUtils.getConn();
        // 预编译SQL,提升批量执行效率
        String sql = "insert into student(id,name,age,sex) values(?,?,?,?)";
        PreparedStatement pstmt = conn.prepareStatement(sql);
        Random random = new Random();
        // 关闭自动提交,提升批量执行效率
        conn.setAutoCommit(false);
        for (int i = 1; i <= 1000; i++) {
            pstmt.setInt(1, i);
            pstmt.setString(2, "学生" + i);
            pstmt.setInt(3, 18 + random.nextInt(10));
            pstmt.setString(4, random.nextBoolean() ? "男" : "女");
            pstmt.addBatch(); // 添加到批处理队列
            // 每500条执行一次,避免队列过大
            if (i % 500 == 0) {
                pstmt.executeBatch(); // 执行批处理
                pstmt.clearBatch();   // 清空队列
            }
        }
        // 执行剩余的批处理
        pstmt.executeBatch();
        // 手动提交事务
        conn.commit();
        System.out.println("批量插入成功!");
        // 关闭资源
        DBUtils.close(pstmt);
        DBUtils.close(conn);
    }
}

优化技巧

  1. 使用PreparedStatement预编译SQL;

  2. 关闭自动提交,批量执行后手动提交;

  3. 分批次执行(如每500条),避免批处理队列过大。

十、JDBC核心知识点总结

  1. JDBC本质:SUN提供的操作数据库的标准接口,数据库厂商提供驱动实现;

  2. 通用步骤:加载驱动→创建连接→创建Statement→执行SQL→处理结果→关闭资源;

  3. 防注入:使用PreparedStatement预编译SQL,用?占位符接收参数;

  4. 工具类封装:DBUtils封装连接和关闭资源,BaseDAO结合反射+泛型实现通用DAO;

  5. 事务处理:关闭自动提交setAutoCommit(false),无异常commit(),有异常rollback()

  6. 性能优化:使用数据库连接池(Druid/HikariCP)、批处理、预编译;

  7. 核心接口Connection(连接)、PreparedStatement(预编译)、ResultSet(结果集)、DataSource(连接池)。

创作不易,觉得有帮助的话,点赞+收藏+关注吧!后续会持续更新Java后端核心知识点~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值