40、Java数据库操作:从基础到实践

Java数据库操作:JDBC从基础到实践

Java数据库操作:从基础到实践

1. 知识回顾与练习

在学习Java数据库操作之前,有一个关于 NameDirectory 类的问题。该类需要能够存储20个不同的名称,要使类正常运行,应选择合适的语句来替换 // answer goes here 。选项如下:
- a. names[nameCount] = newName;
- b. names[nameCount] == newName;
- c. names[nameCount++] = newName;
- d. names[++nameCount] = newName;
答案可在相关网站查询。

为了拓展知识,还可以尝试以下练习:
- 从JARS JavaBean资源部分下载一个bean,并在BeanBox中使用它。
- 向Juggler项目中添加一个TickTock bean,该bean能按设定的时间间隔触发事件,尝试让它每30秒重启juggling bean。

2. Java数据库连接(JDBC)概述

几乎所有的Java程序都会以某种方式处理数据。随着程序复杂度的增加,原始类型、对象、数组等数据结构可能不再是最佳选择。Java Database Connectivity(JDBC)是一个类库,它可以将Java程序与多种关系型数据库(如Microsoft、Sybase、Oracle、Informix等)连接起来。通过使用驱动程序作为桥梁,我们可以直接从Java中存储和检索数据。

JDBC相关的学习内容包括:
- 使用JDBC驱动程序与不同的关系型数据库进行交互。
- 使用结构化查询语言(SQL)访问数据库。
- 设置JDBC数据源。
- 使用SQL和JDBC从数据库中读取记录。
- 使用SQL和JDBC向数据库中添加记录。

3. JDBC基础

JDBC是一组用于使用Java开发客户端/服务器数据库应用程序的类。客户端/服务器软件将信息用户与信息提供者连接起来,是最常见的编程形式之一,比如我们日常上网浏览网页就是这种模式。

数据库程序员面临的一个主要障碍是数据库格式的多样性,每种格式都有自己专有的数据访问方法。为了简化关系型数据库程序的使用,引入了标准语言SQL。使用SQL,我们可以向数据库发送复杂的查询,并按指定的顺序获取所需的记录。

例如,在学生贷款公司,数据库程序员可以使用SQL查询所有最后还款时间超过180天且欠款金额大于0的记录,并按社保号码、收款人姓名、欠款金额等字段排序。

虽然很多数据库格式都支持SQL,但在通过SQL访问特定数据库格式时,可能仍需要了解一些特殊的使用方法。

4. JDBC类库与数据库驱动

JDBC类库支持SQL,使开发人员能够使用各种数据库格式,而无需了解底层数据库的具体细节。JDBC还支持特定于数据库格式的查询。

JDBC库包含了与数据库使用相关的常用任务的类,这些类都位于Java 2的 java.sql 包中:
- 建立与数据库的连接。
- 使用SQL创建语句。
- 在数据库中执行SQL查询。
- 查看查询结果记录。

Java程序使用JDBC类时,可以遵循熟悉的编程模型,即发出SQL语句并处理结果数据,而无需考虑数据库的格式和平台。这种平台和数据库的独立性是通过驱动程序管理器实现的。对于不同的数据库格式,需要使用不同的驱动程序,有时同一格式的不同版本也可能需要不同的驱动程序。

JDBC数据库驱动程序可以完全用Java编写,也可以使用本地方法将Java应用程序与现有的数据库访问库连接起来。此外,JDBC还包含一个将JDBC与另一个数据库连接标准ODBC桥接的驱动程序。

5. JDBC - ODBC桥接

ODBC是Microsoft用于访问SQL数据库的通用接口,在Windows系统上由ODBC数据源管理器管理。可以通过以下步骤打开:
- 大多数Windows版本:点击“开始” - “设置” - “控制面板” - “ODBC数据源”。
- Windows XP:选择“开始” - “控制面板” - “性能和维护” - “管理工具” - “数据源(ODBC)”。

ODBC数据源管理器用于添加ODBC驱动程序、配置驱动程序以与特定数据库文件配合使用,并记录SQL使用情况。

使用JDBC - ODBC桥接需要以下三个条件:
- Java 2中包含的JDBC - ODBC桥接驱动程序: sun.jdbc.odbc.JdbcOdbcDriver
- 一个ODBC驱动程序。
- 一个已使用ODBC数据源管理器等软件与驱动程序关联的ODBC数据源。

