跳转至

Java JDBC Example 深度解析

简介

在Java开发中,与数据库进行交互是非常常见的需求。Java Database Connectivity(JDBC)提供了一种标准的方式来实现Java程序与各种数据库之间的通信。本文将通过详细的示例,深入探讨JDBC的基础概念、使用方法、常见实践以及最佳实践,帮助读者全面掌握JDBC在Java项目中的应用。

目录

  1. 基础概念
    • JDBC 是什么
    • JDBC 架构
  2. 使用方法
    • 加载 JDBC 驱动
    • 建立数据库连接
    • 创建 SQL 语句执行对象
    • 执行 SQL 语句
    • 处理结果集
    • 关闭资源
  3. 常见实践
    • 插入数据
    • 查询数据
    • 更新数据
    • 删除数据
  4. 最佳实践
    • 连接池的使用
    • 事务管理
    • 防止 SQL 注入
  5. 小结
  6. 参考资料

基础概念

JDBC 是什么

JDBC 是 Java 编程语言中用于执行 SQL 语句的 API。它为开发人员提供了一组标准的接口,使得 Java 程序能够与不同类型的数据库(如 MySQL、Oracle、SQL Server 等)进行交互,而无需关心底层数据库的具体实现细节。

JDBC 架构

JDBC 架构主要由以下几个部分组成: - JDBC API:提供给 Java 开发人员使用的接口,包括 Connection、Statement、ResultSet 等,用于与数据库进行交互。 - JDBC Driver API:供驱动开发人员实现的接口,不同的数据库厂商需要根据这些接口来开发自己的 JDBC 驱动。 - JDBC 驱动:负责与具体的数据库进行通信,将 JDBC API 的调用转换为数据库特定的操作。

使用方法

下面通过一个完整的示例来展示 JDBC 的基本使用流程。假设我们使用 MySQL 数据库,首先需要下载并添加 MySQL JDBC 驱动到项目的类路径中。

加载 JDBC 驱动

在 Java 中,我们可以使用 Class.forName() 方法来加载 JDBC 驱动。

try {
    Class.forName("com.mysql.cj.jdbc.Driver");
    System.out.println("JDBC驱动加载成功");
} catch (ClassNotFoundException e) {
    System.out.println("JDBC驱动加载失败");
    e.printStackTrace();
}

建立数据库连接

使用 DriverManager.getConnection() 方法来建立与数据库的连接。需要提供数据库的 URL、用户名和密码。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        try {
            Connection connection = DriverManager.getConnection(url, username, password);
            System.out.println("数据库连接成功");
            // 后续操作
            connection.close();
        } catch (SQLException e) {
            System.out.println("数据库连接失败");
            e.printStackTrace();
        }
    }
}

创建 SQL 语句执行对象

通过 Connection 对象创建 StatementPreparedStatement 对象,用于执行 SQL 语句。Statement 用于执行普通的 SQL 语句,PreparedStatement 用于执行预编译的 SQL 语句,能有效防止 SQL 注入。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        try {
            Connection connection = DriverManager.getConnection(url, username, password);
            Statement statement = connection.createStatement();
            // 后续操作
            statement.close();
            connection.close();
        } catch (SQLException e) {
            System.out.println("数据库操作失败");
            e.printStackTrace();
        }
    }
}

执行 SQL 语句

使用 StatementPreparedStatementexecuteQuery() 方法执行查询语句,executeUpdate() 方法执行插入、更新和删除语句。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        try {
            Connection connection = DriverManager.getConnection(url, username, password);
            Statement statement = connection.createStatement();
            String sql = "SELECT * FROM users";
            ResultSet resultSet = statement.executeQuery(sql);
            // 处理结果集
            resultSet.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
            System.out.println("数据库操作失败");
            e.printStackTrace();
        }
    }
}

处理结果集

使用 ResultSet 对象来处理查询结果。可以通过 next() 方法移动到下一行记录,并使用 getXXX() 方法获取不同类型的列值。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        try {
            Connection connection = DriverManager.getConnection(url, username, password);
            Statement statement = connection.createStatement();
            String sql = "SELECT * FROM users";
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                System.out.println("ID: " + id + ", Name: " + name);
            }
            resultSet.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
            System.out.println("数据库操作失败");
            e.printStackTrace();
        }
    }
}

关闭资源

在完成数据库操作后,需要关闭 ResultSetStatementConnection 对象,以释放资源。

try {
    if (resultSet != null) resultSet.close();
    if (statement != null) statement.close();
    if (connection != null) connection.close();
} catch (SQLException e) {
    e.printStackTrace();
}

