ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

IFIX数据同步到MySQL实战:基于VBA与ODBC的解决方案

2026/9/16 23:15:46 拓冰建站 浏览量
IFIX数据同步到MySQL实战:基于VBA与ODBC的解决方案 1. 为什么要把IFIX的数据同步到MySQL1.1 这个需求是从哪来的干工控和SCADA这行的人对IFIX应该都不陌生。GE的这套组态软件在电力、水处理、冶金、化工这些行业里装机量非常大很多现场已经稳定跑了十几年。但IFIX本身的历史存储逻辑偏向“本地文件”也就是把数据写进自己的HTR历史文件用它的趋势图看很方便可一旦涉及跨系统共享、做报表、上数据平台这文件就变得很封闭了。于是“IFIX往MySQL数据库同步数据”就成了一个看起来不起眼、但隔三差五就会被问到的高频需求。我最早接触这个需求是一位水厂的朋友找我帮忙。现场是IFIX采集了几十台设备的压力、流量、液位领导突然要求做一张“全天生产报表”而且要在手机上看数据。IFIX自带的报表工具做不了这种活他们IT那边又指定要用MySQL存历史数据。压力就落到我头上怎么把IFIX里实时变化的值按周期写进MySQL。这个需求的本质就是数据同步。你在IFIX画面的数据库里能看到每个Tag的实时值在MySQL的某张表里也想看到这些值的历史记录。两个系统之间的桥梁常见做法有三条路用IFIX自带的SQL触发功能SQL Trigger由事件或周期触发写库用IFIX内嵌的VBA脚本在Workspace里跑定时任务或事件把Tag值通过ODBC写入MySQL在中间加一层专用的工业数据库网关比如一些商用数据采集软件或自研的采集服务。这三条路我都试过。个人最推荐、也是实际项目里用得最多的是VBA脚本配合ODBC的方式。原因后面细说。先把这套方法整体讲透你再根据自己的现场情况去选。1.2 先理清楚整体架构少走一半弯路很多人在这一步就乱了一上来就翻IFIX的帮助文档找“数据库同步”的按钮。实际上IFIX和MySQL之间没有现成的“一键同步”功能所有方法本质上都是绕不开中间那一层ODBC。所以整个数据链路是这样的IFIX实时数据库中的Tag值 - VBA脚本读取 - 通过ODBC数据源 - 写入MySQL指定的表这里有两个容易忽略的点。第一IFIX的VBA运行在Workspace进程内它读取的是IFIX实时数据库的当前值不是历史文件里的值。所以如果你需要同步的是“历史数据”那得先保证IFIX进程在运行、数据在实时更新脚本才能采得到。第二ODBC是Windows下的通用数据库接口IFIX侧不需要额外装MySQL的客户端装好MySQL的ODBC驱动就行。这个方法选型的核心优势有两个一是可控性强采集周期、写入条件、插入语句全都可以按现场要求改二是基本不花钱IFIX自带VBA环境MySQL和ODBC驱动也都是免费的不需要额外的License。缺点是IFIX VBA占用的是本机进程资源如果同步频率特别高、数据量特别大会有性能瓶颈。不过在大多数中小型SCADA系统里每秒写几十条记录完全够用。2. 先把环境搞定驱动、数据库与ODBC配置2.1 MySQL驱动怎么选为什么推荐Unicode版配置第一步是装ODBC驱动。这里有坑而且是好几个坑我先说驱动选择。去MySQL官网下载ODBC驱动时会看到一堆版本32位、64位还分ANSI版和Unicode版。我的建议是如果IFIX是32位就装32位的MySQL ODBC驱动如果IFIX是64位就装64位的。这个位数问题后面还会在配置ODBC数据源时再次出现千万别搞混。至于ANSI和Unicode版本建议直接选Unicode。原因很简单咱们现场的设备描述、中文Tag名、甚至报警信息里都可能有中文用ANSI版驱动很容易出现乱码而Unicode版对UTF-8的支持好得多可以少折腾很多事。下面是我常用的一个环境参考组件推荐版本备注IFIX5.5 / 5.8 / 6.x不同版本Workspace差别不大逻辑通用MySQL服务端5.7 / 8.08.0需要新版ODBC驱动版本别太低MySQL ODBC驱动8.0.x Unicode版如果你用MySQL 5.7用5.3的Unicode版也行操作系统Windows Server 2016/201932位IFIX跑在64位系统上很常见驱动装完以后先别急着配数据源。建议顺手把MySQL建库建表的事一起做了这样后面测ODBC时能直接对着一张真实存在的表测试省得反复改配置。2.2 建库建表字段设计直接影响后续取数同步数据的最终目的是为了让别人能查、能用。所以表结构设计特别重要。我见过有人把所有Tag都塞到一张表里每列一个Tag结果现场加了设备就要ALTER TABLE维护起来非常痛苦。更推荐的方式是长表模型一条记录一行用“TagName”字段区分是什么测点。建表SQL可以参考下面这个CREATE DATABASE IF NOT EXISTS ifix_scada DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; USE ifix_scada; CREATE TABLE IF NOT EXISTS tag_history ( id INT AUTO_INCREMENT PRIMARY KEY, tag_name VARCHAR(100) NOT NULL, tag_value DOUBLE NULL, quality INT NULL, update_time DATETIME NOT NULL, KEY idx_tag_time (tag_name, update_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有几个细节我要重点说一下。第一update_time我没设默认值故意让脚本每次插入时自己带上时间。原因在于IFIX读到的值带的是IFIX服务器的时间如果让MySQL自己取NOW()两台机器的时钟有偏差时数据时间就对不上了。用脚本时间至少保证跟IFIX画面的时间一致。第二字段类型里tag_value用DOUBLE因为流量、压力这类过程值很多是浮点。如果你们的项目还需要存状态值比如设备启停这种布尔量可以用单独的字段或加一张状态表别把所有类型都塞进一个字段后期查询会非常难受。第三联合索引idx_tag_time建在tag_name和update_time上这是给报表查询用的。工业报表最典型的查询是“某个Tag在某段时间的值”这两个字段组合起来查效率会高很多。2.3 在Windows上把ODBC数据源配好接下来是配置ODBC数据源。这一步踩坑概率极高我先把最安全的操作流程写出来。如果是64位系统上装的32位IFIX打开ODBC管理工具时要注意一个细节开始菜单里的“ODBC数据源(64位)”和“ODBC数据源(32位)”是两个不同的入口。如果你用64位管理工具配了数据源32位的IFIX照样看不到。所以打开数据源管理器前先确认位数。32位ODBC管理工具的路径一般是C:\Windows\SysWOW64\odbcad32.exe打开后在“系统DSN”选项卡里点“添加”选择“MySQL ODBC 8.0 Unicode Driver”。然后填写连接参数配置项填写内容Data Source Nameifix_mysql_dsnTCP/IP Server127.0.0.1 或数据库服务器IPPort3306Userifix_writerPassword你的密码Databaseifix_scada这里我强调一下用户名建议单独创建一个权限最小的账号只用INSERT权限就够了。有些现场图省事直接拿root写数据一旦脚本被外部触发风险非常大。最小权限原则在工控系统里同样适用不是说没有外部攻击就无所谓内部误操作一样能把表删了。配置完以后先别进IFIX。在ODBC配置窗口里点“Test”如果显示Connection successful再往下走。我强烈建议把这一步作为硬性检查项因为后面所有写库问题最后八成都能回溯到这一步驱动不对、位数不对、IP不通、账号密码错误。3. 核心方法用IFIX VBA把实时值写进MySQL3.1 先从最简单的定时采集版开始环境通了以后剩下的事就是写脚本。IFIX的Workspace内置了VBA编辑器你可以通过菜单或快捷键打开VBA开发环境然后在ThisApplication、代码模块或者某个画面里写代码。下面是我最早用的一版代码逻辑非常简单每隔10秒读取两个Tag的当前值插入到MySQL的tag_history表里。Sub SyncTagToMySQL() Dim conn As Object Dim rs As Object Dim strConn As String Dim strSQL As String Dim tagVal As Double Dim i As Integer Dim tagNames As Variant 要同步的Tag列表 tagNames Array(FIC_101.PV, PIC_201.PV, LI_305.PV) 创建ADO连接对象 Set conn CreateObject(ADODB.Connection) strConn Driver{MySQL ODBC 8.0 Unicode Driver}; _ Server127.0.0.1;Port3306; _ Databaseifix_scada;Uidifix_writer;Pwdyourpassword; _ Option3;CHARSETutf8mb4; conn.Open strConn For i LBound(tagNames) To UBound(tagNames) 从IFIX实时数据库读取Tag当前值 tagVal ReadFixTag(tagNames(i)) 拼接插入语句 strSQL INSERT INTO tag_history (tag_name, tag_value, quality, update_time) VALUES ( _ tagNames(i) , _ tagVal , 0, NOW()) conn.Execute strSQL Next i conn.Close Set conn Nothing End Sub Function ReadFixTag(tagFullName As String) As Double 这里是IFIX读取Tag值的标准用法不同版本写法略有差异 示例写法实际请按你的IFIX版本调整 Dim f As Double f Me.Fix32.Fix.OleItem(tagFullName).Value ReadFixTag f End Function这段代码有几处值得仔细说明。第一连接串里的Driver名称必须和ODBC驱动安装的完全一致。如果你装的是“MySQL ODBC 5.3 Unicode Driver”那Driver{MySQL ODBC 8.0 Unicode Driver}就会报找不到驱动。这一步的问题是新手遇到最多的排查方式就是在VBA里弹出一个连接对象的错误提示看看是哪个环节断的。第二Option3这个参数是把ODBC驱动的一些默认行为打开比如连接超时设置、自动提交等。在不同版本的驱动下这个参数不是必须的但加上以后兼容性更好。如果你发现在MySQL端偶尔出现锁表或连接不释放可以考虑调整这个参数。第三这段代码最笨的地方在于每执行一次就新建和关闭一次连接。采集频率如果是10秒一次数据库压力不大还能接受。如果系统里的Tag数量多、采集频率高后面我会讲一个更好的批量插入方案。3.2 触发方式优化定时器、事件、还是数据变化IFIX里触发这个脚本的方式决定了你的同步是“按时间周期”还是“按值变化”。两种场景在工业现场都有应用。最常见的是定时周期采集。你可以用Workspace里的“Schedule”功能也可以放一个隐藏的Timer控件。我个人更推荐用IFIX的Schedule因为它跟画面是否打开无关只要Workspace在运行就会按设定触发。具体做法是在VBA里找到“Application”对象的事件或者在Workspace中打开Scheduler添加一个周期任务指向上面那个SyncTagToMySQL过程周期设为“每10秒”。另一种触发方式是数据变化触发。有些场景比如报警值、故障状态你希望值一变就立刻写库而不是等下一个周期。这种可以借助IFIX数据连接里的“数据变化事件”来触发在画面的Tag上绑定一个DataChanged事件在事件里调用写入过程。但这里要注意数据变化如果特别频繁比如模拟量压力值一直存在微小波动那数据库会被写爆。所以我实际项目中通常设置“死区”比如变化量超过0.5才触发。我的建议是常规过程量用定时采集关键状态量用数据变化触发两者结合。定时周期兜底事件触发保证及时性。3.3 稳定版本的批量写入方案前面那个简单版本只能算“能跑”距离“能长期稳定跑”还有段距离。现场项目里最忌讳的就是脚本三天两头出问题还没人知道。所以我后来改进了一版加入三个关键机制批量提交、错误日志、单例运行。批量提交的思路是这样的不再一条一条Insert而是先把要写的数据攒在内存里攒够一批或者每隔一段时间一次性用几条SQL插入。MySQL对批量插入效率提升非常明显尤其是一次插入几十条、几百条记录时比一条条插要快一个数量级。下面是我改进后的关键片段Sub BatchInsertTagData() Dim conn As Object Dim strSQL As String Dim i As Integer Dim tagNames As Variant Dim values As String Dim nowTime As String tagNames Array(FIC_101.PV, PIC_201.PV, LI_305.PV) nowTime Format(Now(), yyyy-mm-dd hh:nn:ss) Set conn CreateObject(ADODB.Connection) conn.Open Driver{MySQL ODBC 8.0 Unicode Driver}; _ Server127.0.0.1;Databaseifix_scada; _ Uidifix_writer;Pwdyourpassword;CHARSETutf8mb4; values For i LBound(tagNames) To UBound(tagNames) tagVal ReadFixTag(tagNames(i)) If values Then values values , values values ( tagNames(i) , tagVal ,0, nowTime ) Next i strSQL INSERT INTO tag_history (tag_name, tag_value, quality, update_time) VALUES values conn.Execute strSQL conn.Close Set conn Nothing End Sub这里面有个小细节所有记录的update_time用的是同一个nowTime这样一批数据的时间戳是统一的对报表来说很友好。如果你希望每条数据都是精确到各自采集的时刻可以在循环里单独读取时间但那样的话批量插入的优势会被削弱一些。单例运行也很重要。如果定时任务和画面事件同时触发了写入就会有两个进程同时操作同一个表。虽然INSERT本身不会冲突但会造成数据库连接数增加偶尔还会出现锁等待。我用一个全局变量作为“运行标志”如果上次还没执行完这次就跳过。这个实现很简单加一个模块级变量就行。4. 实操现场从零到一跑通一次同步4.1 完整流程先测ODBC再测VBA再上定时器很多人一上来就直接写代码、跑定时器结果出了问题根本分不清是哪一段的错。我养成了一个习惯所有这类同步项目都按照“三层测试”的顺序来做这里完整分享一遍。第一步用Excel测ODBC驱动和数据源。新建一个Excel文件在“数据”选项卡里选择“获取数据-来自其他源-从ODBC”选择ifix_mysql_dsn数据源输入账号密码看能不能列出tag_history表的数据。这一步通过说明Windows层面的ODBC链路是通的。第二步在IFIX的VBA环境里写一个按钮点击后直接执行上面那个简单版本的单条插入脚本然后去MySQL里查一下有没有新增记录。这一步通过说明IFIX的VBA引擎能正常调用ODBC。 按钮点击事件中先执行一次单条插入作为验证 Private Sub CommandButton1_Click() Dim conn As Object Set conn CreateObject(ADODB.Connection) conn.Open Driver{MySQL ODBC 8.0 Unicode Driver};Server127.0.0.1;Databaseifix_scada;Uidifix_writer;Pwdyourpassword;CHARSETutf8mb4; conn.Execute INSERT INTO tag_history (tag_name, tag_value, quality, update_time) VALUES (TEST.PV, 123.45, 0, NOW()) conn.Close Set conn Nothing MsgBox 写入成功 End Sub第三步验证能写入后再把脚本接到定时器或Schedule上。建议先设一个比较长的周期比如60秒观察半小时确认稳定无误后再缩短到目标周期。不要一上来就1秒插一次万一脚本有Bug数据库里会瞬间塞满垃圾数据排查的时候反而增加了干扰项。4.2 同步后的数据怎么用万能历史曲线与报表场景数据成功进库只是第一步。很多项目为什么要做MySQL同步是为了让第三方报表系统能读取数据。但也有一些项目是希望在IFIX里直接调取MySQL里的历史数据来展示趋势曲线这时候IFIX的“万能历史曲线模板”就派上用场了。这里要解释一下IFIX自带的趋势图一般读取本地历史文件而“万能历史曲线模板”这类自定义工具可以通过SQL查询外部数据库作为数据源把存放在MySQL里的历史数据拉回来画曲线。这就是为什么很多资料里会把“IFIX历史数据同步到MySQL”和“万能历史曲线模板”放在一起讨论它们是上下游关系。数据库里的数据画曲线时我建议直接使用SQL聚合。比如要画2小时的趋势没必要把10秒一条的720条记录全查出来可以按分钟取平均值SELECT DATE_FORMAT(update_time, %Y-%m-%d %H:%i:00) AS time_point, AVG(tag_value) AS avg_value FROM tag_history WHERE tag_name FIC_101.PV AND update_time DATE_SUB(NOW(), INTERVAL 2 HOUR) GROUP BY time_point ORDER BY time_point;这种查询在报表里很常用而且能大幅减少趋势图的渲染压力。不过要注意数据库的趋势曲线始终和IFIX本地历史曲线有差异主要差异在于采集周期。如果你的VBA脚本是10秒采集一次那数据库里的曲线最多只能体现10秒的粒度比IFIX本地1秒甚至更细的历史文件要粗。所以一般不建议拿数据库曲线去替代实时监控用的本地趋势它更适合用在报表、统计分析、多系统数据平台这种场景。5. 常见问题与排查技巧实录5.1 我踩过的五个典型坑这个环节我直接做一张表把经常遇到的现象、原因和解决办法列出。白纸黑字写下来下次遇到可以直接对着查。现象大概率原因解决办法VBA执行时报“未找到数据源名称且未指定默认驱动程序”系统DSN没配好或IFIX位数与ODBC位数不一致确认IFIX是32位还是64位用SysWOW64下的odbcad32.exe重配DSN报错“1251 Client does not support authentication protocol”MySQL 8.0默认的caching_sha2_password加密方式旧版ODBC不认识升级到MySQL ODBC 8.0及以上驱动或把用户改回mysql_native_password插入的数据中文全部变成问号MySQL字符集或ODBC连接串字符集设置不对库表统一utf8mb4连接串加CHARSETutf8mb4写库一段时间后连接失效报“MySQL server has gone away”ODBC连接在空闲时被服务端断开每次操作后释放连接或者缩短脚本执行周期也可以调大MySQL的wait_timeout数据库写入时间比IFIX画面慢几分钟VBA调度周期不准或上次执行没完成导致跳过减少单次执行时间改为批量插入检查服务器系统时间第五个问题其实很有代表性很多人以为是脚本写错了其实是因为定时器任务在执行过程中出现了阻塞上一次还没跑完下一次的触发被跳过。这种问题用“运行日志”最好排查。建议在脚本里加一个文本日志输出把每次执行开始时间、写入条数、执行结束时间记录下来。日志文件不用很大保留最近几百条就够。5.2 一个通用排查思路沿着链路从最底层往上查数据库同步出问题很多时候是“看起来都在就是数据没进去”。这时候我习惯用排除法从最底层的链路开始逐层往上定位。先测MySQL服务本身。在数据库服务器上用命令行客户端连一下确认服务正常、用户权限正确、表结构存在。再测ODBC层用Excel或ODBC管理工具里的Test按钮验证DSN能不能连通。再测VBA连接对象单独写一个只打开连接、不执行插入的测试过程看能不能正常Open。最后再测插入语句本身可以先手动执行一条最简单的INSERT确认SQL语法没问题。这样做的好处是每一层都能快速判断“通”还是“不通”思路特别清晰。我见过有的人一出错就怀疑是不是脚本有问题结果查了半天其实是MySQL服务没启动。沿着链路一层层来可以避免这类盲目的折腾。5.3 同步性能与稳定性优化技巧最后说几个长期运行的经验。采集频率不必一味求快。很多报表需求其实只要分钟级数据就够了10秒一次已经算很密的了。如果是以报表为目的的同步建议把采集周期设置在5到10秒以上既满足需求又不会给IFIX服务器和数据库带来太大压力。数据库连接要“即用即关”。有些人图省事把连接对象设为全局变量这样确实减少了频繁连库的开销但这会带来新的问题长连接如果空闲时间超过MySQL的wait_timeout就会被服务端断开脚本再用这个连接执行INSERT就会报错。我的做法是每次脚本执行时新建连接、执行完立即关闭让连接对象生命周期保持很短。如果确实追求性能可以用连接池的方式但要在池子里做好连接的可用性检查。写入失败一定要有“提醒机制”。工业现场的数据很宝贵如果脚本连续失败一个小时事后才发现那段历史的曲线就是断的。我习惯在脚本里做计数如果连续N次插入失败就用IFIX的报警功能或发邮件提醒运维人员。这个虽然简单但是在实际项目中帮过大忙。关于性能还有一个点值得提尽量让表保持干净的写入模式。不要随便在历史表上建太多索引索引能加速查询但也会拖慢INSERT。我就是只保留一个必要的联合索引其他查询索引都放到专门的分析库或报表库里做。如果同步的业务量特别大还可以考虑按月分表比如tag_history_202507、tag_history_202506这样的结构写入和查询互不干扰。我在多个项目里验证过10秒周期、100个Tag以内用上面这套VBAODBC方案跑几个月都很稳定基本不用人工干预。真正需要干预的基本都集中在MySQL服务端的配置和网络层面的变更上。这个方案唯一让我觉得“要注意一点”的时刻是IFIX版本升级或者MySQL版本升级的时候。每次版本升级都要重新检查一遍ODBC驱动的兼容性别让“老脚本遇到新驱动”的问题破坏了你长时间积累的稳定状态。