SpringBoot解析.mdb文件实战指南

简介: 本文介绍如何在SpringBoot项目中解析旧版Microsoft Access的.mdb文件。通过UCanAccess开源库,无需安装Access或ODBC驱动,即可实现跨平台数据读取。文中提供完整的Maven依赖配置、核心工具类封装及使用示例,帮助开发者快速完成遗留系统数据迁移。该方法尤其适合临时数据提取任务,为处理历史数据库提供便捷的Java解决方案。

文章简介:本文介绍如何在SpringBoot项目中解析旧版Microsoft Access的.mdb文件。通过UCanAccess开源库,无需安装Access或ODBC驱动,即可实现跨平台数据读取。文中提供完整的Maven依赖配置、核心工具类封装及使用示例,帮助开发者快速完成遗留系统数据迁移。该方法尤其适合临时数据提取任务,为处理历史数据库提供便捷的Java解决方案。

最近在做一个数据迁移项目,需要从老旧的.mdb(Microsoft Access)文件中提取数据。虽然Access数据库现在用得不多,但在一些遗留系统中还能见到。网上查了一圈,发现UCanAccess这个神器,结合AI的帮助,很快就完成了需求开发。
以下是UCanAccess的文档地址http://ucanaccess.sourceforge.net/site.html

🚀 快速开始

1️⃣ 引入Maven依赖

首先,我们需要在pom.xml中添加UCanAccess的依赖:

<!-- 添加UCanAccess依赖 -->
<dependency>
    <groupId>net.sf.ucanaccess</groupId>
    <artifactId>ucanaccess</artifactId>
    <version>5.0.1</version>
</dependency>

2️⃣ 核心工具类实现

下面是我封装的MdbJdbcUtil.java工具类,可以直接复制使用:

import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class MdbJdbcUtil {
   
    private static final String DRIVER_CLASS = "net.ucanaccess.jdbc.UcanaccessDriver";
    private static final String URL_PREFIX = "jdbc:ucanaccess://";
    private static final String URL_MEMORY = ";memory=false";

    /**
     * 私有构造方法,防止实例化
     */
    private MdbJdbcUtil() {
   
        throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
    }
    /**
     * 静态初始化块,加载数据库驱动
     */
    static {
   
        try {
   
            Class.forName(DRIVER_CLASS);
        } catch (ClassNotFoundException e) {
   
            throw new RuntimeException("Failed to load UCanAccess JDBC driver", e);
        }
    }

    /**
     * 创建数据库连接
     *
     * @param mdbPath MDB文件路径
     * @return 数据库连接
     * @throws SQLException 如果连接失败
     */
    public static Connection getConnection(String mdbPath) throws SQLException {
   
        if (mdbPath == null || mdbPath.trim().isEmpty()) {
   
            throw new IllegalArgumentException("MDB file path cannot be null or empty");
        }

        Properties props = new Properties();
        props.put("charSet", "UTF-8");

        String dbUrl = URL_PREFIX + mdbPath + URL_MEMORY;
        return DriverManager.getConnection(dbUrl, props);
    }
    /**
     * 执行带参数的查询并返回List<Map<String, Object>>结果
     *
     * @param mdbPath MDB文件路径
     * @param sql SQL查询语句
     * @param params 查询参数列表
     * @return 查询结果列表,每个Map代表一行数据
     * @throws SQLException 如果查询失败
     */
    public static List<Map<String, Object>> queryForList(String mdbPath, String sql, Object... params) throws SQLException {
   
        validateParameters(mdbPath, sql);

        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;

        try {
   
            conn = getConnection(mdbPath);
            stmt = conn.prepareStatement(sql);

            // 设置查询参数
            if (params != null) {
   
                for (int i = 0; i < params.length; i++) {
   
                    stmt.setObject(i + 1, params[i]);
                }
            }

            rs = stmt.executeQuery();
            return convertResultSetToList(rs);

        } finally {
   
            closeResources(rs, stmt, conn);
        }
    }

    /**
     * 验证参数有效性
     *
     * @param mdbPath MDB文件路径
     * @param sql SQL语句
     */
    private static void validateParameters(String mdbPath, String sql) {
   
        if (mdbPath == null || mdbPath.trim().isEmpty()) {
   
            throw new IllegalArgumentException("MDB file path cannot be null or empty");
        }
        if (sql == null || sql.trim().isEmpty()) {
   
            throw new IllegalArgumentException("SQL statement cannot be null or empty");
        }
    }

    /**
     * 关闭数据库资源
     *
     * @param rs ResultSet对象
     * @param stmt Statement对象
     * @param conn Connection对象
     */
    private static void closeResources(ResultSet rs, Statement stmt, Connection conn) {
   
        try {
   
            if (rs != null) {
   
                rs.close();
            }
        } catch (SQLException e) {
   
            // 记录日志但不抛出异常
            System.err.println("Failed to close ResultSet: " + e.getMessage());
        }

        try {
   
            if (stmt != null) {
   
                stmt.close();
            }
        } catch (SQLException e) {
   
            System.err.println("Failed to close Statement: " + e.getMessage());
        }

        try {
   
            if (conn != null) {
   
                conn.close();
            }
        } catch (SQLException e) {
   
            System.err.println("Failed to close Connection: " + e.getMessage());
        }
    }

    /**
     * 将ResultSet转换为List<Map<String, Object>>
     *
     * @param rs ResultSet对象
     * @return 转换后的列表
     * @throws SQLException 如果转换失败
     */
    private static List<Map<String, Object>> convertResultSetToList(ResultSet rs) throws SQLException {
   
        List<Map<String, Object>> resultList = new ArrayList<>();

        if (rs == null) {
   
            return resultList;
        }

        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();

        // 获取列名列表
        List<String> columnNames = IntStream.rangeClosed(1, columnCount)
                .mapToObj(i -> {
   
                    try {
   
                        return metaData.getColumnLabel(i);
                    } catch (SQLException e) {
   
                        throw new RuntimeException("Failed to get column name", e);
                    }
                })
                .collect(Collectors.toList());

        // 遍历结果集
        while (rs.next()) {
   
            Map<String, Object> row = new LinkedHashMap<>();
            for (String columnName : columnNames) {
   
                row.put(columnName, rs.getObject(columnName));
            }
            resultList.add(row);
        }

        return resultList;
    }
}