ODBC数据源必须有简短的描述性名称,该名称将在Java程序中用于连接数据源所指向的数据库。

6. 连接到ODBC数据源

以下是使用JDBC - ODBC桥接连接到Microsoft Access文件的步骤:
1. 准备数据库文件 :项目使用的Access文件是 world20.mdb ,这是一个由美国能源信息管理局发布的世界能源统计数据库,其中的 Coal 表包含 Country Year Anthracite Production 三个字段。
2. 安装ODBC驱动程序 :确保系统上有支持Microsoft Access文件的ODBC驱动程序。
3. 创建ODBC数据源 :使用ODBC数据源管理器创建一个与 world20.mdb 关联的新ODBC数据源。具体操作如下:
- 打开ODBC数据源管理器,点击“用户DSN”选项卡,查看可用的数据源列表。
- 点击“添加”按钮,选择一个ODBC驱动程序,然后点击“完成”按钮。
- 在弹出的设置窗口中,提供数据库的名称、简短描述等信息,点击“选择”按钮找到并选择数据库文件。
4. 加载驱动程序 :在Java程序中使用 Class.forName(String) 方法加载驱动程序。对于使用ODBC数据源的程序,需要加载 sun.jdbc.odbc.JdbcOdbcDriver ,代码如下:

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
  1. 建立连接 :使用 DriverManager 类的 getConnection(String, String, String) 方法建立与数据源的连接。该方法返回一个表示活动数据连接的 Connection 对象。三个参数分别是:
    • 标识数据源和所使用的数据库连接类型的名称。
    • 用户名。
    • 密码。
      如果数据源没有设置用户名和密码,后两个参数可以为空字符串。使用JDBC - ODBC桥接时,数据源名称前需要加上 jdbc:odbc: ,例如:
Connection payday = DriverManager.getConnection(
    "jdbc:odbc:Payroll", "Doc", "1rover1");
7. 使用SQL从数据库中检索数据

在Java中,SQL语句由 Statement 对象表示。 Statement 是一个接口,不能直接实例化,但可以通过 Connection 对象的 createStatement() 方法返回,示例如下:

Statement lookSee = payday.createStatement();

获取 Statement 对象后,可以调用其 executeQuery(String) 方法执行SQL查询。例如,对 world20.mdb 数据库的 Coal 表执行以下查询:

ResultSet set = lookSee.executeQuery(
    "SELECT Country, Year, 'Anthracite Production' FROM Coal "
    + "WHERE (Country Is Not Null) ORDER BY Year");

如果SQL查询语法正确, executeQuery() 方法将返回一个 ResultSet 对象,其中包含从数据源检索到的所有记录。

ResultSet 对象提供了一系列方法来获取当前记录的信息,例如:
- getDate(String) :返回指定字段名称存储的日期值。
- getDouble(String) :返回指定字段名称存储的双精度浮点值。
- getFloat(String) :返回指定字段名称存储的单精度浮点值。
- getInt(String) :返回指定字段名称存储的整数值。
- getLong(String) :返回指定字段名称存储的长整数值。
- getString(String) :返回指定字段名称存储的字符串值。

也可以使用整数作为参数,例如 getString(5) 表示获取第5个字段的值。

当需要移动到下一条记录时,可以调用 ResultSet 对象的 next() 方法。该方法在尝试移动到结果集末尾之后时返回 false 。还可以使用其他方法在结果集中移动,如 afterLast() beforeFirst() first() last() previous()

以下是一个完整的示例代码 CoalTotals.java

import java.sql.*;

public class CoalTotals {
    public static void main(String[] arguments) {
        String data = "jdbc:odbc:WorldEnergy";
        try {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            Connection conn = DriverManager.getConnection(
                data, "", "");
            Statement st = conn.createStatement();
            ResultSet rec = st.executeQuery(
                "SELECT * " +
                "FROM Coal " +
                "WHERE " +
                "(Country='" + arguments[0] + "') " +
                "ORDER BY Year");
            System.out.println("FIPS\tCOUNTRY\t\tYEAR\t" +
                "ANTHRACITE PRODUCTION");
            while(rec.next()) {
                System.out.println(rec.getString(1) +  "\t"
                    + rec.getString(2) + "\t\t"
                    + rec.getString(3) + "\t"
                    + rec.getString(4));
            }
            st.close();
        } catch (SQLException s) {
            System.out.println("SQL Error: " + s.toString() + " "
                + s.getErrorCode() + " " + s.getSQLState());
        } catch (Exception e) {
            System.out.println("Error: " + e.toString()
                + e.getMessage());
        }
    }
}

