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

JDBC看这一篇就够了 JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,()使用这些类库可以以一种标准的方法、方便地访问数据库资源。JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。JDBC的目标是使Java程序员使用JDBC可以连接任何提供了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),根据参数类型选择对应方法(如setInt、setString)。

五、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);
        }
    }
}

测试:在sql1和sql2之间添加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后端核心知识点~

Spring JDBC教程:从入门到实践 在Spring Boot中,JdbcTemplate通常通过自动配置创建,但你也可以自定义它以满足特定的需求。 阅读详情

相关推荐

Java基础入门课后习题答案深度解析:从JDK到JDBC的避坑指南

学习Java开发语言,首先要理解JDK与JRE的区别:JDK是开发工具箱,JRE是运行环境,而跨平台离不开JVM的中间字节码机制。掌握了这些基础原理后,面向对象三大特性、集合框架的List/Set/Map、字符串与IO流的选择等核心知识点,构成了入门阶段的完整知识地图。这些概念既是日常编码的基石,也是排查环境配置、集合去重、数据库连接等工程问题的关键。当系统学习这些内容时,配套的课后习题答案能帮初学者快速定位易混概念,理清从编译运行到JDBC操作数据库的完整链路,避免踩中常见坑点。

weixin_33391446的博客 295

JDBC详解

1.JDBC是什么? Java DataBase Connectivity(Java语言连接数据库) 2.JDBC的本质是什么? JDBC是SUN公司制定的一套接口(interface) java.sql.*;(这个软件包下有很多接口) 接口都有调用者和实现者。 面向接口调用、面向接口写实现类,这都属于面向接口编程。 为什么要面向接口编程? 解耦合:降低程序的耦合度,提高程序的扩展力。 多态机制就是非常典型的:面向抽象编程。(不要面向具体编程) 建议: Animal a = new Cat

LiLi的博客 4万+

销售预测的方法与模型(三)丨安全库存与再订货(补货)

较高的 Z 值对应较高的服务水平(例如,服务水平 99% 对应 Z 值 2.33),意味着企业希望更低的缺货风险,因此需要更高的安全库存。在再订货点的管理中,考虑到供应商交货的不确定性,通常需要结合安全库存,以防止在交货期间库存用尽。要对L开根号,根号L表示交货周期越长,企业需要的安全库存越多,因为在较长的供应期内,需求波动的累积效应更明显。举例:供应商的交期服从标准差为2件/天的正态分布,顾客需求为50件/天的正态分布,若要客户服务水平达到 90%,安全库存量应该是多少?下面介绍几种核心的模型与公式。

weixin_45675709的博客 1534

JDBC简介

文章目录一、JDBC简介二、JDBC执行步骤三、执行步骤中类的简介1、DriverManager类2.Connection类 一、JDBC简介 1.什么是jdbc JDBC全称:java database connectivity,简称jdbc, 翻译就是 Java 数据库连接。 2.jdbc有什么作用: 是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库。可以通过jdbc代码实现对数据库的操作。包括DDL,DML,DQL等。 二、JDBC执行步骤 1.导入驱动

chenxingxingxing的博客 2万+

高通Camera AWB跳变问题实战:从夕阳场景到参数调优的完整避坑指南

本文深入解析高通Camera AWB跳变问题,特别是在夕阳场景下的色温突变现象。通过分析灰区统计失效、光源混合干扰等成因,提供从参数调优到诊断工具链的完整解决方案,包括动态灰区扩展算法、色温平滑过渡方案及高通平台特定优化技巧,帮助工程师有效解决AWB跳变问题。

sre5engineer的博客 855

如何利用PREEvision和MATLAB开发AUTOSAR软件组件

在业界,比较著名的电子电气架构开发工具要属德国Vector公司开发的PREEvision工具了,而MATLAB/Simulink软件是非常高效且实用的基于模型的应用软件开发工具。利用PREEvision与Simulink联合开发AUTOSAR应用软件组件的开发流程有三种,分别是:“自上而下”开发流程(从PREEvision开始),“自下而上”开发流程(从Simulink开始),以及“双向”开发流程。如下图所示,无论哪一种开发流程,PREEvision与Simulink工具都是通过arxml文件进行信息交互的

怿星科技的博客 5395

访问数据库_常用的数据库访问方式是什么?

常用的数据库访问方式是什么?ASP访问数据库的方式有哪些?在ASP中可以通过三种方式访问数据库:1、IDC(InternetDatabaseConnector)方式;2、ADO(ActiveXDataObjects)方式;3、RDS(RemoteDataService)方式。这三种访问方式对数据库的访问都是由InternetInformationServer完成的。通过Web浏览器用H...

weixin_39781186的博客 4988

vins-mono保存、重载地图、evo工具测试

下面咱们来对vins-mono的重定位vins-mono官方源码地址:https://github.com/HKUST-Aerial-Robotics/VINS-Mono https://blog.youkuaiyun.com/learning_tortosie/article/details/83182258 运行这条: roslaunch benchmark_publisher publish.launc...

追 1万+

SpringBoot-整合JDBC

整合JDBC======1.创建SpringBoot项目,引入以下模块Spring WebJDBC APIMySQL Driver​2.编写yaml配置文件连接数据库;application.yml:spring:datasource:username: rootpassword: 123456#?serverTimezone=UTC解决时区的报错url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&char

2401_83704218的博客 1365

假期搞定!2026国社科申报AI全攻略指南:从选题到创新,7大核心要点手把手教你!

