JSP连接Access数据库:JDBC-ODBC桥配置、排坑与JDK 8迁移指南 简介面向JSP初学者的数据库连接实操文档以连接ACCESS数据库为例讲解JDBC的基础用法适合学习小型Web项目数据交互或复习JDBC-ODBC桥接技术的读者。文档完整覆盖从创建test.mdb数据库及username表含uid、pwd两个文本字段到将数据库文件部署至Tomcat的data目录再到编写JSP页面完成连接、查询并输出字段的全过程并附有可直接参考的示例代码和常见错误提示的排查方向。文中还详细说明了加载JDBC-ODBC桥驱动、构建连接字符串、通过Statement执行SQL以及关闭ResultSet、Statement、Connection释放资源等关键环节同时指出Access数据库更适用于小型项目或学习实践企业级开发中常转向MySQL、Oracle等关系型数据库有助于读者建立正确的技术选型认知。包体为单个doc文件大小31KB内容集中、便于按步骤对照练习。目前已有240人学习下载对想快速上手JSPACCESS数据读取的初学者具有较好的参考价值。1. JSP连接ACCESS数据库小项目够用但JDK 8起这条路就断了JSP连接ACCESS数据库看起来像是十年前课设里的老题目但直到今天我在接手内部小工具、竞赛原型代码时还会撞上它。这套方案的核心就三件事建一个test.mdb库和username表、把文件放进Tomcat的ROOT\data目录、通过JDBC-ODBC桥驱动连上再查数据。先说结论sun.jdbc.odbc.JdbcOdbcDriver这个桥驱动在JDK 8里已经被移除所以你要么在JDK 7及以下环境复现要么把这段代码当历史遗产来改造。适合谁想快速验证Web连接数据库流程的初学者以及被老项目困住的维护者。下面按建库、放文件、写代码、排坑的顺序把整条路走一遍。2. 建库与部署环境test.mdb、ROOT\data和驱动位数必须一致2.1 为什么是Access选型边界先看清Access能活到今天靠的不是性能而是零门槛。建一个mdb文件不需要单独装数据库服务双击Access就能建表插数据拷走一个文件整个数据库也跟着走。JSP这种服务端脚本配合Access适合几种场景校内实训、内部报表小站、演示原型以及用户量能数得过来的工具系统。一旦并发超过二三十个或者需要半夜跑批任务mdb的短板就完全暴露文件锁冲突、连接数上限低、没有日志和备份机制。这些边界不是劝退而是告诉你什么时候不要用。这里我为什么还要提它因为市面上大量存量代码就是这么写的。老版本教材示例、培训机构的快速Demo到现在依然有人在跑。理解这套代码的运行机制比直接否定它更有用。只要是学习JDBC流程或者处理老系统维护这个方案都值得拆开看一遍。2.2 建test.mdb和username表打开Access新建一个空数据库保存时注意文件类型选“Access 2002-2003格式.mdb”不要存成默认的.accdb。原因很简单ODBC驱动名里写的是Microsoft Access Driver (.mdb)桥驱动通过ODBC访问老格式最稳accdb虽然也能通过新版ACE驱动访问但那要额外装ACE驱动部署时更容易出幺蛾子。数据库建好后在表设计视图中新建表username两个字段按原文要求都设为文本型字段名类型字段大小说明uid文本50用户名pwd文本50密码建议顺手插入两三条测试数据不然select查出来是空表很难判断到底是连成功了还是查到了空结果。字段大小给50是经验值如果存长内容就在设计视图里改但JSP代码里rs.getString(uid)读取时不会受字段大小限制限制只影响Access端录入。这里有个常见翻车点建表时字段名打错比如写成user_name而不是uid运行时会报“Column not found”页面只显示字段名错误定位起来相对费劲。所以我一般直接复制下面的SQL到Access的查询设计里执行比手点界面靠谱CREATE TABLE username ( uid TEXT(50), pwd TEXT(50) ); INSERT INTO username (uid, pwd) VALUES (admin, 123456); INSERT INTO username (uid, pwd) VALUES (zhangsan, abc123);Access的查询向导支持直接跑这类SQL跑完表就建好了。注意TEXT(50)是Access的Jet SQL语法跟MySQL的VARCHAR不一样不要拿MySQL习惯去套。这段SQL的逻辑说明先建表再插入两条记录确保第3章执行select时至少有数据显示。2.3 数据库文件放哪getRealPath怎么找原文要求把test.mdb放到Tomcat安装目录下的webapps\ROOT\data文件夹更准确说是Tomcat安装目录\webapps\ROOT\data\test.mdb。webapps是Tomcat存放Web应用的根目录ROOT是默认应用访问http://localhost:8080/时直接命中它。data文件夹如果不存在就手动新建。为什么放在这里而不是随便放D盘因为代码里用的是application.getRealPath(spath)getRealPath会把“相对于当前Web应用根目录的路径”转换成服务器上的物理路径。JSP在ROOT下运行时spathdata/test.mdb结果就是Tomcat安装目录\webapps\ROOT\data\test.mdb。如果你把JSP放在某个子应用里比如webapps\myapp\demo.jsp那getRealPath对应的根目录就是webapps\myappdata也要放进myapp下这个对应关系是新手最容易搞混的。有个细节要注意Tomcat 6到Tomcat 9虽然在Servlet规范里仍保留getRealPath但从Tomcat 7起部分版本对未解压的WAR包或虚拟目录调用getRealPath会返回null或临时路径。如果你是用IDE直接部署、没走标准目录结构跑出null时不要慌先打印一句application.getRealPath(/)看看根路径到底指向哪。另外data目录必须有写权限。Access通过ODBC打开mdb时会在同目录创建.laccdb锁文件老格式是.ldb没有写权限就直接报“不能更新。数据库或对象为只读”。2.4 环境搭配JDK、Tomcat和驱动位数这套代码最挑剔的是环境组合。JDBC-ODBC桥驱动类名是sun.jdbc.odbc.JdbcOdbcDriver只有JDK 7及以下才有。JDK 8起JDBC-ODBC桥被官方移除Class.forName会直接抛ClassNotFoundException。如果你是学习目的最省事的做法是装一个JDK 7配Tomcat 6或7如果是维护老项目先确认服务器JDK版本再决定是改代码还是换环境。第二个环境坑是位数。ODBC管理器有32位和64位两套Microsoft Access Driver (*.mdb)这个驱动一般由Office提供常见的Office 32位安装只带32位驱动。如果Tomcat跑在64位JVM里调用的是64位ODBC就找不到32位驱动。反过来装64位Office后Tomcat却是32位JVM同样会失败。判断方法Windows下分别运行C:\Windows\SysWOW64\odbcad32.exe和C:\Windows\System32\odbcad32.exe查看两套驱动列表再看Tomcat启动日志确认JVM位数。总之JVM位数和Access驱动位数必须对齐这是很多“驱动明明装了却连不上”的根源。建库、放文件、环境组合这三件事定下来接下来进入代码拆解。3. 连接字符串与JSP代码拆解桥驱动、物理路径和资源关闭3.1 JDBC-ODBC桥是什么JDBC-ODBC桥是JDK早期提供的一个适配层它让Java程序通过JDBC API间接调用ODBC驱动再由ODBC去访问Access这类桌面数据库。对写代码的人来说整个过程是个黑匣子你只看到Class.forName一个类名后面其实经历了“JDBC调用→桥转换→ODBC调用→Jet/ACE引擎读取mdb”四层。这也是为什么这类连接出问题时报错信息经常含糊。加载驱动的原理很简单。Class.forName(sun.jdbc.odbc.JdbcOdbcDriver)会触发驱动类的静态初始化把JdbcOdbcDriver实例注册到java.sql.DriverManager里之后DriverManager.getConnection(url)才能识别jdbc:odbc:开头的URL。如果你的classpath里没有这个类forName这一行就会抛ClassNotFoundException后续代码根本不执行。这个异常在JDK 8以上环境几乎是必现的。顺带解释一个新手常问的为什么不直接连Access而要绕ODBC因为Access的Jet/ACE引擎没有提供原生JDBC驱动Java标准库只能走ODBC这座桥。后来UCanAccess这类纯Java驱动出现才把ODBC这一层省掉但那是后话。3.2 连接字符串拼法Driver和DBQ各管什么原文里的连接字符串是很多教程的标准写法String url jdbc:odbc:Driver{Microsoft Access Driver (*.mdb)};DBQ dbpath;这行代码用了DSN-less方式不提前在控制面板建数据源直接在连接串里指定驱动名和数据库路径。各参数说明如下参数值说明前缀jdbc:odbc:固定写法告诉DriverManager走JDBC-ODBC桥Driver{Microsoft Access Driver (*.mdb)}ODBC驱动显示名花括号不能省星号和空格也不能改DBQdbpathmdb文件的物理路径来自application.getRealPath()PWD可选Access数据库密码无密码时可省略有几个容易写错的地方。第一花括号内的驱动名必须和系统ODBC管理器里显示的名字完全一致少了星号、多打一个空格都会报“指定的驱动程序不存在”。第二DBQ后面接的是物理路径而不是JSP相对路径这就是为什么前面要先用getRealPath转换一次。第三参数之间用分号分隔最后一个参数后面不要加分号。如果你在Access里给数据库设了密码连接串要追加PWD参数例如String url jdbc:odbc:Driver{Microsoft Access Driver (*.mdb)};DBQ dbpath ;PWD123456;注意这跟“用户名密码”是两回事。Access数据库密码是文件级密码ODBC连接时用户名一般留空。原文代码里定义了dbname、user、password三个变量但都没被连接代码使用这种写法在新手代码里很常见实际是冗余的。真正要传的只有DBQ和可选的PWD。还有一种常见做法是预先在系统里建一个DSN数据源连接串简化为jdbc:odbc:test。这种方式在开发机上方便但换一台机器就要重新配置ODBC数据源部署麻烦DSN-less把所有信息都写在连接串里更适合代码分发和教学演示。3.3 完整JSP代码与执行流程说明把上面的铺垫合并成一份完整的JDBCAccess.jsp放在ROOT目录下和data目录同级浏览器直接访问http://localhost:8080/JDBCAccess.jsp就能跑% page contentTypetext/html; charsetgb2312 languagejava importjava.sql.* % meta http-equivContent-Type contenttext/html; charsetgb2312 % try { // 1. 数据库相对路径相对于当前Web应用的根目录 String spath data/test.mdb; // 2. 转成服务器物理路径 String dbpath application.getRealPath(spath); // 3. DSN-less连接串驱动名 数据库物理路径 String url jdbc:odbc:Driver{Microsoft Access Driver (*.mdb)};DBQ dbpath; // 4. 加载JDBC-ODBC桥驱动JDK 7及以下才存在 Class.forName(sun.jdbc.odbc.JdbcOdbcDriver); // 5. 建立连接 Connection conn DriverManager.getConnection(url); // 6. 创建语句对象 Statement stmt conn.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); // 7. 查询并遍历输出 String sql select * from username; ResultSet rs stmt.executeQuery(sql); while (rs.next()) { out.print(用户名: rs.getString(uid)); out.print( 密码: rs.getString(pwd) br); } out.print(br恭喜你数据库连接成功); // 8. 逆序关闭对象 rs.close(); stmt.close(); conn.close(); } catch (Exception e) { out.print(数据库连接错误,错误信息如下br); out.print(e.getMessage()); } %执行流程拆开看try块里第一步先把相对路径转成物理路径这是整个环节最容易出问题的地方第二步拼URL驱动名必须和ODBC管理器里一字不差第三步Class.forName加载桥驱动第四步建连接第五步建语句对象并执行查询最后While循环逐行读取uid和pwd并输出到页面。catch块只做了输出没有finally清理逻辑这是代码的隐患。两个参数说明。createStatement的两个参数第一个TYPE_SCROLL_SENSITIVE表示结果集要支持双向滚动第二个CONCUR_UPDATABLE表示结果集允许就地更新。这两项对Access的ODBC驱动来说要求偏高很多驱动只支持TYPE_FORWARD_ONLY和CONCUR_READ_ONLY如果你只是查数据展示建议改成Statement stmt conn.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);再补一个容易踩的页面显示“数据库连接错误”时catch里只打印了e.getMessage()信息经常被截断。实际排查时我会临时改成e.printStackTrace()把完整堆栈打到Tomcat的catalina.out或控制台定位是哪一层出的问题改完记得改回来。4. 常见问题排查五条踩坑记录从文件锁到中文乱码这段代码跑起来碰壁率不低。我把实战中最常遇到的五类问题按现象、原因、解决三要素列出来你可以对应自己的报错信息逐条对照。4.1 数据库文件被占用、出现.laccdb锁文件现象Tomcat运行中去修改或复制test.mdb时提示文件正在被另一个程序使用data目录下多出test.laccdb这样的锁文件删掉后还会再生成。原因Access引擎通过ODBC打开mdb时会在同目录创建锁文件用于记录当前连接。只要有一个连接没关闭锁文件就存在。如果JSP里conn.close()没执行异常时跳到了catchTomcat进程还占着连接文件就一直是锁定状态。解决把data目录放到Tomcat进程有写权限的位置改动数据库前先停止Tomcat长期使用后定期用Access打开数据库执行“压缩和修复数据库”这个操作能清掉残留锁并回收文件体积。另外确保rs、stmt、conn在finally里也有关闭逻辑只靠try结尾关闭异常情况下会漏。关于锁文件还有一点血泪经验不要在Tomcat运行中直接用Access的界面操作同一个mdb两边同时打开极易触发“文件正在使用中”的弹窗页面也连不上。4.2 ClassNotFoundException提示桥驱动不存在现象页面报java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver。原因JDK 8起官方移除了JDBC-ODBC桥。这行代码在JDK 8、JDK 11、JDK 17等新版本上必然翻车跟Tomcat版本无关。这个坑最坑的地方在于很多教程是十年前写的当年的JDK 6能用现在照着敲就炸。解决如果只是复现这个例子安装JDK 7并把Tomcat的JAVA_HOME指过去如果要新环境做正式开发放弃ODBC桥改用UCanAccess这种纯Java的Access驱动连接串变成jdbc:ucanaccess://...完全绕开ODBC层位数问题也一并消失。4.3 64位系统下提示驱动不存在但这驱动明明装了现象控制面板的ODBC数据源管理器里能看到Microsoft Access Driver (*.mdb)但Tomcat里运行代码报“指定的驱动程序不存在”或者找不到数据源。原因位数不一致。Windows上有两套ODBC管理器32位和64位。常见的Office是32位装法只带32位Access驱动如果Tomcat跑在64位JVM里它会去加载64位ODBC自然找不到32位驱动。反过来装64位OfficeTomcat却是32位JVM同样失败。这种问题最玄学因为你在图形界面看驱动明明存在代码却告诉你没有。解决先确认Tomcat的JVM位数。Windows任务管理器里看进程名带不带“*32”或者看java -version输出。然后分别打开C:\Windows\SysWOW64\odbcad32.exe和C:\Windows\System32\odbcad32.exe确认对应的驱动列表。要做的就是让两边对上要么把Tomcat换成32位版配32位Office要么装64位Office配64位Tomcat。4.4 中文乱码和中文查询条件失败现象页面输出“用户名:?? 密码:??”或者执行select where uid张三返回空结果数据明明在表里。原因编码不一致。JSP页面声明charsetgb2312浏览器按GBK解码Tomcat老版本默认URI编码是ISO-8859-1如果JSP文件名或路径里有中文getRealPath拿到的路径就会乱Access表里数据按Unicode存储输出时再经过gb2312转码多环节不一致表现就是乱码。解决新页面统一用UTF-8把contentType改为charsetUTF-8Tomcat老版本连接器加URIEncodingUTF-8测试数据用Access界面正常录入不要用命令行工具乱灌。至于中文条件查询最稳的写法是参数化查询把值通过setString传进去而不是拼接SQL字符串这样既解决编码也避免注入。4.5 getRealPath返回null页面直接报空指针现象application.getRealPath(data/test.mdb)返回nullDBQ拼出来是“null”连接失败。原因应用不是以解压目录的形式部署。比如IDE里以exploded方式部署到临时目录、或者部署的是WAR且Tomcat没有解压该应用getRealPath在这种情况下可能拿不到物理路径。另外路径如果以/开头也会影响结果。解决先打印application.getRealPath(/)看Web应用根路径的值确认JSP和data目录的相对位置如果确实拿不到把mdb路径配置到.properties文件里再读。提醒一句Tomcat 7以后的Servlet规范里getRealPath已经标注为deprecated新改造的代码建议用ServletContext.getResource或把文件放到类路径下通过ClassLoader读取。五条问题排查下来有个共性几乎都是环境问题而不是SQL问题。接下来把这段一次性连接代码往前推一步。5. 往前走一步参数化查询与连接复用跑通上面的例子只是起点。这段代码放在学习场景没问题但它是典型的“一次请求一次连接”模型每次访问JSP都重新Class.forName、重新建连接、用完就扔。Access本身并发弱这种写法在多人同时访问时会造成大量连接竞争页面变慢、锁文件频繁出现。我一般会把改造分成两步不引入复杂框架也能见效。第一步把SQL从拼接改成参数化。上面代码里select * from username没有任何外部输入看不出问题一旦改成where uid request.getParameter(uid) 注入和编码问题就全来了。改成PreparedStatementString sql select * from username where uid?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, request.getParameter(uid)); ResultSet rs ps.executeQuery();setString把第一个问号替换成请求参数值参数化后既避免SQL拼接的注入风险也让中文参数按连接串的字符集统一处理比手工加引号和转义省心得多。第二步把连接参数抽到一个统一的常量类或properties文件里避免每次改路径都要翻JSP。如果再往前一步用一个简单的连接池或者至少把连接复用逻辑封装到工具类整个工程就好维护多了。不过使用连接池时要注意Access的ODBC驱动对连接池化的支持并不完善JDBC-ODBC桥本身也没有实现标准的PooledConnection某些池化实现会导致连接失效后无法自动恢复所以我通常会加一个连接有效性检测再复用。以这套代码为例我的建议改法是仍然保留JDBC-ODBC桥代码作为学习参照但真实项目一律用UCanAccess或者直接迁移到MySQL。从那以后我每次做数据库相关的老项目改造都强制先走一遍“驱动版本、位数、编码、物理路径”四查再动手改代码少踩了不少冤枉路。希望帮到你。本文还有配套的精品资源点击获取