news 2026/10/10 3:34:17

JSP连接ACCESS数据库实战:UCanAccess与JDBC-ODBC选型及避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JSP连接ACCESS数据库实战:UCanAccess与JDBC-ODBC选型及避坑指南

简介:这份资源面向JSP初学者与Web开发入门者,聚焦小型项目或教学实践中JSP与ACCESS数据库的基础数据交互问题。包内共1个doc文档,约31KB,以图文与代码示例讲解如何创建test.mdb数据库及username表,将数据库文件放入Tomcat指定目录,并编写JDBCAccess.jsp完成连接与数据读取。内容涵盖JDBC-ODBC桥驱动加载、连接字符串拼接、Statement与ResultSet使用,以及资源关闭等关键环节,同时提示ACCESS在企业级应用中的局限,并对比MySQL、Oracle等数据库的连接差异。已有239人学习,适合希望理解JDBC原理、快速跑通JSP访问ACCESS流程的读者参考。

1. JSP 连接 ACCESS 数据库:为什么老项目还在用,新项目要不要碰

接手一个 2010 年前后的内部管理系统,服务器上跑着 Tomcat 6,数据库是一个.mdb文件,需求是加一个「设备借用登记」页面。你打开项目一看,数据源配置里写着jdbc:odbc:driver={Microsoft Access Driver (*.mdb)},连密码都没有。这就是 JSP 连接 ACCESS 数据库最典型的场景——不是因为它好,而是因为它已经在那儿了。

ACCESS 是文件型数据库,单文件、零服务、拷走就能跑,适合单机或极小并发(个位数同时在线)的内部工具。JSP 作为服务端页面技术,通过 JDBC-ODBC 桥或 UCanAccess 纯 Java 驱动读写.mdb/.accdb。这套组合能解决「不想装 MySQL、不想配服务、只想快速出增删改查页面」的问题,适合维护老系统、做课程设计、写小型内部登记工具的人。不适合高并发、多用户写入、需要事务隔离的生产系统——这一点必须先说清楚,否则后面全是坑。

2. 两条连接路线:JDBC-ODBC 桥与 UCanAccess 怎么选

2.1 先搞清楚 ACCESS 驱动在 JDK 里的命运

JDK 8 之前,sun.jdbc.odbc.JdbcOdbcDriver是内置的,写一行Class.forName("sun.jdbc.odbc.JdbcOdbcDriver")就能连。JDK 8 开始这个桥被标记废弃,JDK 11 之后彻底移除。所以如果你现在用 JDK 8 以上,JDBC-ODBC 桥这条路基本走不通,除非你手动把rt.jar里的相关类抽出来——不推荐,维护成本高。

常见做法是改用 UCanAccess,这是一个纯 Java 的 ACCESS 驱动,底层用 Jackcess 库直接读.mdb/.accdb文件,不依赖操作系统的 ODBC 数据源。它支持 JDK 8 到 JDK 17,Maven 坐标是net.sf.ucanaccess:ucanaccess。选它的理由很直接:跨平台、不装驱动、不配 DSN、代码里写 JDBC URL 就能跑。

如果你维护的是 JDK 6/7 的老项目,且服务器是 Windows,那 JDBC-ODBC 桥还能用,配置 ODBC 数据源反而更省事——因为老代码里可能已经写死了jdbc:odbc:xxx。两条路线的对比如下:

对比项JDBC-ODBC 桥UCanAccess
依赖系统 ODBC 数据源 + JDK 内置桥纯 Java jar 包
JDK 支持JDK 8 以下JDK 8 及以上
跨平台仅 Windows全平台
部署复杂度需在服务器配 DSN拷 jar 即可
并发能力差差(本质一样)
推荐场景维护 JDK 7 老项目新写或升级项目

2.2 UCanAccess 的最小可运行配置

先加依赖。Maven 项目在pom.xml里写:

<dependency> <groupId>net.sf.ucanaccess</groupId> <artifactId>ucanaccess</artifactId> <version>5.0.1</version> </dependency>

