java jdbc的使用及实践

在这里插入图片描述

介绍

JDBC(Java Database Connectivity)的由来可以追溯到1990年代中期,当时Java语言正在蓬勃发展之中。在那个时期,Java以其“一次编写,到处运行”的理念迅速赢得了开发者的青睞。然而,为了进一步扩展Java语言在企业级应用中的可用性,需要一个标准化的接口,让Java应用能够与数据库进行交互,这就是JDBC诞生的背景。

背景

在JDBC出现之前,数据库互操作性常常依赖于数据库厂商特定的API,或者是采用诸如ODBC(Open Database Connectivity)这样的数据库互联接口。这些方法或多或少存在一定的限制,特别是对于Java这样旨在跨平台运行的语言来说。例如,使用ODBC需要通过JNI(Java Native Interface)来进行连接,这降低了Java程序的可移植性。

发展

为了解决这个问题,Java的母公司Sun Microsystems(太阳微系统)发布了JDBC API。JDBC 1.0在1997年随JDK 1.1发布,标志着Java程序可以直接,以一种跨平台的、与数据库厂商无关的方式来访问数据库。从那时起,JDBC API成为了Java SE(Standard Edition)的一部分。

目的和设计

JDBC API的主要目的是提供一个统一的、数据库无关的方法来访问多种关系型数据库。这意味着Java开发者可以用几乎相同的代码基础来与不同的数据库进行交互,仅需更换相应数据库的JDBC驱动即可完成对不同数据库的访问,大大提高了代码的可重用性和开发效率。

JDBC API通过“驱动管理器”和“数据库URL”简化了数据库连接过程。它提供了一套接口(如Connection、Statement、ResultSet等),开发者可以使用这些接口与数据库进行交互,而这些接口均由具体数据库的JDBC驱动实现。

演进

随着时间的推移,JDBC API经历了多个版本的更新,每个版本都增加了新的特性和性能改进。例如,JDBC 2.0(包含在JDK 1.2中)增加了批处理、滚动结果集等特性,JDBC 3.0提高了连接池管理,而JDBC 4.0引入了自动发现驱动的能力,简化了驱动的加载过程。

结论

总的来说,JDBC是Java技术栈中关键的一环,它有效地弥合了Java应用与数据库之间的鸿沟,使得Java成为了一个理想的选择,用于开发企业级数据库驱动的应用。JDBC以其强大的数据库操作能力、跨平台的特性、以及出色的扩展性,继续在当今的软件开发领域发挥着重要作用。

JDBC的主要组件

  1. DriverManager:这个类管理一组JDBC驱动程序的列表。当一个应用程序尝试连接数据库时,DriverManager会负责寻找合适的驱动来建立连接。

  2. Connection:表示应用程序和数据库之间的连接(或会话)。通过Connection对象,可以管理事务(比如提交或回滚事务)。

  3. Statement:用于在数据库上执行静态SQL语句并返回它所生成结果的对象。

  4. PreparedStatement:继承自Statement,它表示预编译的SQL语句。这种语句的性能更好,并且可以防止SQL注入攻击。

  5. CallableStatement:继承自PreparedStatement,用于执行数据库存储过程。

  6. ResultSet:表示SQL语句执行结果的数据集。它允许以迭代方式读取数据。

JDBC使用流程

  1. 加载JDBC驱动:加载连接数据库所需要的驱动,可以通过调用Class.forName()实现。
Class.forName("com.mysql.jdbc.Driver");
  1. 建立连接:使用DriverManager.getConnection()方法通过数据库的URL、用户名和密码来建立连接。
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/数据库名", "用户名", "密码");
  1. 创建Statement:创建一个Statement或PreparedStatement对象,用于执行SQL语句。
Statement stmt = conn.createStatement();
  1. 执行SQL语句:执行SQL查询或更新语句。
ResultSet rs = stmt.executeQuery("SELECT * FROM 表名");
  1. 处理结果:处理ResultSet中的数据(仅针对查询操作)。
while (rs.next()) {
    System.out.println(rs.getString("列名"));
}
  1. 清理环境:关闭ResultSet、Statement和Connection对象。
rs.close();
stmt.close();
conn.close();

JDBC的事务管理

JDBC允许开发者通过Connection对象控制事务。默认情况下,JDBC的事务是自动提交的,这意味着每条SQL语句被执行后会立即提交。如果需要手动控制事务,可以关闭自动提交模式,然后显式地提交或回滚事务:

