带徒弟从java连接access数据过程中发现的疑难问题吸取成长经验

本文主要是介绍带徒弟从java连接access数据过程中发现的疑难问题吸取成长经验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.背景

        当然还是公司要求的师带徒任务。公司的化检验室在作业后,数据只能手工填到系统中,打开化检验室电脑发现是用的access数据。我想可以把access数据库的数据自动上传到系统,这样就减少了检化验人员的工作量,也减少了数据因手工录入带来的不必要错误。其实,在很多公司都有类似的边缘系统,用类似这种数据的还很多。只是在过程中出现了意想不到的问题,这个案例值得记录。

二.开发环境

操作系统:win11家庭版

jdk:1.8

开发工具:eclipse(我)、idea(徒弟)

access:2007

三.连接的技术路线选择

       网上资料主要是ODBC-JDBC桥接、JDBC连接两种,参考资料Java 连接Access数据库的两种方式_java_脚本之家。很多年以前,我是用的ODBC-JDBC桥接的方式。我建议徒弟用JDBC的方式。让他先动手,不行我再来。

      JDBC的驱动,网络资料用UCanAccess的居多,如Springboot连接Access2003数据库_springboot连接access数据库-CSDN博客

四.问题的发生

Exception in thread "main" java.io.IOException: Unsupported newer version: 20at com.healthmarketscience.jackcess.JetFormat.getFormat(JetFormat.java:289)at com.healthmarketscience.jackcess.Database.<init>(Database.java:908)at com.healthmarketscience.jackcess.Database.open(Database.java:676)at com.healthmarketscience.jackcess.Database.open(Database.java:615)at com.healthmarketscience.jackcess.Database.open(Database.java:585)at com.healthmarketscience.jackcess.Database.open(Database.java:558)at com.healthmarketscience.jackcess.Database.open(Database.java:534)at com.scantt.sevenstarcolor.AccessJackcessUtils.main(AccessJackcessUtils.java:43)

因为用的数据连接池的方式,启动时报错。一看错误认为是版本的问题,反复换了ucanaccess的多个版本,错误一直都没有变。

五.问题的跟踪解决

1.看源码,加断点,发现惊天密码

在网上收索了一大堆,没有一个资料写到了这个问题。徒弟没有了思路,该我上场了。先看看源代码,发现JetFormat.getFormat主要就是从文件头的字节码来判断access文件的版本,没有找到版本就要报错啊!这个完整的方法如下:

public static JetFormat getFormat(FileChannel channel) throws IOException {ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH);int bytesRead = channel.read(buffer, 0L);if(bytesRead < HEADER_LENGTH) {throw new IOException("Empty database file");}buffer.flip();byte version = buffer.get(OFFSET_VERSION);if (version == CODE_VERSION_3) {return VERSION_3;} else if (version == CODE_VERSION_4) {if(ByteUtil.matchesRange(buffer, OFFSET_ENGINE_NAME, MSISAM_ENGINE)) {return VERSION_MSISAM;}return VERSION_4;} else if (version == CODE_VERSION_12) {return VERSION_12;} else if (version == CODE_VERSION_14) {return VERSION_14;}throw new IOException("Unsupported " +((version < CODE_VERSION_3) ? "older" : "newer") +" version: " + version);}

跟踪代码发现,第21个字节存储的是版本信息。实际buffer的值,第21个字节值为20。

[37, 84, 83, 68, 45, 72, 101, 97, 100, 101, 114, 45, 35, 35, 35, 37, -90, 28, -128, -101, 20]

而代码中各个版本的定义值分别是:

CODE_VERSION_3:0x0

CODE_VERSION_4:0x1

CODE_VERSION_12:0x2

CODE_VERSION_14:0x3

根本没有20这个版本的定义啊!我把access另存为2000、2003、2007等都是报的相同问题,见鬼了,难道字节码还被谁修改了?突然我注意到了文件图标上面的锁,心里一惊,哎呀,可能跟公司安装的监视加密软件有关。。。。

平时,我们的word、ppt等文档都被加密了的,发出去别人看到的是乱码。加密嘛,在存储层面肯定对字节码做了手脚的。为啥我们机器上打开文档不是乱码呢?加密软件应该劫持了微软word、金山wps等软件的进程,在内存中喂数据给软件之前对数据进行了解密,所以在软件中看到的内容就不是乱码了。而我们的开发工具没有被加密软件劫持,我们拿到的就是加密的字节码,当然就是不正确的啦!

2.绕开加密软件,看正常文件的version标识值,验证猜想

既然,我们开发工具eclipse没有被劫持,那么我可以用eclipse创建并写入数据,该文档就应该是未加密状态。代码如下:

String filePath = "D:/test/test1.mdb";
Database db = Database.create(FileFormat.V2000,new File(filePath));Table newTable = new TableBuilder("NewTable").addColumn(new ColumnBuilder("a").setSQLType(Types.INTEGER).toColumn()).addColumn(new ColumnBuilder("b").setSQLType(Types.VARCHAR).toColumn()).toTable(db);newTable.addRow(1,"foo");
db.close();

为了追求快速验证我的想法,代码随便写的,不要吐槽啊!

发现文件图标没有锁的标识了。

再读取一下数据看看呢?代码如下:

String filePath = "D:/test/test1.mdb";
Database db = Database.open(new File(filePath),true);
Table newTable =db.getTable("NewTable");for(Map<String,Object> row: newTable) {System.out.println(row);}
db.close();

读取正常,输出如下:

11:07:41.682 [main] DEBUG com.healthmarketscience.jackcess.PageChannel - Reading in page 1a
{a=1, b=foo}

断点调试,取得文件头21个字节的值为:

[0, 1, 0, 0, 83, 116, 97, 110, 100, 97, 114, 100, 32, 74, 101, 116, 32, 68, 66, 0, 1]

第21个字节的值为1,对应是CODE_VERSION_4,经过查找发现我创建文件的FileFormat.V2000的值相对应。至此,破案了,一切都是加密软件背锅。

六.总结

       徒弟毕业不到一年,能用网上资料搭建环境,连接access已经不错了。出现的搜索不到的问题,我们要大胆的阅读源代码。思维打开,放飞想法,谁能想到开发机器安装了加密监视软件?代码的断点调试,字节码值的妖怪现象还是揭露了加密监视软件的手脚。本来不是问题,有了这样的问题出现,提升了徒弟排查问题的能力,打开了思维。不要怕,再诡异的问题都有原因!

这篇关于带徒弟从java连接access数据过程中发现的疑难问题吸取成长经验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/900253

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定