最后给大家推荐的400多所高校教师都在用的AI平台——高级学术版专业应用平台,集成了国际主流学术应用,以及ChatGPT、Claude、Gemini、Grok等Al大模型的高级版本平台,还有,可以辅助大家高效完成科研和学术写作任务,当然撰写硕博论文,课题、职称论文、国社科、国自然基金本子也是手拿把掐。你的任务是:用高度凝练的方式说明在(某一明确国家战略 / 政策方向,如:中国式现代化、共同富裕、基层治理现代化、数字中国、文化强国、国家安全等)背景下,我究竟要研究一个什么“具体而可操作的问题”。

智能AI让学术科研更容易 623

qtcreator使用远程服务器编译代码

我并没有找到很好的windows上可以用的rsync工具,最后是装了wsl来调用rsync同步到代码后,在用ssh调用linux命令来编译的。安装wsl安装ubuntu启动wsl然后把windows里的ssh文件证书和配置复制到wsl里同时config的key目录需要改一下,这样就可以登录服务器了然后在home目录创建build.sh进行远程编译。

习惯就好zz的专栏 1380

Java入门基础知识点总结(详细篇)

很多新手在学习java的时候都比较迷茫,不知道从哪里开始学起,这里就给大家整理了一份java开发学习路线,比较系统全面,可参考这份大纲来安排学习计划,希望可以帮到你~ 第一阶段:java专业基础课程 阶段目标: 1、熟练掌握java的开发环境与编程核心知识; 2、熟练运用java面向对象知识进行程序开发; 3、对java的核心对象和组件有深入理解; 4、熟练运用javaAPI相关知识; 5、熟练应用java多线程技术; 6、能综合运用所学知识完成一个项目。 知识点: 1、基本数据类型

java9787的博客 3246

什么是 Agent 的 Context Window?为什么它是 Agent 工程中最核心的约束之一?

什么是 Agent 的 Context Window?为什么它是 Agent 工程中最核心的约束之一?

我哎GIS博客 814

JDBC概述,MySQL驱动jar包,数据库连接

1、数据的持久化持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数据保存到硬盘上加以”固化”,而持久化的实现过程大多通过各种关系数据库来完成。持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中。2、Java中的数据存储技术在Java中,数据库存取技术可分为如下几类:①JDBC直接访问数据库②JDO (Java Data Object )技术。

2401_83641443的博客 1047

[ATF]-smc指令详解

1、在ree/tee调用smc之前 2、调用smc之后,cpu触发同步异常,进入ATF的sync_exception_aarch64—>handle_sync_exception—>smc_handler64处理函数 在smc_handler64中又调用了smc_handler func smc_handler64 /* ---------------------------------------------- * Detect if this is a RUN_IMAGE or ot

baron-周贺贺-代码改变世界ctw 1万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Java核心技术及面试指南 JDBC部分的面试题总结以及答案

1、看视频进行系统学习这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。2、读源码,看实战笔记,学习大神思路“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。

2401_84102979的博客 715

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

收获颇丰!终于学完了高级开发工程师精心整理142页Java实践指南

以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。现在重新好好复习手上的。

2401_84446548的博客 897

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Java开发基础-JDBC-核心对象的使用—02(1)

PreparedStatement继承自Statement:[通过源码可知]Statement代码可读性和可维护性将sql语句与参数分离,可读性高sql语句与参数混合拼接,可读性差,拼接sql语句易出错执行性能语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个函数效果)就会得到执行,相同操作sql可以复用,效率高,另外支持批处理操作。

m0_72758098的博客 1020

【附带Java采用JDBC连接数据库】SQLServer2012的安装与注意事项详解

由于篇幅原因,就不多做展示了《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取![外链图片转存中…(img-LXANtjNw-1713555846323)][外链图片转存中…(img-8TSOFg53-1713555846331)][外链图片转存中…(img-27H9iaEj-1713555846333)][外链图片转存中…(img-IfmzpSsq-1713555846334)]由于篇幅原因,就不多做展示了。

2401_84408058的博客 1013

Java Web 学习全指南:从入门到实战,体系化掌握核心技能

Java Web 是基于 Java 技术构建 Web 应用的核心体系,也是后端开发的主流方向之一,涵盖前端交互、后端逻辑、数据库交互、服务器部署等全链路知识。以下从。

2501_94447362的博客 1738

面试官问我:看过sharding-jdbc的源码吗?我吧啦吧啦说了一通!!

我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记。

2401_84433680的博客 1037

JDBC是什么,2024年前端笔试题总结

这种驱动直接把jdbc调用转换为符合相关数据库系统规范的请求.由于4型驱动写的应用可以直接和数据库服务器通讯,这种类型的驱动完全由java实现,因此实现了平台独立性。排序算法根据考频高低主要有:快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序、Timsort这十种,这类考核点要么是算法的时间、空间复杂度、稳定度,要么是直接手写代码,故在理解算法原理的同时,对JS语言版的排序算法代码也要加强记忆。JDBC API是面向对象的,可以让用户把常用的方法封装为—个类,以备后用。

m0_60721649的博客 700

Java学习路线图—精心整理 java进阶

看到过无数套毫无用处的Java路线图,到现在为止还在云端飘着,对于Java小白来说就像天书一般,Java大神看了以后感觉云山雾绕不知道讲什么东西,动力节点Java学院作为Java业界标杆深意为耻,于是从实际教学出发,呕心沥血整理出来Java学习路线图希望大家点波关注,你的关注是我的动力。出于对Java小白的考虑从Java基础出发,先对于Java小白从哪里入手有一个大体的认知,先踏进入门阶段,然后脚踏实地的出发,阶段性的来学习Java,一步一步蜕完成Java小白到大神的蜕变。Java基础入门概要。...

bsegebr的博客 313
上一篇: Maven 核心知识整理
下一篇: Spring核心之IOC与DI:手写工厂到Spring容器演进(第一部分)
StackNoOverflow
博客等级 码龄1年 22粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值