3️⃣ 如何使用工具类

public class Example {
   
    public static void main(String[] args) throws SQLException {
   
        String sql = "select * from UserInfo";
        String mdbPath = "D:\\mdb\\mdbtest.mdb";
        List<Map<String, Object>> resultList = MdbJdbcUtil.queryForList(mdbPath,sql);
        System.out.println("查询结果数量"+resultList.size());
        for (Map<String, Object> row : resultList) {
   
            System.out.println(row);
        }
    }
}

运行上面的代码,你会看到如下输出:

查询结果数量: 2
{UserNO=1, UserID=Admin, UserName=管理员Admin, UserPassword=123456}
{UserNO=2, UserID=Xiuji, UserName=管理员Xiuji, UserPassword=123456789}

⚠️ 注意事项

  • memory设置

在处理大型数据库并使用默认的"memory"设置(即驱动属性memory=true)时,建议用户通过-Xms和-Xmx选项为JVM分配足够的内存。否则,必须将驱动的"memory"属性设置为"false"

  • ignoreCase设置

ignoreCase:此属性用于禁用(ignoreCase=true)或启用(ignoreCase=false)文本比较的区分大小写功能。默认值=true。

📝 总结

通过UCanAccess库,我们可以轻松地在SpringBoot项目中解析.mdb文件,无需依赖Windows环境或ODBC驱动。这个方案特别适合:

  • ✅ 临时数据提取任务
  • ✅ 遗留系统数据迁移
