被一个貌似简单的老技术问题虐了几天

公司的程序需要使用一套外部系统,是必须要用,没得商量的那种,这套外部系统Since 2001年,有将近18年的历史,跟它对接用什么方式?说出来你可能不信,竟然是用生成Microsoft Access(简称MSAccess)文件的方式,没错,就是生成mdb文件,往mdb里写数据,然后丢给这套外部系统。

一个mdb,就是一个数据库,文件型数据库,这也是很多我这个年代来的程序员接触的第一个数据库系统,我记得最早的时候我是用VB(不是VB.NET,那时没有.NET)来访问它的。后来我发觉在比较简单的应用场景里,根本就不需要把数据保存到mdb中,直接读写带一定格式的文件比mdb访问快得多;再后来我发现可以用一些压缩算法来生成更小巧的数据存储文件;再后来我发现xml是一种可读性更好的数据存储方式;再后来我发觉sqlite功能蛮强,不比MSAccess差,由于开源跨平台,应用场景更丰富……总而言之,我没有理由再使用mdb来存储数据了。

若干年后(如果今天看的话就是许多许多年前了),我去了一家公司,我所在的部门有一套非常重要的程序,用VC++写的,保存数据的文件的格式竟然就是mdb……VC++使用mdb文件的方式相当繁琐且容易出错,我当时觉得十分不爽,于是努力替换掉它,把它之前需要好几兆空间保存的数据压缩到几十K,你没看错,缩小了两个数量级,读写速度飞快,可这并不是一件令我有多少愉快回忆的事情,你想我这么一个新人努力地把人家辛辛苦苦定下来的东西“推倒重来”,人家会怎么想?

又若干年后,命运又跟我开了个玩笑:对不起,虽然已经是2019年了,你还是得继续通过mdb文件交换数据!我:……


现在公司的程序并非2019年才诞生,早有了,使用.NET Framework访问mdb文件比VC++轻松无数倍,虽然如此,我还是想进一步简化工作,我写了一套帮助类库,让程序无需关心具体操作,只需要准备好数据到一个数据字典中,把数据字典交给我的帮助类库,就自动完成了填充mdb文件的操作,非常方便。

在刚过去的2018年里,我干了一件事情,就是将大量的程序从.NET Framework上迁移至.NET Core,这里边自然遇到了不少障碍,其中一个“无法逾越”的障碍就是mdb的生成!

访问mdb数据库的正统方法是OLEDB接口,OLE这是个古老的概念,它基于COM(公共组件模型),COM的一个重要特点就是:Windows特有,并且,微软没有把它做成跨平台的打算。

我花了很多时间寻找解决方案,未果,看来只能使用一些折中的做法:mdb的生成使用一个公共的Windows服务器来做,我自定义了一套通信规则,编写了生成mdb的服务程序,还提供了一套方便的客户端代码,调用者可以像原先那样,直接一个方法生成mdb,不用关心中间经过了那些网络通信步骤,还是一样的方便。我的程序经过了全面的测试,确认无误,一切看起来非常OK,直到系统正式使用的时候客户反映mdb的生成频频出问题……

马上查看log,发现了这么一个错误:“XXXX正由另一进程使用,因此该进程无法访问此文件。”XXXX便是我要生成的mdb文件,我在生成mdb文件的时候,把模板复制到临时目录一份,名字用GUID,不会重复的,打开,填充数据,关闭,然后将mdb文件返回给客户端。这“正由另一进程使用”是什么意思?我的文件只可能是我这个进程使用啊。

再经过了N次测试,我本地就是重现不出这个问题,只有把程序部署到服务器上才会出现,并且不能每次都重现,我的本地和服务器的差别是IIS Express和IIS的差别,但对IIS这么纷繁复杂的配置,我感觉要从中找出什么端倪来简直是大海捞针,搜索相关信息,无果。(不喜欢Windows服务器很大程度上是不喜欢IIS,对,我就这么旗帜鲜明)

这个问题的本质就是:我关闭了OLEDB的连接后,mdb文件似乎还处于锁定状态,想用程序读取这个mdb文件返回的话就会出错。好,这个难不倒我,我开始寻找一些解决方法。

1,禁用连接池

OLEDB数据库连接默认也是有连接池的,你关闭一个数据库连接,实际上并不是真的关闭它,而是让它返回到池中,准备给下次打开连接时使用。我很快找到了禁用连接池的选项,禁用之,测试,OK,上线!问题依旧。

2,GC.Collect

我虽然开始学.NET的时候就知道垃圾回收,可直接显式地使用这个方法,是第一次,按照微软官方文档的说法,一般情况下并无GC.Collect的必要,调用这个方法能强制释放一些内存资源,也许能强迫数据库真正关闭。但上线后很快发现问题依旧。

3,外部复制