如果你不用 Maven,需要手动下载这几个 jar 放进WEB-INF/lib:ucanaccess、jackcess、commons-lang3、commons-logging、hsqldb。少一个都会在运行时报ClassNotFoundException,这是血泪经验。

然后写一个连接工具类:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class AccessConn { // ACCESS 文件放在 WEB-INF/db 下,避免被直接下载 private static final String DB_PATH = "D:/project/webapp/WEB-INF/db/device.mdb"; private static final String URL = "jdbc:ucanaccess://" + DB_PATH + ";memory=false"; public static Connection getConnection() throws SQLException { try { Class.forName("net.ucanaccess.jdbc.UcanaccessDriver"); } catch (ClassNotFoundException e) { throw new SQLException("UCanAccess 驱动未找到", e); } return DriverManager.getConnection(URL); } }

逻辑说明:jdbc:ucanaccess://后面跟绝对路径,memory=false表示不把整个库加载进内存——对于几十 MB 的.mdb,设true会快一点,但内存占用高;设false每次读磁盘,适合文件不大但内存紧张的场景。参数DB_PATH必须用绝对路径,相对路径在 Tomcat 里会相对于bin目录,不是你的项目目录,这是新手最容易翻车的地方。

2.3 JDBC-ODBC 桥的配置步骤(仅限 JDK 7 及以下)

如果你确实在老环境里,步骤是:控制面板 → 管理工具 → ODBC 数据源(32 位)→ 系统 DSN → 添加 → 选Microsoft Access Driver (*.mdb)→ 填数据源名(比如devdb)→ 选文件。然后 Java 代码里:

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection conn = DriverManager.getConnection("jdbc:odbc:devdb", "", "");

注意 Tomcat 如果是 64 位,ODBC 数据源也必须配 64 位的,否则报[Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序。这个报错我见过太多次,原因就是 32 位 DSN 配了 64 位 Tomcat。

3. 在 JSP 里写增删改查:从建表到分页展示

3.1 建表与字段类型映射

ACCESS 的字段类型和 Java 类型对应关系要心里有数,否则getObject会给你惊喜:

ACCESS 类型Java 读取方式注意
文本(短文本)rs.getString()长度默认 255
备注(长文本)rs.getString()可能返回null
数字(长整型)rs.getLong()自增主键用这个
日期/时间rs.getTimestamp()格式敏感
是/否rs.getBoolean()ACCESS 里存 -1/0
OLE 对象rs.getBytes()存图片用,不推荐

建表可以在 ACCESS 界面里手动建,也可以用 SQL 在 JSP 里建。手动建更稳,因为 UCanAccess 对CREATE TABLE的语法支持有限,比如AUTOINCREMENT关键字有时不认。我一般建议在 ACCESS 里建好表,JSP 只做增删改查。

3.2 查询与分页的 JSP 片段

下面是一个设备列表分页查询的 JSP 核心代码:

<%@ page import="java.sql.*, com.example.AccessConn" %> <% int pageSize = 10; int pageNo = 1; String p = request.getParameter("page"); if (p != null) pageNo = Integer.parseInt(p); int offset = (pageNo - 1) * pageSize; String sql = "SELECT id, name, status FROM device ORDER BY id DESC"; Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = AccessConn.getConnection(); // ACCESS 不支持 LIMIT OFFSET,用绝对定位模拟 ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); rs = ps.executeQuery(); rs.absolute(offset + 1); // 定位到本页第一条 int count = 0; while (rs.next() && count < pageSize) { count++; %> <tr> <td><%= rs.getLong("id") %></td> <td><%= rs.getString("name") %></td> <td><%= rs.getInt("status") == 1 ? "在用" : "停用" %></td> </tr> <% } } catch (Exception e) { out.println("查询失败:" + e.getMessage()); } finally { if (rs != null) rs.close(); if (ps != null) ps.close(); if (conn != null) conn.close(); } %>

逻辑说明:ACCESS 的 SQL 方言不支持LIMIT和OFFSET,所以分页要用ResultSet的滚动游标。TYPE_SCROLL_INSENSITIVE允许absolute()定位,CONCUR_READ_ONLY减少锁开销。rs.absolute(offset + 1)把游标移到本页第一条,然后循环取pageSize条。参数pageSize建议不超过 20,因为 ACCESS 文件锁在并发读时表现很差,一次取太多会拖慢响应。

3.3 插入、更新、删除的写法与事务

增删改都用PreparedStatement,不要拼字符串,否则单引号就能让你的页面崩掉:

public static int addDevice(String name, int status) throws SQLException { String sql = "INSERT INTO device (name, status) VALUES (?, ?)"; try (Connection conn = AccessConn.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, name); ps.setInt(2, status); return ps.executeUpdate(); } }

更新和删除同理,把 SQL 换成UPDATE device SET name=? WHERE id=?或DELETE FROM device WHERE id=?。注意 ACCESS 的executeUpdate返回受影响行数,但有时因为文件锁会返回 0 而不报错,所以业务层要再查一次确认。

事务方面,ACCESS 支持conn.setAutoCommit(false)和commit(),但并发写入时容易死锁。我的做法是:单条增删改不显式开事务,靠自动提交;批量操作才开事务,且加conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED)。即便如此,两个用户同时写同一个.mdb仍可能报Could not update; currently locked,这是 ACCESS 的硬限制,不是代码问题。