常见实践

插入数据

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class InsertExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        String sql = "INSERT INTO users (name, age) VALUES (?,?)";

        try (Connection connection = DriverManager.getConnection(url, username, password);
             PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

            preparedStatement.setString(1, "John Doe");
            preparedStatement.setInt(2, 30);

            int rowsInserted = preparedStatement.executeUpdate();
            if (rowsInserted > 0) {
                System.out.println("数据插入成功");
            }
        } catch (SQLException e) {
            System.out.println("数据插入失败");
            e.printStackTrace();
        }
    }
}

查询数据

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class QueryExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        String sql = "SELECT * FROM users WHERE age >?";

        try (Connection connection = DriverManager.getConnection(url, username, password);
             PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

            preparedStatement.setInt(1, 25);
            ResultSet resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
            }
        } catch (SQLException e) {
            System.out.println("数据查询失败");
            e.printStackTrace();
        }
    }
}

更新数据

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class UpdateExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        String sql = "UPDATE users SET age =? WHERE id =?";

        try (Connection connection = DriverManager.getConnection(url, username, password);
             PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

            preparedStatement.setInt(1, 35);
            preparedStatement.setInt(2, 1);

            int rowsUpdated = preparedStatement.executeUpdate();
            if (rowsUpdated > 0) {
                System.out.println("数据更新成功");
            }
        } catch (SQLException e) {
            System.out.println("数据更新失败");
            e.printStackTrace();
        }
    }
}

删除数据

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class DeleteExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        String sql = "DELETE FROM users WHERE id =?";

        try (Connection connection = DriverManager.getConnection(url, username, password);
             PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

            preparedStatement.setInt(1, 2);

            int rowsDeleted = preparedStatement.executeUpdate();
            if (rowsDeleted > 0) {
                System.out.println("数据删除成功");
            }
        } catch (SQLException e) {
            System.out.println("数据删除失败");
            e.printStackTrace();
        }
    }
}

最佳实践

连接池的使用

连接池可以预先创建一定数量的数据库连接,并在需要时复用这些连接,从而减少连接创建和销毁的开销,提高系统性能。常见的连接池有 HikariCP、C3P0、DBCP 等。

以下是使用 HikariCP 的示例:

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.Connection;
import java.sql.SQLException;

public class ConnectionPoolExample {
    private static HikariDataSource dataSource;

    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        config.setUsername("root");
        config.setPassword("password");
        dataSource = new HikariDataSource(config);
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void main(String[] args) {
        try (Connection connection = getConnection()) {
            System.out.println("从连接池获取到连接");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

事务管理

事务是一组不可分割的数据库操作序列,要么全部执行成功,要么全部失败回滚。在 JDBC 中,可以通过 Connection 对象的 setAutoCommit(false)commit()rollback() 方法来实现事务管理。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TransactionExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        String sql1 = "INSERT INTO users (name, age) VALUES ('Alice', 28)";
        String sql2 = "UPDATE users SET age = age + 1 WHERE name = 'Alice'";

        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            connection.setAutoCommit(false);

            try (PreparedStatement preparedStatement1 = connection.prepareStatement(sql1);
                 PreparedStatement preparedStatement2 = connection.prepareStatement(sql2)) {

                preparedStatement1.executeUpdate();
                preparedStatement2.executeUpdate();

                connection.commit();
                System.out.println("事务执行成功");
            } catch (SQLException e) {
                connection.rollback();
                System.out.println("事务回滚");
                e.printStackTrace();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

防止 SQL 注入

使用 PreparedStatement 而不是 Statement 可以有效防止 SQL 注入。PreparedStatement 会对传入的参数进行预编译,将参数值与 SQL 语句分开处理,从而避免恶意 SQL 语句的执行。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class AntiSqlInjectionExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "password";

        String sql = "SELECT * FROM users WHERE name =?";
        String input = "John' OR '1'='1"; // 模拟恶意输入

        try (Connection connection = DriverManager.getConnection(url, username, password);
             PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

            preparedStatement.setString(1, input);
            ResultSet resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                System.out.println("ID: " + id + ", Name: " + name);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

小结

本文详细介绍了 Java JDBC 的基础概念、使用方法、常见实践以及最佳实践。通过示例代码展示了如何进行数据库连接、执行 SQL 语句、处理结果集以及如何优化 JDBC 应用。掌握这些知识,能够帮助开发人员更加高效、安全地实现 Java 程序与数据库的交互,提升项目的质量和性能。

参考资料