目录
相关文章
|
2月前
|
存储 弹性计算 安全
2026年阿里云计算型 c7 实例全解析:性能参数、场景适配与选型参考
阿里云 ECS 计算型 c7 实例依托第三代神龙架构,以 Intel Ice Lake 处理器为核心,聚焦计算密集与高网络负载场景,提供从 2 核 4G 到 128 核 256G 的全规格配置,兼具性能稳定性与安全特性,以下从硬件架构、核心参数、适用场景及选型对比展开解析。
|
1月前
|
人工智能 物联网 Shell
告别“人工智障”:零代码驯服大语言模型,打造你的专属AI助手
本文详解大模型微调(Fine-tuning)如何破解通用AI“懂但不专”的痛点:用专属数据为大模型做“岗前培训”。全程零代码、纯在线,基于ModelScope与QLoRA技术,30分钟即可完成Yi-6B模型微调,重塑其身份认知。兼顾原理通俗解读与手把手实战,助你真正掌握“塑造AI”的主动权。(239字)
191 3
告别“人工智障”:零代码驯服大语言模型,打造你的专属AI助手
|
2月前
|
存储 人工智能 前端开发
PinMe:零成本三秒发布你的网站
PinMe是一款零配置、去中心化的前端部署工具,基于IPFS实现静态网站一键发布。无需服务器、域名或复杂配置,支持网页拖拽或命令行上传,自动生成可验证、抗篡改的永久链接。单文件200MB、整站1GB以内免费部署,让发布变得简单、安全、可靠。🚀
507 11
PinMe:零成本三秒发布你的网站
|
Java Maven
MapStruct - Couldn‘t retrieve @Mapper annotation
MapStruct - Couldn‘t retrieve @Mapper annotation
3021 0
|
15天前
|
存储 人工智能 网络安全
2026年OpenClaw/Clawdbot多Agent实战指南:阿里云+Windows部署,打造全功能AI智能体协作团队
2026年AI智能体进入规模化协作时代,OpenClaw(原Clawdbot)凭借原生多Agent支持、独立工作区隔离、灵活路由机制,成为搭建专属智能体团队的首选框架。不同于单智能体“全能但混乱”的痛点,多Agent架构通过“角色拆分、身份隔离、协作分工”,让每个智能体专注特定领域,彻底解决上下文污染、人设混乱、Token消耗过高的核心问题。
1145 3
|
3月前
|
安全 Linux 测试技术
外网下载内网部署:Yum离线升级Linux软件包
针对生产环境内网隔离、无法直连外网的困境,本文分享利用 `yum install --downloadonly` 命令在外网下载RPM包及依赖,再离线传输至内网部署的完整方案。涵盖单包、批量、指定版本下载,依赖处理与本地安装步骤,实现安全合规的漏洞修复与软件升级,适用于应急响应、批量部署等场景。
478 156
|
3月前
|
机器学习/深度学习 算法
费曼学习法:为什么你应该通过写博客来掌握任何知识
你是否学完就忘?诺贝尔奖得主费曼提出:若无法简单解释,便是未真正理解。其学习法四步——学习、教授、反思、简化——结合写博客,能深度巩固知识。写作倒逼思维清晰,暴露理解盲区,构建个人知识库。无需完美,从“初学者视角”出发,边学边写,用输出驱动输入。写博客不仅是记录,更是成为专家的路径。开始吧,让文字见证你的深度学习之旅。
500 163
费曼学习法:为什么你应该通过写博客来掌握任何知识
|
5月前
|
安全 数据安全/隐私保护
Dataphin功能Tips系列(73)Dataphin行级权限:构建灵活高效的权限管理体系
Dataphin行级权限通过“控制字段”实现精细化数据管控,有效避免传统字段权限过度开放带来的安全风险,提升权限管理效率与灵活性,满足复杂场景下的数据安全需求。
243 4
|
2月前
|
安全 文件存储 数据安全/隐私保护
告别密码焦虑!开源密码神器 password-XL:安全、美观、全能的私有密码管家
password-XL是一款开源、安全的私有密码管理工具,支持本地或服务器部署,数据自主可控。美观界面、多端同步、功能丰富,适合个人与团队使用,告别密码泄露风险,打造专属数字管家。
320 12
告别密码焦虑!开源密码神器 password-XL:安全、美观、全能的私有密码管家
|
缓存 监控 Java
优化Spring Boot应用的数据库访问性能
优化Spring Boot应用的数据库访问性能

热门文章

最新文章