// 关闭自动提交
conn.setAutoCommit(false);

// 执行SQL语句
// ...

// 提交事务
conn.commit();

// 或回滚事务
// conn.rollback();

JDBC驱动类型

JDBC驱动主要分为四种类型:

  1. 类型1:JDBC-ODBC桥驱动(不再推荐使用)
  2. 类型2:本地API部分Java驱动
  3. 类型3:网络协议全Java驱动
  4. 类型4:数据库协议全Java驱动(直接连接数据库,无需其他服务器或桥接程序,通常推荐使用类型4驱动)

结论

JDBC为Java应用提供了一种与数据库交互的强大机制,通过将Java代码与数据库交互细节解耦,使数据库访问更加标准化和简化。了解和掌握JDBC对于任何从事Java开发,并需要与关系型数据库交互的开发者来说,都是非常重要的。

insert和batch insert

  1. 插入单条记录(Insert)
    插入单条记录通常使用 PreparedStatement。预编译的 SQL 语句提高了性能,并且有助于防止SQL注入攻击。

示例:

假设我们有一个数据库名为 mydatabase,表名为 students,表结构包含两列:id(INT 类型)和 name(VARCHAR 类型)。

以下是插入单条记录到 students 表的 JDBC 代码示例:

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

public class JdbcInsertDemo {
    public static void main(String[] args) {
        String jdbcURL = "jdbc:mysql://localhost:3306/mydatabase";
        String username = "user";
        String password = "password";

        try {
            Connection connection = DriverManager.getConnection(jdbcURL, username, password);

            // 插入SQL语句
            String sql = "INSERT INTO students (id, name) VALUES (?, ?)";

            // 创建PreparedStatement
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setInt(1, 1);  // 设置第一个问号(id)的值为 1
            statement.setString(2, "John Doe");  // 设置第二个问号(name)的值为 John Doe

            int rowsInserted = statement.executeUpdate();

            // 检查插入是否成功
            if (rowsInserted > 0) {
                System.out.println("A new student was inserted successfully!");
            }

            // 关闭连接
            statement.close();
            connection.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 批量插入多条记录(Batch Insert)
    当需要插入多条记录时,使用批处理方式可以大大提高性能,减少对数据库的操作次数。

示例:
我们使用相同的数据库和表结构执行批量插入操作。

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

public class JdbcBatchInsertDemo {
    public static void main(String[] args) {
        String jdbcURL = "jdbc:mysql://localhost:3306/mydatabase";
        String username = "user";
        String password = "password";

        try {
            Connection connection = DriverManager.getConnection(jdbcURL, username, password);

            // 关闭自动提交
            connection.setAutoCommit(false);

            // 插入SQL语句
            String sql = "INSERT INTO students (id, name) VALUES (?, ?)";

            // 创建PreparedStatement
            PreparedStatement statement = connection.prepareStatement(sql);

            // 添加多批次操作到PreparedStatement
            for (int i = 1; i <= 5; i++) {
                statement.setInt(1, i);
                statement.setString(2, "Student " + i);
                statement.addBatch();  // 将这个设置的参数加入到批处理中
            }
            
            // 执行批处理操作
            int[] rowsInserted = statement.executeBatch();

            // 提交事务
            connection.commit();

            System.out.println("Inserted rows: " + rowsInserted.length);
            
            // 关闭连接
            statement.close();
            connection.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,我们用 PreparedStatement.addBatch() 方法添加了多个插入操作到批处理任务中,最后用 executeBatch() 方法执行这些操作。使用 connection.setAutoCommit(false) 和 connection.commit() 来手动管理事务,保证所有插入操作要么全部成功,要么全部失败,从而保持数据的一致性。

update和batch update

  1. 更新单条记录(Update)
    更新操作通常使用 PreparedStatement 来实现,以提高性能并防止SQL注入攻击。

示例:
假设我们有一个数据库名为 mydatabase,表名为 students,要更新这个表中的记录。

String jdbcURL = "jdbc:mysql://localhost:3306/mydatabase";
String username = "root";
String password = "password";

try {
    Connection connection = DriverManager.getConnection(jdbcURL, username, password);

    // 更新SQL语句
    String sql = "UPDATE students SET name = ? WHERE id = ?";

    // 创建PreparedStatement
    PreparedStatement statement = connection.prepareStatement(sql);
    statement.setString(1, "John Doe Updated");  // 将名字更新为 'John Doe Updated'
    statement.setInt(2, 1);  // 更新id为1的记录

    int rowsUpdated = statement.executeUpdate();

    // 检查更新是否成功
    if (rowsUpdated > 0) {
        System.out.println("An existing student was updated successfully!");
    }

    // 关闭连接
    statement.close();
    connection.close();

} catch (Exception e) {
    e.printStackTrace();
}
  1. 批量更新多条记录(Batch Update)
    当需要更新多条记录时,使用批处理(Batch Processing)方式可以大大提高效率,减少对数据库的操作次数。

示例:
仍然使用相同的数据库和表结构来执行批量更新操作。

String jdbcURL = "jdbc:mysql://localhost:3306/mydatabase";
String username = "root";
String password = "password";

try {
    Connection connection = DriverManager.getConnection(jdbcURL, username, password);

    // 关闭自动提交
    connection.setAutoCommit(false);

    // 更新SQL语句
    String sql = "UPDATE students SET name = ? WHERE id = ?";

    // 创建PreparedStatement
    PreparedStatement statement = connection.prepareStatement(sql);

    // 添加多个批次操作到PreparedStatement
    for (int i = 1; i <= 5; i++) {
        statement.setString(1, "Student " + i + " Updated");
        statement.setInt(2, i);  // 更新id为i的记录
        statement.addBatch();  // 将这个设置的参数加入到批处理中
    }
    
    // 执行批处理操作
    int[] rowsUpdated = statement.executeBatch();

    // 提交事务
    connection.commit();

    System.out.println("Updated rows count: " + rowsUpdated.length);
    
    // 关闭连接
    statement.close();
    connection.close();

} catch (Exception e) {
    e.printStackTrace();
}

在这个例子中,我们通过使用 addBatch() 方法向 PreparedStatement 添加了多个更新操作。然后,使用 executeBatch() 方法执行这些操作。使用 connection.setAutoCommit(false) 来关闭自动提交,并手动调用 connection.commit() 提交事务,从而确保这些更新操作要么全部成功,要么在遇到错误时全部撤回,以保持数据的一致性。

事务的重要性

在批量更新中,手动管理事务非常重要,因为它可以保障数据的完整性和一致性。如果在处理过程中发生错误,它允许我们回滚到事务开始之前的状态,撤销所有的更新操作。通过调用 connection.rollback() (在捕获异常时)实现。

delete和batch delete

单条记录删除(Delete)

删除操作通常使用 PreparedStatement 来实现,以提高性能并防止 SQL 注入攻击。

示例:
假设我们有一个数据库名为 mydatabase,表名为 students,并想删除该表中的某些记录。

String jdbcURL = "jdbc:mysql://localhost:3306/mydatabase";
String username = "root";
String password = "password";

try {
    Connection connection = DriverManager.getConnection(jdbcURL, username, password);

    // DELETE SQL语句
    String sql = "DELETE FROM students WHERE id = ?";

    // 创建PreparedStatement
    PreparedStatement statement = connection.prepareStatement(sql);
    statement.setInt(1, 1);  // 删除id为1的记录

    int rowsDeleted = statement.executeUpdate();

    // 检查删除是否成功
    if (rowsDeleted > 0) {
        System.out.println("A student was deleted successfully!");
    }

    // 关闭连接
    statement.close();
    connection.close();

} catch (Exception e) {
    e.printStackTrace();
}

这段代码将删除 students 表中 id 等于 1 的记录。

批量删除多条记录(Batch Delete)

与批量插入或更新相似,可以使用批处理来删除多条记录,从而减少数据库操作的次数和提高性能。

示例:
使用相同的数据库和表结构来执行批量删除操作。

String jdbcURL = "jdbc:mysql://localhost:3306/mydatabase";
String username = "root";
String password = "password";

try {
    Connection connection = DriverManager.getConnection(jdbcURL, username, password);

    // 关闭自动提交
    connection.setAutoCommit(false);

    // DELETE SQL语句
    String sql = "DELETE FROM students WHERE id = ?";

    // 创建PreparedStatement
    PreparedStatement statement = connection.prepareStatement(sql);

    // 添加多个批次操作到PreparedStatement
    for (int i = 1; i <= 5; i++) {
        statement.setInt(1, i);  // 删除id为i的记录
        statement.addBatch();  // 将这个设置的参数加入到批处理中
    }
    
    // 执行批量删除操作
    int[] rowsDeleted = statement.executeBatch();

    // 提交事务
    connection.commit();

    System.out.println("Deleted rows count: " + rowsDeleted.length);
    
    // 关闭连接
    statement.close();
    connection.close();

} catch (Exception e) {
    e.printStackTrace();
}

在这个例子中,我们通过使用 addBatch() 方法向 PreparedStatement 中添加了多个删除操作。然后,使用 executeBatch() 方法执行这些操作。使用 connection.setAutoCommit(false) 来关闭自动提交,并手动调用 connection.commit() 提交事务。与更新操作类似,这样做可以确保这些删除操作要么全部成功,要么在遇到错误时全部撤回,以保持数据的一致性。

在处理可能遇到的任何 SQLException 时,应该对事务进行回滚,使用 connection.rollback()。这会撤销自上一个提交或回滚以来执行的所有更改。在生产环境中,你通常也需要添加适当的错误处理,并且始终确保资源在使用后被适当地关闭,最好是在 finally 块或使用 try-with-resources 语句。

查询

在 JDBC 中,执行查询操作通常涉及到以下步骤:编写 SQL 查询语句、执行查询、处理 ResultSet 对象并提取数据,以及最后清理资源。

下面是一个使用 JDBC 执行查询操作并处理结果集的完整示例。

示例:
假设我们有一个数据库名为 mydatabase,表名为 employees,表结构包含以下列:id(INT 类型)、name(VARCHAR 类型)和 department(VARCHAR 类型)。

要查询 employees 表中的数据,可以使用以下 JDBC 代码:

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

public class JdbcSelectDemo {

    public static void main(String[] args) {
        String jdbcURL = "jdbc:mysql://localhost:3306/mydatabase";
        String username = "root";
        String password = "password";
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        
        try {
            // 建立数据库连接
            connection = DriverManager.getConnection(jdbcURL, username, password);
            
            // 准备 SQL 查询语句
            String sql = "SELECT id, name, department FROM employees";
            
            // 创建 PreparedStatement 对象
            statement = connection.prepareStatement(sql);
            
            // 执行查询语句并获取结果集
            resultSet = statement.executeQuery();
            
            // 遍历结果集并获取数据
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String department = resultSet.getString("department");
                
                // 打印出从数据库中检索的数据
                System.out.println("ID: " + id + ", Name: " + name + ", Department: " + department);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭 ResultSet
                if (resultSet != null) {
                    resultSet.close();
                }
                // 关闭 PreparedStatement
                if (statement != null) {
                    statement.close();
                }
                // 关闭 Connection
                if (connection != null) {
                    connection.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

在这个例子中,我们建立了与数据库的连接,使用了一个 SELECT 语句来查询 employees 表。然后使用 PreparedStatement.executeQuery 方法执行了查询,并返回了一个 ResultSet 对象。

通过 while 循环和 ResultSet.next 方法遍历结果集,我们可以逐行读取数据。通过 ResultSet 的 getInt、getString 等方法根据列的数据类型来获取每列的值。

最后,我们在 finally 块中关闭了 ResultSet、PreparedStatement 和 Connection。这样做是很重要的,因为它可以释放数据库和 JDBC 资源,避免内存泄漏和其他潜在问题。一个更清洁的替代方案是使用 Java 7 引入的 try-with-resources 语法,这将自动关闭在 try 语句中打开的资源。

JDBC 的查询操作是 数据库交互的核心,不仅可以检索整个表格或者特定列,还可以根据需要进行条件查询、联合查询或其他复杂的数据库操作。

参考资料

官方文档和教程:

  • Oracle官方JDBC文档:Oracle提供了完整的JDBC参考文档,其中包含了API的全部细节。
  • Oracle的JDBC教程:一个涵盖JDBC基础概念到高级特性的综合性教程。
    这些资源对理解 JDBC 的不同方面以及如何与数据库交互非常有帮助。您可以在 Oracle 的官方网站或Java的官方文档中找到这些资源。

官方API规范:

  • 访问Java SE API规范可以查看关于 JDBC 接口和类的官方说明。
  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

namedlock

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值