带徒弟从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

相关文章

通过ibd文件恢复MySql数据的操作方法

《通过ibd文件恢复MySql数据的操作方法》文章介绍通过.ibd文件恢复MySQL数据的过程,包括知道表结构和不知道表结构两种情况,对于知道表结构的情况,可以直接将.ibd文件复制到新的数据库目录并... 目录第一种情况:知道表结构第二种情况:不知道表结构总结今天干了一件大事,安装1Panel导致原来服务

Java实现将byte[]转换为File对象

《Java实现将byte[]转换为File对象》这篇文章将通过一个简单的例子为大家演示Java如何实现byte[]转换为File对象,并将其上传到外部服务器,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言1. 问题背景2. 环境准备3. 实现步骤3.1 从 URL 获取图片字节数据3.2 将字节数组

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

Jmeter如何向数据库批量插入数据

《Jmeter如何向数据库批量插入数据》:本文主要介绍Jmeter如何向数据库批量插入数据方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Jmeter向数据库批量插入数据Jmeter向mysql数据库中插入数据的入门操作接下来做一下各个元件的配置总结Jmete

SpringBoot接收JSON类型的参数方式

《SpringBoot接收JSON类型的参数方式》:本文主要介绍SpringBoot接收JSON类型的参数方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、jsON二、代码准备三、Apifox操作总结一、JSON在学习前端技术时,我们有讲到过JSON,而在

Spring-AOP-ProceedingJoinPoint的使用详解

《Spring-AOP-ProceedingJoinPoint的使用详解》:本文主要介绍Spring-AOP-ProceedingJoinPoint的使用方式,具有很好的参考价值,希望对大家有所帮... 目录ProceedingJoinPoijsnt简介获取环绕通知方法的相关信息1.proceed()2.g

Spring Security注解方式权限控制过程

《SpringSecurity注解方式权限控制过程》:本文主要介绍SpringSecurity注解方式权限控制过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、摘要二、实现步骤2.1 在配置类中添加权限注解的支持2.2 创建Controller类2.3 Us

Spring MVC跨域问题及解决

《SpringMVC跨域问题及解决》:本文主要介绍SpringMVC跨域问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录跨域问题不同的域同源策略解决方法1.CORS2.jsONP3.局部解决方案4.全局解决方法总结跨域问题不同的域协议、域名、端口

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin

JAVA SE包装类和泛型详细介绍及说明方法

《JAVASE包装类和泛型详细介绍及说明方法》:本文主要介绍JAVASE包装类和泛型的相关资料,包括基本数据类型与包装类的对应关系,以及装箱和拆箱的概念,并重点讲解了自动装箱和自动拆箱的机制,文... 目录1. 包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和自动拆箱2. 泛型2