该程序需要传入一个国家名称作为参数,用于从数据库中检索该国家的相关记录。

8. 使用SQL向数据库中写入数据

除了使用普通的SQL语句, java.sql 包还支持另一种创建SQL语句的方式:预编译语句( PreparedStatement )。预编译语句在执行前会进行编译,能够更快地返回数据,并且在同一程序中重复执行SQL语句时是更好的选择。

在Windows系统上,使用 PreparedStatement 还可以向Microsoft Access数据库写入数据。

创建预编译语句的步骤如下:
1. 调用 Connection 对象的 prepareStatement(String) 方法,传入一个表示SQL语句结构的字符串。在该字符串中,参数用问号表示,例如:

PreparedStatement ps = cc.prepareStatement(
    "SELECT * FROM Coal WHERE (Country='?') ORDER BY YEAR");
  1. 在执行语句之前,需要使用 PreparedStatement 类的方法为每个占位符填入数据。例如,将字符串“Swaziland”填入第一个占位符:
ps.setString(1, "Swaziland");

PreparedStatement 类提供了多种方法来设置不同类型的数据,例如:
- setAsciiStream(int, InputStream, int) :在指定位置插入一个表示ASCII字符流的输入流。
- setBinaryStream(int, InputStream, int) :在指定位置插入一个表示字节流的输入流。
- setCharacterStream(int, Reader, int) :在指定位置插入一个表示字符流的读取器。
- setBoolean(int, boolean) :在指定位置插入一个布尔值。
- setByte(int, byte) :在指定位置插入一个字节值。
- setBytes(int, byte[]) :在指定位置插入一个字节数组。
- setDate(int, Date) :在指定位置插入一个 java.sql 包中的 Date 对象。
- setDouble(int, double) :在指定位置插入一个双精度浮点值。
- setFloat(int, float) :在指定位置插入一个单精度浮点值。
- setInt(int, int) :在指定位置插入一个整数值。
- setLong(int, long) :在指定位置插入一个长整数值。
- setShort(int, short) :在指定位置插入一个短整数值。
- setString(int, String) :在指定位置插入一个字符串值。
- setNull(int, int) :在指定位置存储SQL的空值,第二个参数应是 java.sql 包中 Types 类的类变量,用于指示该位置应存储的SQL值类型。

以下是一个使用预编译语句向数据库中添加股票报价数据的示例 QuoteData.java

import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.*;

public class QuoteData {
    private String ticker;

    public QuoteData(String inTicker) {
        ticker = inTicker;
    }

    private String retrieveQuote() {
        StringBuffer buf = new StringBuffer();
        try {
            URL page = new URL("http://quote.yahoo.com/d/quotes.csv?s=" +
                ticker
                + "&f=sl1d1t1c1ohgv&e=.csv");
            String line;
            URLConnection conn = page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader(
                conn.getInputStream());
            BufferedReader data = new BufferedReader(in);
            while ((line = data.readLine()) != null) {
                buf.append(line + "\n");
            }
        } catch (MalformedURLException mue) {
            System.out.println("Bad URL: " + mue.getMessage());
        } catch (IOException ioe) {
            System.out.println("IO Error:" + ioe.getMessage());
        }
        return buf.toString();
    }