4. 避坑与排查:ACCESS 连接最常见的 5 个翻车现场

4.1 报错[Microsoft][ODBC 驱动程序管理器] 未发现数据源名称

现象:JSP 页面抛出这个异常,堆栈指向DriverManager.getConnection。

原因:ODBC 数据源没配,或者配的位数和 Tomcat 不一致。32 位 DSN 在 64 位 JVM 里不可见,反之亦然。

解决:确认 Tomcat 的位数(java -version看 64-Bit 字样),然后去C:\Windows\SysWOW64\odbcad32.exe(32 位)或C:\Windows\System32\odbcad32.exe(64 位)配对应的系统 DSN。配完重启 Tomcat。

4.2 报错UCanAccessDriver not found

现象:Maven 依赖加了,但运行时报ClassNotFoundException: net.ucanaccess.jdbc.UcanaccessDriver。

原因:UCanAccess 依赖链没打全,缺jackcess或hsqldb。Maven 有时因为仓库问题只下了主包。

解决:在pom.xml里显式加jackcess和hsqldb依赖,或者用mvn dependency:copy-dependencies把所有传递依赖拷到WEB-INF/lib。检查WEB-INF/lib下至少有 5 个相关 jar。

4.3 报错Could not update; currently locked

现象:多人同时操作时,插入或更新失败,提示文件被锁。

原因:ACCESS 是文件锁,一个写操作会锁整个文件,其他写操作排队或直接失败。

解决:把memory=false改成memory=true让 UCanAccess 用内存副本,减少文件锁时间;或者用conn.setAutoCommit(true)尽快释放锁。根本方案是换数据库,如果并发超过 5 个人,ACCESS 就不该继续用。

4.4 中文乱码

现象:JSP 页面显示的中文变成???或乱码。

原因:ACCESS 文件本身编码、JDBC URL 没指定字符集、JSP 页面pageEncoding不一致。

解决:JSP 顶部写<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>;UCanAccess 的 URL 加;charSet=UTF-8;ACCESS 建表时字段用「短文本」而不是「备注」,备注字段在某些驱动版本下编码处理有问题。

4.5 日期格式写入失败

现象:ps.setTimestamp()写入 ACCESS 日期字段时报Data type mismatch。

原因:ACCESS 的日期字段对格式敏感,java.sql.Timestamp在某些驱动版本下不被识别。

解决:改用ps.setString()传yyyy-MM-dd HH:mm:ss格式的字符串,ACCESS 会自动转换。或者用ps.setObject()传java.util.Date,让驱动自己处理。我一般用字符串,最稳。

