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");
-
建立连接
:使用
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");
-
在执行语句之前,需要使用
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语句。
- 示例代码 :
-
问题描述
:执行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数据库操作,在实际开发中取得更好的效果。
Java数据库操作:JDBC从基础到实践
超级会员免费看

被折叠的 条评论
为什么被折叠?