经过尝试,我发觉竟然可以用Windows的copy命令来复制被打开着的mdb,我灵光一闪,对,服务器也可以这么干,于是关闭mdb连接后调用了外部的copy命令,复制生成的mdb文件,再把复制好的这个文件返回给客户端,perfect!果然,客户那边不再反映什么问题了。这个难题难道就这么解决了吗?图样!第二天,客户找到我们,说我们生成的mdb文件缺数据!这是大问题!甚至比生成不了mdb的问题还要打,前者的话他们可以再次尝试,而后者则可能带来业务上的数据错误。我马上到服务器上看,对比了生成的临时文件,我确认了问题还在!我这样copy被锁定的mdb文件是未写入完全的!有缓存,我要想方法禁掉缓存。

4,尝试禁用OLEDB的写入缓存

Windows在将数据存储至磁盘上的时候,其实都不是直接写磁盘,而是使用了一种缓存机制,先写到缓存,再缓存到物理磁盘,这样无疑提高了调用的速度,所以才有了Flush的概念,Flush就是立即将缓存的数据冲掉,也就是强制立即写入磁盘,而我现在要做的,是禁用掉这个缓存,让对mdb的操作更直截了当地写到磁盘上,我费了不少力气,在微软的官方文档上找到了这个选项,但是这回更惨,本地测试报错,原因是并不支持这个选项,可以理解为OLEDB只是接口,究竟支不支持,还得看引擎,访问mdb的这个Jet引擎貌似不行。

5,更换引擎

Microsoft.Jet.OLEDB.4.0变更为Microsoft.ACE.OLEDB.12.0,嗯,具体的安装文件可以在微软官网下载到。ACE.OLEDB.12.0这个应该更新一些,结果还是不行,并且一样地不支持上一点提到的那个选项。

6,等待解锁

既然上面都不是办法,那我就用重试的机制,读取文件失败,抛出异常,捕捉异常,间隔两秒钟,重试读取,再失败,再重试,最多尝试两分钟,两分钟文件总归写入完成了吧?结果还是不行,2分钟还是无法读取,且这回客户那边有些受不了这样的漫长等待了,客户问能不能恢复之前那个有数据缺失的版本?至少能用。

7,到底有没有.NET Core下的访问mdb文件的第三方库

微软不提供支持,我找第三方行不行?很显然,我之前找过,但这次我打算更认真仔细地找。最后找到了这么一篇文章:《Using Microsoft Access in .NET Core》,写于2018年11月,还挺新,难怪我之前没找到。文章提到了,.NET Core可以用ODBC接口访问mdb,但微软只提供了Windows版本的ODBC引擎,Linux版本的却没有提供,想在Linux环境下直接用ODBC访问mdb的话得找第三方的方案,这里就有一个:Access ODBC Driver,但并不免费,并且费用还不低。

看吧,老板是肯定不会同意让我去买这么一个东西的。

8,ODBC

好,既然上面提到ODBC,那我就切换到ODBC接口去,不用什么OLEDB了,过程进展还挺顺利,除了对MSAccess的类型的理解有少许不同外,ODBC和OLEDB接口差别很小,我很快就弄完了。测试,上线!嗯?这次居然貌似可以了。客户用了一天下来,没再发现什么异常,我检查了日志,也没再出现“正由另一进程使用”的问题。这次难道真的好了吗?我已经有点焦头烂额了。

好吧!至少到现在没再出什么问题。尽管我这几天里并不只在处理这个问题,但这个问题却是这几年来最让我掉面子的问题了。第一它很老,第二它看起来很简单,第三它似乎有很多种变通方法。但实际搞起来却被它虐了许多回合,实在令人唏嘘。


半年前一个许多年前的老同事突然QQ我,说他在解决一个技术问题的时候搜到了我的博客,于是想起了我,挺怀念当初跟我学技术的日子,因为2018年了,他居然在做VB,没错,不是VB.NET,是VB,本文开头提到的那个VB,这是一套极其古老的系统,他还在维护着,我能理解他的苦闷,但这就是生活。

原文地址:https://www.cnblogs.com/guogangj/p/10258345.html

时间: 2024-08-30 05:00:07

被一个貌似简单的老技术问题虐了几天的相关文章

打造支持apk下载和html5缓存的 IIS(配合一个超简单的android APP使用)具体解释

为什么要做这个看起来不靠谱的东西呢? 由于刚学android开发,还不能非常好的熟练控制android界面的编辑和操作,所以我的一个急着要的运用就改为html5版本号了,反正这个运用也是须要从server获取大量数据来展示在手机上面的,也就是说:必须联网,才干正常工作,于是想了一下,反正都要联网获取数据,为什么不直接用我相对熟悉一点的 html来做这个运用呢?省的花费不够用的时间去学习android界面的控制,于是就简单了:用蹩脚的手段做了一个android程序的启动欢迎界面,内页就是一个全屏的

[.NET] 打造一个很简单的文档转换器 - 使用组件 Spire.Office