5. 进阶技巧:用连接池和只读模式把 ACCESS 压榨到极限

ACCESS 本身不支持连接池,但你可以用 DBCP 或 HikariCP 包一层,减少频繁打开文件的开销。配置 HikariCP 的maximumPoolSize设 3 到 5,connectionTimeout设 3000 毫秒,idleTimeout设 60000。超过 5 个连接反而会因为文件锁互相等待,性能下降。

另一个技巧是只读模式。如果页面只做展示,UCanAccess 的 URL 加;readonly=true,这样多个请求可以同时读,不会互相锁。写操作单独走一个连接,读写分离在 ACCESS 层面也能凑合实现。

验证方法:用 JMeter 开 10 个线程循环请求列表页,观察响应时间。如果平均超过 500 毫秒,说明文件锁在拖后腿,这时候要么加缓存(把查询结果放application作用域,定时刷新),要么换 SQLite——SQLite 的并发读比 ACCESS 好,迁移成本也不高。

我自己的习惯是:新项目一律不选 ACCESS,老项目维护时先确认 JDK 版本,JDK 8 以上直接上 UCanAccess,JDK 7 以下才考虑 ODBC 桥。每次改完连接代码,先在本机用main方法跑一遍增删改查,再部署到 Tomcat,能省掉一半的调试时间。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 3:34:02

JUnit 5自定义@ClassTemplate:基于@TestTemplate扩展机制实现多环境测试

先说结论&#xff1a;JUnit 5 官方并没有内置ClassTemplate这个注解。你在 IDE 里敲一个ClassTemplate&#xff0c;编译器会直接标红。但很多项目确实在这么写——准确说&#xff0c;大家叫的“类模板”&#xff0c;底层其实是TestTemplateTestTemplateInvocationContextProvid…

作者头像 李华
网站建设 2026/10/10 3:33:39

形式语言与自动机理论试题解析:从死记硬背到独立推导

简介&#xff1a;这份文档面向计算机专业学生与考研备考者&#xff0c;针对形式语言与自动机理论课程中的习题与考试难点&#xff0c;提供系统的试题答案解析。内容覆盖集合幂集计算、文法构造、DFA设计、语言识别、形式语言分类、语言推导及泵引理证明等核心知识点&#xff0c…

作者头像 李华
网站建设 2026/10/10 3:32:56

SpringBoot3+MyBatis-Plus快速搭建CRUD工程:版本升级与配置避坑实践

先说明一个现实问题&#xff1a;五分钟只是一个理想化目标&#xff0c;真正卡时间的地方往往不是创建项目&#xff0c;而是版本不对、依赖冲突、扫描路径漏配这三个深坑。我自己是从 SpringBoot2 升级上来的&#xff0c;当时被 javax 换 jakarta 的改动坑了一整个下午&…

作者头像 李华
网站建设 2026/10/10 3:32:50

FFmpeg+Nginx+SSM搭建RTSP转HLS网页直播系统实战

简介&#xff1a;这套以SSM架构整合Nginx与FFmpeg的流媒体方案&#xff0c;专门面向需要将RTSP实时流转为HLS并在网页上播放的开发者&#xff0c;尤其适合刚接触视频接入的小白和希望快速预览实时画面的朋友。压缩包共52个文件&#xff0c;约70.26MB&#xff0c;涵盖png界面图、…

作者头像 李华
网站建设 2026/10/10 3:32:47

栈:从数据结构到全栈开发的思维暗号

栈这东西&#xff0c;是我跟同行聊天时几乎绕不开的话题。数据结构课上说“Stack栈”是最基础的容器之一&#xff0c;算法竞赛里单调栈和表达式求值常年出镜&#xff0c;线上服务崩了抓调用栈&#xff08;backtrace&#xff09;定位问题&#xff0c;聊全栈开发时“技术栈”三个…

作者头像 李华