准备工作
在开始编码之前,你需要确保以下几点:

1 准备 Access 数据库文件
-
创建一个 Access 数据库,你可以使用 Microsoft Access 软件来创建。
-
在数据库中创建一张表,我们创建一个名为
students的表,包含id,name,age三个字段。 -
向表中插入一些示例数据。
students表结构: | 字段名 | 数据类型 | 说明 | | :--- | :--- | :--- | |id| 自动编号 (AutoNumber) | 主键 | |name| 短文本 (Text) | 学生姓名 | |age| 数字 (Number) | 学生年龄 |
(图片来源网络,侵删)示例数据: | id | name | age | | :--- | :--- | :--- | | 1 | 张三 | 20 | | 2 | 李四 | 21 | | 3 | 王五 | 22 |
假设我们将这个数据库文件保存在 D:\database\mydb.accdb。
2 下载 Access 数据库驱动
Java 通过 JDBC (Java Database Connectivity) 来连接数据库,Access 数据库需要一个 JDBC 驱动程序。
-
对于较新的 Access 2007 及以上版本 (
.accdb文件):
(图片来源网络,侵删)- 你需要 UCanAccess 驱动,这是一个开源的、纯 Java 的 JDBC 驱动,是目前连接
.accdb文件的最佳选择。 - 下载地址: https://github.com/UCanAccess/UCanAccess
- 下载最新版本的发布包(
UCanAccess-5.0.4-bin.zip),解压后,你会得到一个包含多个.jar文件的文件夹。
- 你需要 UCanAccess 驱动,这是一个开源的、纯 Java 的 JDBC 驱动,是目前连接
-
对于较旧的 Access 2003 及以下版本 (
.mdb文件):- 你需要 Microsoft Access Database Engine,这个驱动包含本地库(不是纯 Java),因此你的 Java 应用程序在运行时需要访问这些本地库。
- 下载地址: https://www.microsoft.com/en-us/download/details.aspx?id=54920
- 注意: 32位和64位的驱动不同,请根据你的 Java 运行环境 和操作系统 选择正确的版本,如果出现
java.lang.UnsatisfiedLinkError错误,通常就是驱动位数不匹配导致的。
3 配置项目依赖
将下载的驱动库文件添加到你的项目中。
-
如果你使用 Maven (推荐): UCanAccess 可以通过 Maven 中央仓库获取,这是最简单的方式,在
pom.xml中添加以下依赖:<dependencies> <!-- UCanAccess JDBC Driver for Access .accdb files --> <dependency> <groupId>com.github.u-can-access</groupId> <artifactId>ucanaccess</artifactId> <version>5.0.4</version> <!-- 使用最新版本 --> </dependency> </dependencies> -
如果你手动管理 JAR 文件:
- 将 UCanAccess 解压包中的 所有
.jar文件(如ucanaccess-5.0.4.jar,hsqldb.jar,jackcess-5.0.4.jar等)添加到你的项目的类路径(Classpath)中。 - 如果你使用的是旧版的
.mdb驱动,通常只需要msaccess.jar或jdbcodbc.jar(如果使用 JDBC-ODBC 桥接)。
- 将 UCanAccess 解压包中的 所有
Java 代码示例
下面是使用 UCanAccess 连接 .accdb 文件并执行基本操作的完整代码。
1 数据库连接 URL 格式
UCanAccess 的连接 URL 有固定的格式:
jdbc:ucanaccess://<数据库文件的完整路径>
<数据库文件的完整路径>:指向你的.accdb或.mdb文件的绝对路径。
2 完整代码示例
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class AccessDBExample {
// 数据库文件路径 - 请务必修改为你自己的路径
private static final String DB_URL = "jdbc:ucanaccess://D:/database/mydb.accdb";
public static void main(String[] args) {
// try-with-resources 语句,确保连接、语句和结果集在使用后被自动关闭
try (Connection conn = DriverManager.getConnection(DB_URL);
Statement stmt = conn.createStatement()) {
System.out.println("成功连接到 Access 数据库!");
// 1. 查询数据
System.out.println("\n--- 查询所有学生信息 ---");
queryStudents(stmt);
// 2. 插入数据
System.out.println("\n--- 插入一条新学生记录 ---");
insertStudent(stmt, "赵六", 23);
// 再次查询以验证插入
queryStudents(stmt);
// 3. 更新数据
System.out.println("\n--- 更新学生信息 (将李四的年龄改为 22) ---");
updateStudentAge(stmt, "李四", 22);
queryStudents(stmt);
// 4. 删除数据
System.out.println("\n--- 删除学生信息 (删除王五) ---");
deleteStudent(stmt, "王五");
queryStudents(stmt);
} catch (SQLException e) {
System.err.println("数据库操作出错: " + e.getMessage());
e.printStackTrace();
}
}
// 查询学生信息
private static void queryStudents(Statement stmt) throws SQLException {
String sql = "SELECT id, name, age FROM students";
try (ResultSet rs = stmt.executeQuery(sql)) {
System.out.println("ID\t姓名\t年龄");
System.out.println("--------------------");
while (rs.next()) {
// 通过列名获取数据,可读性更好,且与列的顺序无关
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println(id + "\t" + name + "\t" + age);
}
}
}
// 插入学生信息
private static void insertStudent(Statement stmt, String name, int age) throws SQLException {
// 注意:对于自动编号字段,不需要在SQL中指定
String sql = String.format("INSERT INTO students (name, age) VALUES ('%s', %d)", name, age);
int affectedRows = stmt.executeUpdate(sql);
if (affectedRows > 0) {
System.out.println("成功插入 " + affectedRows + " 行数据。");
} else {
System.out.println("插入数据失败。");
}
}
// 更新学生年龄
private static void updateStudentAge(Statement stmt, String name, int newAge) throws SQLException {
String sql = String.format("UPDATE students SET age = %d WHERE name = '%s'", newAge, name);
int affectedRows = stmt.executeUpdate(sql);
if (affectedRows > 0) {
System.out.println("成功更新 " + affectedRows + " 行数据。");
} else {
System.out.println("未找到名为 " + name + " 的学生,更新失败。");
}
}
// 删除学生信息
private static void deleteStudent(Statement stmt, String name) throws SQLException {
String sql = String.format("DELETE FROM students WHERE name = '%s'", name);
int affectedRows = stmt.executeUpdate(sql);
if (affectedRows > 0) {
System.out.println("成功删除 " + affectedRows + " 行数据。");
} else {
System.out.println("未找到名为 " + name + " 的学生,删除失败。");
}
}
}
重要注意事项和最佳实践
1 SQL 注入风险
上面的示例中,我们使用了 String.format 来拼接 SQL 语句,这种方式极易受到 SQL 注入攻击,如果 name 参数是 ' OR '1'='1,那么查询语句就变成了 SELECT * FROM students WHERE name = '' OR '1'='1',会返回所有记录。
正确做法是使用 PreparedStatement:
// 安全的插入方法示例
private static void safeInsertStudent(Connection conn, String name, int age) throws SQLException {
String sql = "INSERT INTO students (name, age) VALUES (?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, name);
pstmt.setInt(2, age);
int affectedRows = pstmt.executeUpdate();
System.out.println("安全插入 " + affectedRows + " 行数据。");
}
}
PreparedStatement 会对输入参数进行转义,从根本上防止 SQL 注入。
2 资源管理
数据库连接(Connection)、语句(Statement/PreparedStatement)和结果集(ResultSet)都是需要系统资源的重要对象,使用完毕后必须关闭它们。
- 传统方式: 在
finally块中手动关闭。 - 推荐方式: 使用
try-with-resources语句(如示例代码所示),它会自动在try块执行完毕后调用这些对象的close()方法,代码更简洁、安全。
3 数据库文件锁定
Access 是一个文件数据库,当你的 Java 程序连接到它时,数据库文件会被锁定,这意味着:
- 不能同时用 Access 软件和你的 Java 程序打开同一个数据库文件,否则会抛出错误。
- 如果程序异常终止,可能会导致数据库文件处于锁定状态,下次连接时会失败,通常需要手动删除同目录下的
.laccdb锁定文件。
4 性能考虑
Access 数据库不适合高并发的场景,如果你的应用需要同时处理大量请求,请考虑使用客户端-服务器模式的数据库,如 MySQL, PostgreSQL, SQL Server 等。
常见问题 (FAQ)
Q1: 运行时出现 ClassNotFoundException 错误。
原因: JVM 找不到 JDBC 驱动的类。 解决方案:
- 确保你已经下载了正确的驱动 JAR 文件。
- 确保你已经将这些 JAR 文件正确地添加到了项目的类路径中,如果你使用 IDE(如 IntelliJ IDEA 或 Eclipse),请检查项目的库配置。
Q2: 运行时出现 java.lang.UnsatisfiedLinkError 错误。
原因: 这个错误在使用旧版 Access 驱动(非纯 Java)时非常常见,它表示 Java 无法加载本地库(如 .dll 文件)。
解决方案:
- 首选方案: 切换到 UCanAccess,它是纯 Java 的,没有这个问题。
- 如果必须使用旧版驱动,请确保:
- 你的 Java 运行环境(JRE)的位数(32位或64位)与 Access Database Engine 的位数完全一致。
- 本地库文件(如
.dll)所在的路径在系统的PATH环境变量中,或者 Java 的java.library.path中。
Q3: 连接字符串写错了,或者数据库文件路径不对。
原因: DB_URL 中的路径不正确。
解决方案:
- 检查路径是否是绝对路径(从盘符开始的完整路径)。
- 确保路径中的分隔符是正确的,在 Java 字符串中,Windows 路径的反斜杠
\是一个转义字符,所以需要写成D:\\database\\mydb.accdb或者使用正斜杠D:/database/mydb.accdb,后者在 Windows 和 Java 中都能正常工作,推荐使用。
希望这份详细的指南能帮助你成功地在 Java 中连接和使用 Access 数据库!