打造一个很简单的文档转换器 - 使用组件 Spire.Office 目录 Spire.Office 介绍 库引用 界面预览 代码片段 Spire.Office 介绍 关于 Spire.Office,它是一个专门为开发人员创建,读取,写入设计的库,转换和从打印 word 文档文件.作为一个独立的 .NET组件,它不需要在机器上安装微软的 Word 等办公软件.然而,它可以将微软的“文档创建功能”集成到任何开发人员的网络应用程序中.它是一个可靠的 MS Word 的API,可以执行许多Word文档处

Hello,Cardboard!!-如何开发一个最简单的Cardboard虚拟现实应用(一)

温馨提醒,本篇为介绍篇,如果只想看如何开发的具体步骤请参看<Hello,Cardboard!!-如何开发一个最简单的Cardboard虚拟现实应用(三)> 前述:恕我啰嗦一下,主要照顾对cardboard不太了解的朋在,Cardboard是由Google公司的两位巴黎办公室的员工利用业余时间创作出来的作品,它最大的特点就是将原来人们以为高大上的虚拟现实技术以廉价的方式带进了公众的视野,到目前为止,google已推出了改良版的cardboard 2代盒子,相比1代,2代改善了成像,增加了视野范围

JNI编程(一) —— 编写一个最简单的JNI程序

来自:http://chnic.iteye.com/blog/198745 忙了好一段时间,总算得了几天的空闲.貌似很久没更新blog了,实在罪过.其实之前一直想把JNI的相关东西整理一下的,就从今天开始吧.Here we go. JNI其实是Java Native Interface的简称,也就是java本地接口.它提供了若干的API实现了和Java和其他语言的通信(主要是C&C++).也许不少人觉得Java已经足够强大,为什么要需要JNI这种东西呢?我们知道Java是一种平台无关性的语言,平

Mybatis_reveiw之Mybatis官方的一个很简单的Demo

上学的时候,一个老师讲了个故事,这个故事的大意是,我们有很多种方式去削苹果,第一种方式,使用指甲刀,第二种方式,使用机床,第三种方式,使用手摇的那种削平果小工具.我们当然都能够完成这个简单的需求,但是使用指甲刀削出来的苹果一定比较坑坑洼洼,不够美观,而且可能会让人感觉到有点没啥食欲.使用机床呢?可能会造成大量的浪费,原本一个美观大方的苹果变成了只能啃几口的正方形.第三个,因为是专门为了削苹果皮而设计的,理论上是最合适用来解决削苹果这个问题的解决方案. 一个好的架构,其实要做的事情是非常简单的,除

Windows-消息映射机制原理和简单的绘图技术

Windows-消息映射机制原理和简单的绘图技术 1.MFC消息映射机制 众所周知,Windows程序是基于消息编程的,但是在MFC中已经为我们封装好了这个框架的消息机制,我们需要了解它的实现原理,才能深入的学习和精通Visual C++. **(1).消息映射机制的原理: MFC消息映射机制的具体实现方法是,在每个能接收和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表.在消息映射表中,消息与对应的消息处理函数指针是成对出现的.某个类能处理的所有消息及其对应的消息处理函数的地址都

创建一个最简单的Linux随机启动服务

创建一个最简单的Linux随机启动服务 ? Xiaoxia[PG] 创建一个最简单的Linux随机启动服务网上有不少关于如何让Linux自动运行自己编写的脚本或者程序的方法,但是大多数都是把命令写到/etc/rc.d/rc.local或者/etc/rc.local里,这样虽然能够实现随机运行,但是并不够灵活.不能像mysql,apache等服务一样能够使用service命令或者调用init.d下的脚本启动.关闭或者重启进程.例如, service mysql restart service ap

转:简单介绍 P3P 技术

原文来自于:http://blog.csdn.net/ghj1976/article/details/4889219 以 Internet Explorer 为例,默认情况下,IE的隐私策略如下图所设: (图一) 请注意其中这一条:阻止保存可用来联系您的信息而没有您的明确同意的第三方Cookie. 下面我们首先来演示一下,这一条起作用的情况: 站点 b.com 有这样一个网页: http://b.com/WebApp_P3P/p3p.htm 这个页面的源代码如下: <!DOCTYPE html

利用x64_dbg破解一个最简单的64位小程序

最近在研究学习一些逆向的东西,其实之前也涉及到这方面的东西,只是之前的系统和应用,基本上都是32位的,所以直接用od来分析就行了,这方面的资料在网上很多,随便一搜到处都是,不过随着技术的不断发展,64位系统出现了,随之64位的应用也出现了,而od只能分析32位应用,所以一些64位应用,od是没办法分析逆向的,所以,在这里要提到另一个可以用于分析64位应用的调试软件,名字叫x64_dbg.网上对于这款软件的介绍很少,只是说能分析64位应用,具体用法也找不到,不过我找到了它的一个教程,里面有一个最简