SpringBoot实现解析.mdb文件的实战指南

 更新时间:2026年02月04日 08:33:17   作者:修己xj  
这篇文章主要为大家详细介绍了如何在SpringBoot项目中解析旧版Microsoft Access的.mdb文件,文中提供完整的Maven依赖配置、核心工具类封装及使用示例,帮助开发者快速完成遗留系统数据迁移,希望对大家有所帮助

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

以下是UCanAccess的文档地址ucanaccess.sourceforge.net/site.html

引入Maven依赖

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

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

核心工具类实现

下面是我封装的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;
    }
}

如何使用工具类

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}

注意事项

1.memory设置

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

2.ignoreCase设置

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

总结

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

  • 临时数据提取任务
  • 遗留系统数据迁移

到此这篇关于SpringBoot实现解析.mdb文件的实战指南的文章就介绍到这了,更多相关SpringBoot解析mdb文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java随机生成10位数的字符串ID

    java随机生成10位数的字符串ID

    这篇文章主要为大家详细介绍了java随机生成10位数字符串ID的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • Spring Boot访问静态资源css/js,你真的懂了吗

    Spring Boot访问静态资源css/js,你真的懂了吗

    在搭建springboot时经常需要在html中访问一些静态资源,很多朋友不清楚如何在 Spring Boot中访问静态资源,本文给大家带来两种解决方案,感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • Java Optional解决空指针异常总结(java 8 功能)

    Java Optional解决空指针异常总结(java 8 功能)

    这篇文章主要介绍了Java Optional解决空指针异常总结(java 8 功能),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • SpringBoot读取多环境配置文件的几种方式

    SpringBoot读取多环境配置文件的几种方式

    这篇文章主要给大家介绍了SpringBoot读取多环境配置文件的几种方式,文章通过代码示例介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2023-10-10
  • Java ArrayList实现班级信息管理系统

    Java ArrayList实现班级信息管理系统

    这篇文章主要为大家详细介绍了Java ArrayList实现班级信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • java使用CompletableFuture分批处理任务实现

    java使用CompletableFuture分批处理任务实现

    本文主要介绍了java使用CompletableFuture分批处理任务实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • 关于@Data和@Builder注解解析

    关于@Data和@Builder注解解析

    在使用Lombok库时,@Data和@Builder注解混用可能会导致编译失败,解决方法包括添加@NoArgsConstructor和@AllArgsConstructor注解,或者重写无参构造器并注解@Tolerate,这是因为@Data自动生成的构造器与@Builder的构造模式存在冲突
    2024-10-10
  • Java与JavaScript自动化测试Selenium使用详解

    Java与JavaScript自动化测试Selenium使用详解

    这篇文章主要介绍了Java与JavaScript自动化测试Selenium的使用,Selenium是一个用于Web应用程序测试的工具,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样,需要的朋友可以参考下
    2025-05-05
  • 基于Java实现记事本功能

    基于Java实现记事本功能

    这篇文章主要为大家详细介绍了基于Java实现记事本功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • 几种JAVA细粒度锁的实现方式

    几种JAVA细粒度锁的实现方式

    这篇文章主要为大家详细介绍了几种JAVA细粒度锁的实现方式,感兴趣的小伙伴们可以参考一下
    2016-05-05

最新评论