    private void storeQuote(String data) {
        StringTokenizer tokens = new StringTokenizer(data, ",");
        String[] fields = new String[9];
        for (int i = 0; i < fields.length; i++) {
            fields[i] = stripQuotes(tokens.nextToken());
        }
        String datasource = "jdbc:odbc:QuoteData";
        try {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            Connection conn = DriverManager.getConnection(
                datasource, "", "");
            PreparedStatement pstmt = conn.prepareStatement(
                "INSERT INTO Stocks VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
            pstmt.setString(1, fields[0]);
            pstmt.setString(2, fields[1]);
            pstmt.setString(3, fields[2]);
            pstmt.setString(4, fields[4]);
            pstmt.setString(5, fields[5]);
            pstmt.setString(6, fields[6]);
            pstmt.setString(7, fields[7]);
            pstmt.setString(8, fields[8]);
            pstmt.executeUpdate();
            conn.close();
        } catch (SQLException sqe) {
            System.out.println("SQL Error: " + sqe.getMessage());
        } catch (ClassNotFoundException cnfe) {
            System.out.println(cnfe.getMessage());
        }
    }

    private String stripQuotes(String input) {
        StringBuffer output = new StringBuffer();
        for (int i = 0; i < input.length(); i++) {
            if (input.charAt(i) != '\"') {
                output.append(input.charAt(i));
            }
        }
        return output.toString();
    }

    public static void main(String[] arguments) {
        if (arguments.length < 1) {
            System.out.println("Usage: java QuoteData tickerSymbol");
            System.exit(0);
        }
        QuoteData qd = new QuoteData(arguments[0]);
        String data = qd.retrieveQuote();
        qd.storeQuote(data);
    }
}

该程序从Yahoo!网站下载股票报价数据,并使用预编译语句将数据添加到数据库中。

9. 使用其他JDBC驱动程序

创建使用JDBC驱动程序的Java程序与使用JDBC - ODBC桥接的程序类似。首先需要获取并安装JDBC驱动程序,Sun没有在Java 2中包含JDBC驱动程序,但有多家公司出售或随商业产品提供驱动程序。可以在Sun的JDBC网站上找到可用的JDBC驱动程序列表。

例如,NetDirect的JDataConnect Server可以用于试验项目,可从http://www.j-netdirect.com/ 下载试用。另外,MySQL在2002年8月开始分发免费的开源JDBC驱动程序MySQL Connector/J,可从http://www.mysql.com/downloads/api-jdbc.html 下载。

设置JDBC数据源的步骤与JDBC - ODBC桥接类似:
1. 创建数据库。
2. 将数据库与JDBC驱动程序关联。
3. 建立数据源,可能需要选择数据库格式、数据库服务器、用户名和密码。

以下是一个使用JDataConnect JDBC驱动程序访问 People.mdb 数据库的示例 Presidents.java

import java.sql.*;

public class Presidents {
    public static void main(String[] arguments) {
        String data = "jdbc:JDataConnect://127.0.0.1/Presidents";
        try {
            Class.forName("JData2_0.sql.$Driver");
            Connection conn = DriverManager.getConnection(
                data, "", "");
            Statement st = conn.createStatement();
            ResultSet rec = st.executeQuery(
                "SELECT * FROM Contacts ORDER BY NAME");
            while(rec.next()) {
                System.out.println(rec.getString("NAME") +  "\n"
                    + rec.getString("ADDRESS1") + "\n"
                    + rec.getString("ADDRESS2") + "\n"
                    + rec.getString("PHONE") + "\n"
                    + rec.getString("E-MAIL") + "\n");
            }
            st.close();
        } catch (Exception e) {
            System.out.println("Error -- " + e.toString());
        }
    }
}

在运行该程序之前,需要确保JDataConnect Server已启动。该程序将从数据库中检索联系人信息并输出。

通过以上内容,我们学习了如何使用JDBC进行数据库的连接、数据的检索和写入,以及如何使用不同的驱动程序。这些知识将帮助我们在Java开发中更好地处理数据库操作。

Java数据库操作:从基础到实践

10. 操作流程总结

为了更清晰地展示使用JDBC进行数据库操作的流程,下面通过mermaid流程图和表格进行总结。

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B(选择驱动方式):::process
    B --> C{JDBC - ODBC桥接?}:::decision
    C -->|是| D(安装ODBC驱动):::process
    C -->|否| E(获取并安装JDBC驱动):::process
    D --> F(创建ODBC数据源):::process
    E --> G(关联数据库与驱动):::process
    F --> H(加载驱动类):::process
    G --> H
    H --> I(建立数据库连接):::process
    I --> J{操作类型?}:::decision
    J -->|查询| K(创建Statement或PreparedStatement):::process
    J -->|写入| K
    K --> L(执行SQL语句):::process
    L --> M(处理结果):::process
    M --> N(关闭连接):::process
    N --> O([结束]):::startend
步骤 操作内容 代码示例
1 选择驱动方式 -
2 安装驱动 JDBC - ODBC桥接:确保系统有ODBC驱动;其他JDBC驱动:从相应网站获取并安装
3 创建数据源 JDBC - ODBC桥接:使用ODBC数据源管理器创建;其他JDBC驱动:按驱动文档关联数据库与驱动
4 加载驱动类 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); (JDBC - ODBC桥接)
Class.forName("JData2_0.sql.$Driver"); (JDataConnect Server)
5 建立连接 Connection conn = DriverManager.getConnection("jdbc:odbc:数据源名", "用户名", "密码");
6 创建语句对象 Statement st = conn.createStatement();
PreparedStatement ps = conn.prepareStatement("SQL语句");
7 执行SQL语句 ResultSet rs = st.executeQuery("SELECT ...");
ps.executeUpdate();
8 处理结果 while(rs.next()) { ... }
9 关闭连接 conn.close();
11. 常见问题与注意事项

