在Java企业级应用开发中,与数据库交互是核心技能,而JDBC(Java Database Connectivity)是这一技能的基石。掌握一套JDBC连接MySQL数据库完整增删改查代码,其核心价值远不止于实现数据存取,而在于深入理解数据库连接的底层管理、SQL执行的生命周期、资源泄漏的防范以及事务控制的基本思想,这是后续学习任何ORM框架(如MyBatis、Hibernate)不可或缺的前提。本文将手把手带你从驱动加载到连接关闭,完成一套生产可用的CRUD模板。
一、 环境准备与项目搭建

1. 引入MySQL驱动依赖 首先,你需要将MySQL的JDBC驱动jar包加入项目。以Maven项目为例,在`pom.xml`中添加:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version> <!-- 请使用与MySQL服务匹配的版本 -->
</dependency>
如果使用非Maven项目,需手动下载对应的`mysql-connector-java.jar`并添加到项目的构建路径中。
2. 创建数据库与测试表 在MySQL中执行以下SQL,准备测试环境:
CREATE DATABASE IF NOT EXISTS `jdbc_demo`; USE `jdbc_demo`;CREATE TABLE
user(idINT PRIMARY KEY AUTO_INCREMENT,nameVARCHAR(50) NOT NULL,ageINT,create_timeTIMESTAMP DEFAULT CURRENT_TIMESTAMP );
INSERT INTOuser(name,age) VALUES ('张三', 'zhangsan@example.com', 25), ('李四', 'lisi@example.com', 30);
二、 核心基石:编写数据库连接工具类
直接在每个方法中编写连接代码会导致大量重复和难以维护。最佳实践是封装一个工具类,集中管理数据库连接参数和获取连接的方法。这是JDBC连接MySQL数据库完整增删改查代码走向规范化的第一步。
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ResourceBundle;public class JdbcUtil { // 使用配置文件(如jdbc.properties)管理敏感信息,避免硬编码 private static final String DRIVER; private static final String URL; private static final String USER; private static final String PASSWORD;
static { // 加载配置文件 ResourceBundle bundle = ResourceBundle.getBundle(“jdbc”); DRIVER = bundle.getString(“jdbc.driver”); URL = bundle.getString(“jdbc.url”); USER = bundle.getString(“jdbc.user”); PASSWORD = bundle.getString(“jdbc.password”); try { // 1. 注册驱动 (MySQL 8+ 可省略此步,但显式加载更清晰) Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(“加载数据库驱动失败!”); } } /** * 获取数据库连接 * @return Connection 对象 * @throws SQLException */ public static Connection getConnection() throws SQLException { // 2. 建立连接 return DriverManager.getConnection(URL, USER, PASSWORD); } // 关闭资源的方法将在后面统一展示
}
对应的`src/main/resources/jdbc.properties`配置文件内容:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbc_demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false
jdbc.user=你的用户名
jdbc.password=你的密码
在鳄鱼java的项目规范中,将数据库配置外部化是强制要求,这提高了安全性和部署灵活性。
三、 模板与核心:增删改查的标准化实现
接下来,我们将实现一个`UserDao`类,包含完整的CRUD操作。请特别注意其中的资源管理和异常处理。
import java.sql.*; import java.util.ArrayList; import java.util.List;public class UserDao {
/** * 增(Create) - 插入用户 * @param user 用户对象(假设有name, email, age属性) * @return 插入的行数,或生成的主键(根据需求) */ public int insert(User user) { String sql = “INSERT INTO user(name, email, age) VALUES(?, ?, ?)”; // 使用 try-with-resources 自动关闭 Connection, PreparedStatement try (Connection conn = JdbcUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { pstmt.setString(1, user.getName()); // 参数索引从1开始 pstmt.setString(2, user.getEmail()); pstmt.setInt(3, user.getAge()); int affectedRows = pstmt.executeUpdate(); // 执行更新 // 获取自增主键 try (ResultSet generatedKeys = pstmt.getGeneratedKeys()) { if (generatedKeys.next()) { return generatedKeys.getInt(1); // 返回生成的主键ID } } return affectedRows; } catch (SQLException e) { // 应转换为自定义的业务异常,此处简化处理 throw new RuntimeException(“插入用户失败”, e); } // 无需手动关闭 conn 和 pstmt,try-with-resources 会自动处理 } /** * 删(Delete) - 根据ID删除用户 * @param id 用户ID * @return 受影响的行数 */ public int deleteById(int id) { String sql = “DELETE FROM user WHERE id = ?”; try (Connection conn = JdbcUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, id); return pstmt.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(“删除用户失败”, e); } } /** * 改(Update) - 根据ID更新用户信息 * @param user 用户对象(需包含id) * @return 受影响的行数 */ public int update(User user) { String sql = “UPDATE user SET name=?, email=?, age=? WHERE id=?”; try (Connection conn = JdbcUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, user.getName()); pstmt.setString(2, user.getEmail()); pstmt.setInt(3, user.getAge()); pstmt.setInt(4, user.getId()); return pstmt.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(“更新用户失败”, e); } } /** * 查(Retrieve) - 根据ID查询单个用户 * @param id 用户ID * @return User对象,未找到返回null */ public User selectById(int id) { String sql = “SELECT id, name, email, age, create_time FROM user WHERE id = ?”; try (Connection conn = JdbcUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, id); try (ResultSet rs = pstmt.executeQuery()) { // 嵌套try-with-resources关闭ResultSet if (rs.next()) { return extractUserFromResultSet(rs); // 封装结果集到对象 } return null; } } catch (SQLException e) { throw new RuntimeException(“查询用户失败”, e); } } /** * 查(Retrieve) - 查询所有用户 * @return 用户列表 */ public List<User> selectAll() { String sql = “SELECT id, name, email, age, create_time FROM user”; List<User> userList = new ArrayList<>(); try (Connection conn = JdbcUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery()) { while (rs.next()) { userList.add(extractUserFromResultSet(rs)); } return userList; } catch (SQLException e) { throw new RuntimeException(“查询所有用户失败”, e); } } /** * 工具方法:从ResultSet中提取数据构建User对象 * @param rs ResultSet * @return User对象 * @throws SQLException */ private User extractUserFromResultSet(ResultSet rs) throws SQLException { User user = new User(); user.setId(rs.getInt(“id”)); user.setName(rs.getString(“name”)); user.setEmail(rs.getString(“email”)); user.setAge(rs.getInt(“age”)); user.setCreateTime(rs.getTimestamp(“create_time”)); return user; }
}
这份JDBC连接MySQL数据库完整增删改查代码模板清晰地展示了几个黄金法则:
1. 必须使用PreparedStatement:它通过预编译和参数绑定,从根本上防止了SQL注入攻击,同时提升了SQL执行效率。绝对禁止使用字符串拼接来构造SQL语句。
2. 必须使用try-with-resources管理资源:确保`Connection`、`PreparedStatement`和`ResultSet`这些实现了`AutoCloseable`接口的资源在任何情况下(包括异常)都能被正确关闭,避免连接泄漏导致数据库连接池耗尽。
3. 结果集到对象的映射:`extractUserFromResultSet`方法展示了手动ORM的过程,这是理解所有高级框架底层原理的关键。
四、 进阶:事务处理与连接池引入
1. 事务管理 对于需要原子性的一组操作(如转账),必须使用事务。
try (Connection conn = JdbcUtil.getConnection()) {
conn.setAutoCommit(false); // 1. 开启事务(关闭自动提交)
// 执行多个 insert/update/delete 操作
// ...
conn.commit(); // 2. 提交事务
} catch (SQLException e) {
// conn.rollback(); // 3. 在catch块或finally块中回滚
throw new RuntimeException(“事务执行失败”, e);
}
2. 引入数据库连接池 上述例子中,每次操作都新建物理连接,性能极差。生产环境必须使用连接池,如HikariCP(目前性能最优)、Druid(功能强大)。以HikariCP为例:
// 在JdbcUtil中,用HikariDataSource替代DriverManager
HikariConfig config = new HikariConfig();
config.setJdbcUrl(URL);
config.setUsername(USER);
config.setPassword(PASSWORD);
private static final HikariDataSource dataSource = new HikariDataSource(config);
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); // 从池中获取连接
}
连接池负责管理连接的创建、复用和销毁,这是高并发应用的基石。在鳄鱼java的线上项目中,连接池是标准配置。
五、 总结:从原生JDBC到现代框架的桥梁
通过这套完整的JDBC连接MySQL数据库完整增删改查代码实战,我们不仅学会了如何操作数据库,更重要的是建立了对数据访问层的基本认知:连接管理、会话生命周期、资源安全释放和SQL执行。这正是理解MyBatis(它封装了JDBC)或Spring Data JPA(它抽象了JDBC)等框架内部运作的钥匙。
在鳄鱼java看来,一个Java开发者即使未来只使用高级框架,也必须扎实地走一遍原生JDBC的实践之路。这能让你在框架出现诡异问题时,有能力深入底层排查;在需要极致优化时,知道从何处着手。
现在,请你基于这个模板进行扩展:如何实现分页查询?如何批量插入以提升性能?当查询结果字段很多时,是否有更优雅的方式封装对象?理解基础,方能驾驭复杂。你的下一个挑战,或许是尝试用这套原生代码实现一个简单的ORM映射框架。
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。





