当前位置:首页 > 后端开发 > 正文

java里怎么调用数据库

在 Java 中通过 JDBC 调用数据库:先加载驱动类,用 DriverManager 获取连接;再创建 Statement 对象,执行 SQL 语句;最后处理结果集

以下是关于 Java 调用数据库 的完整技术指南,涵盖核心步骤、最佳实践及典型场景实现:


前置准备与核心依赖

1 必备组件清单

类别 名称/描述 作用说明
JDBC驱动 mysql-connector-java.jar MySQL官方提供的Java数据库连接器
项目配置文件 jdbc.properties 存储数据库连接参数(如URL/账号/密码)
Java核心API java.sql. 提供标准数据库操作接口
IDE工具链 Maven/Gradle + IntelliJ IDEA 项目管理与代码调试支持

2 环境配置要点

  • Maven依赖声明(以MySQL为例):
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
    </dependency>
  • 属性文件内容示例 (src/main/resources/jdbc.properties):
    db.url=jdbc:mysql://localhost:3306/mydatabase?useSSL=false&serverTimezone=UTC
    db.user=root
    db.password=123456

标准开发流程详解

1 五步法实现数据库交互

序号 阶段 关键技术点 注意事项
1 加载数据库驱动 Class.forName("com.mysql.cj.jdbc.Driver") 仅适用于传统方式,新版JDBC可省略此步
2 建立数据库连接 DriverManager.getConnection(url, user, password) 必传三要素:URL/用户名/密码
3 创建执行器对象 Connection.createStatement() → 普通语句
prepareStatement(sql) → 预编译语句
优先使用PreparedStatement防SQL注入
4 执行SQL指令 executeUpdate()→更新操作
executeQuery()→查询操作
根据业务类型选择对应方法
5 处理结果集 ResultSet遍历+next()判断+getXXX()取值 严格遵循列索引/别名映射规则
6 资源释放 close()顺序:ResultSet→Statement→Connection 必须放在finally块保证执行

2 完整代码示例(增删改查全场景)

import java.sql.;
import java.util.Properties;
public class JdbcDemo {
    // 静态常量定义
    private static final String PROPERTIES_PATH = "jdbc.properties";
    public static void main(String[] args) {
        // 1. 读取配置文件
        Properties prop = new Properties();
        try {
            prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_PATH));
        } catch (Exception e) {
            System.err.println("配置文件加载失败: " + e.getMessage());
            return;
        }
        // 2. 声明数据库连接变量
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            // 3. 建立数据库连接
            conn = DriverManager.getConnection(
                prop.getProperty("db.url"),
                prop.getProperty("db.user"),
                prop.getProperty("db.password")
            );
            // ========== 插入数据示例 ==========
            String insertSql = "INSERT INTO users(name, email) VALUES(?, ?)";
            pstmt = conn.prepareStatement(insertSql);
            pstmt.setString(1, "张三");
            pstmt.setString(2, "zhangsan@example.com");
            int affectedRows = pstmt.executeUpdate();
            System.out.println("插入成功,影响行数: " + affectedRows);
            // ========== 查询数据示例 ==========
            String selectSql = "SELECT id, name, email FROM users WHERE id = ?";
            pstmt = conn.prepareStatement(selectSql);
            pstmt.setInt(1, 1); // 假设刚插入的ID为1
            rs = pstmt.executeQuery();
            while(rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.printf("查询结果 ID:%d, 姓名:%s, 邮箱:%s%n", id, name, email);
            }
            // ========== 更新数据示例 ==========
            String updateSql = "UPDATE users SET email=? WHERE id=?";
            pstmt = conn.prepareStatement(updateSql);
            pstmt.setString(1, "new_email@example.com");
            pstmt.setInt(2, 1);
            affectedRows = pstmt.executeUpdate();
            System.out.println("更新成功,影响行数: " + affectedRows);
            // ========== 删除数据示例 ==========
            String deleteSql = "DELETE FROM users WHERE id=?";
            pstmt = conn.prepareStatement(deleteSql);
            pstmt.setInt(1, 1);
            affectedRows = pstmt.executeUpdate();
            System.out.println("删除成功,影响行数: " + affectedRows);
        } catch (SQLException e) {
            System.err.println("数据库操作异常: " + e.getMessage());
            e.printStackTrace();
        } finally {
            // 4. 逆向关闭资源
            try { if(rs != null) rs.close(); } catch(SQLException ignored) {}
            try { if(pstmt != null) pstmt.close(); } catch(SQLException ignored) {}
            try { if(conn != null) conn.close(); } catch(SQLException ignored) {}
        }
    }
}

3 关键机制解析

技术点 实现原理 优势分析
预编译语句(占位符) SQL模板预先编译,参数化绑定 防止SQL注入
提升重复执行效率
事务控制 conn.setAutoCommit(false) + commit()/rollback() 保证原子性操作
批量操作一致性
批处理 addBatch() + executeBatch() ⏱️ 减少网络往返次数
⏱️ 提升大数据量性能
连接池 HikariCP/C3P0/DBCP等第三方库 复用物理连接
降低建连开销

进阶优化策略

1 连接池选型对比表

连接池名称 特点 适用场景
HikariCP 轻量级/高性能/零配置启动 中小型应用首选
C3P0 功能丰富/支持缓存/JMX监控 复杂企业级系统
DBCP Apache Commons组件/简单易用 快速原型开发
Druid 阿里开源/监控功能强大/支持SQL防火墙 高并发生产环境

2 性能调优建议

  1. 索引优化:对高频查询字段建立复合索引
  2. 分页查询:使用LIMIT startIndex, pageSize替代全表扫描
  3. 懒加载:仅在需要时初始化数据库连接
  4. 超时设置jdbc:mysql://...?connectTimeout=5000&socketTimeout=10000
  5. 二进制日志:开启binlog用于主从复制和故障恢复

常见错误解决方案

错误现象 根本原因 解决方法
Communications link failure 网络中断/数据库服务未启动 检查防火墙/重启数据库服务
Access denied for user 用户名密码错误/权限不足 核对凭证/授予相应权限
Table doesn't exist 表名大小写不匹配/未创建表 统一使用反引号`table_name`
Too many connections 连接数超过最大限制 增大maxPoolSize或优化业务逻辑
Lock wait timeout exceeded 长事务导致锁竞争 缩短事务时长/优化锁粒度

相关问答FAQs

Q1: 如何有效防止SQL注入攻击?

A: 应始终使用PreparedStatement代替字符串拼接的Statement,通过占位符进行参数化绑定,JDBC驱动会自动对特殊字符进行转义。

java里怎么调用数据库  第1张

// 危险做法(易受注入)
String sql = "SELECT  FROM users WHERE username='" + userInput + "'";
// 安全做法(推荐)
String sql = "SELECT  FROM users WHERE username=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, userInput);

Q2: 为什么要按照ResultSet→Statement→Connection的顺序关闭资源?

A: 因为这三个对象存在依赖关系:ResultSet依赖于StatementStatement又依赖于Connection,如果先关闭父级对象(如Connection),子级对象(如ResultSet)会立即失效,反向关闭可以确保所有资源都被正确释放,避免内存泄漏,典型的finally块结构如下:

finally {
    try { if(rs != null) rs.close(); } catch(SQLException ignored) {}
    try { if(pstmt != null) pstmt.close(); } catch(SQLException ignored) {}
    try { if(conn != null) conn.close(); } catch(SQLException ignored) {}

0