在使用JDBC进行数据库操作时,可能会遇到一些常见问题,以下是一些解决方法和注意事项:

  • 驱动加载问题
    • 问题描述 :使用 Class.forName() 方法加载驱动时,可能会抛出 ClassNotFoundException 异常。
    • 解决方法 :确保驱动类名正确,并且驱动类所在的JAR文件已添加到项目的类路径中。
    • 示例代码
try {
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException e) {
    System.out.println("驱动类未找到: " + e.getMessage());
}
  • SQL语法错误
    • 问题描述 :执行SQL语句时,可能会因为语法错误导致 SQLException 异常。
    • 解决方法 :仔细检查SQL语句的语法,确保符合数据库的要求。可以在数据库管理工具中先测试SQL语句。
    • 示例代码
try {
    Statement st = conn.createStatement();
    ResultSet rs = st.executeQuery("SELECT * FROM 表名 WHERE 条件");
} catch (SQLException e) {
    System.out.println("SQL执行错误: " + e.getMessage());
}
  • 数据类型不匹配
    • 问题描述 :在使用 PreparedStatement 设置参数时,可能会因为数据类型不匹配导致异常。
    • 解决方法 :确保使用正确的 setXxx() 方法设置参数,并且数据类型与数据库字段类型一致。
    • 示例代码
PreparedStatement ps = conn.prepareStatement("INSERT INTO 表名 (字段1, 字段2) VALUES (?, ?)");
ps.setString(1, "字符串值");
ps.setInt(2, 123);
  • 资源未关闭
    • 问题描述 :使用完 Connection Statement ResultSet 等资源后,如果没有及时关闭,可能会导致资源泄漏。
    • 解决方法 :在使用完资源后,调用相应的 close() 方法关闭资源。可以使用 try-with-resources 语句自动关闭资源。
    • 示例代码
try (Connection conn = DriverManager.getConnection("jdbc:odbc:数据源名", "用户名", "密码");
     Statement st = conn.createStatement();
     ResultSet rs = st.executeQuery("SELECT * FROM 表名")) {
    while (rs.next()) {
        // 处理结果
    }
} catch (SQLException e) {
    System.out.println("数据库操作错误: " + e.getMessage());
}
12. 总结与展望

通过本文的学习,我们全面了解了使用JDBC进行数据库操作的方法,包括使用JDBC - ODBC桥接和其他JDBC驱动程序,以及如何进行数据的检索和写入。掌握这些知识可以让我们在Java开发中更高效地处理数据库相关的任务。

随着技术的不断发展,数据库领域也在不断创新。未来,我们可以关注以下几个方面的发展:

  • 新的数据库技术 :如NoSQL数据库(MongoDB、Redis等),它们在处理大规模数据和高并发场景下具有独特的优势。
  • 数据库连接池技术 :可以提高数据库连接的性能和效率,减少频繁创建和销毁连接的开销。
  • 分布式数据库 :能够实现数据的分布式存储和处理,提高系统的可扩展性和容错性。

希望本文能够帮助你更好地掌握Java数据库操作,在实际开发中取得更好的效果。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值