PI Square中文论坛: PI SDK 开发中级篇| PI Square
注: 为了更好的利用站内资源营造一个更好的中文开发资源空间,本文为转发修正帖,原作者为OSIsoft技术工程师王曦(Xi Wang),原帖地址:PI SDK 中级篇
来源:https://d.gg363.site/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=2ahUKEwjJ3-HLrP3eAhXJULwKHWSqBloQFjADegQIBxAB&url=https%3A%2F%2Fpisquare.osisoft.com%2Fcommunity%2Fall-things-pi%2Fchinese%2Fblog%2F2016%2F08%2F19%2Fpi-sdk-%25E5%25BC%2580%25E5%258F%2591%25E4%25B8%25AD%25E7%25BA%25A7%25E7%25AF%2587&usg=AOvVaw0su5H-KyXXiNMxqaueXYFa
本帖旨在介绍使用PI SDK做一些基本的数据分析,同时,也包括了数据更新的方法,和一些推荐的程序结构。
本帖针对已对PI SDK基础篇比较了解的开发人员。由于OSIsoft在.NET环境下的开发包,已基本由AF SDK取代,因此,本帖只使用C++语言作为PI SDK的开发平台。如果您需要在.NET环境中进行二次开发,请参考AF SDK中级篇。
说明:PI SDK 是过时的技术
1. 准备工作
在这里的第一段程序,是推荐使用的,进行PI服务器的连接工作,是用子程序的调用方式:
- static ServerPtr PIServerConnect(_bstr_t servername)
- {
- ::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); // 初始化COM
- IPISDKPtr spPISDK // 创建PI SDK连接
- spPISDK.CreateInstance(__uuidof(PISDK)); // 实例化PI SDK连接
- ServerPtr spServer = spPISDK->GetServers()->GetItem(servername); // 通过参数,获取连接
- return spServer; // 返回已连接的服务器指针
- }
进行数据的基本分析,需要搜索PI服务器内的点的数据,以下两端子程序,来自PI基础篇的所有点名和搜索点表的子程序:
按点名搜索:
- static PIPointPtr GetPIPointsByName(ServerPtr server, _bstr_t tagname)
- {
- return server->PIPoints->GetItem(tagname); // 返回一个PIPoint类型的指针
- }
按点表搜索:
- static _PointListPtr SearchPIPoints(ServerPtr server, _bstr_t condition)
- {
- return server->GetPoints(condition, NULL); //返回PointList指针类
- }
2. Variant类型转换: 这是非常重要的部分,后面所有函数的讲解,都要依据此部分的功能
PI SDK的大部分函数所需要的参数,都要转换成variant类型,有的传递variant指针,有的传递引用,有的传递二级指针。下面的转换工作将为您展示如何将字符串类型的指针转换成variant类型:
在C++中,字符串指针一般会使用bstr指针类,我们使用这个类型作为例子,进行转换:
- _bstr_t start = "*-2h"; // 字符串类起始时间
- _variant_t starttime = (_variant_t)start; // variant类起始时间
上面是比较简单的方法,直接做的指针类型强制转换。
下面是做更加通用的方法:
- _bstr_t start = "*-2h"; //起始时间字符串
- _PITimeFormatPtr spStart; // 定义PI时间格式指针
- spStart.CreateInstance(__uuidof(PITimeFormat)); // 指针实例化
- spStart->InputString = start; // 指针指向起始时间字符串
- VariantInit // 初始化variant指针
- V_VT (&starttime) = VT_DISPATCH; // 在variant内部类中进行通用指针转换
- V_DISPATCH(&starttime) = spStart; // 使用dispatch函数,将variant指针指向PI时间格式指针
- 除了PI的时间,PI的服务器名,PI点名等等,基本都是用这种方法进行格式转换。
有了这部分内容后,后面各个函数将省略参数类型转换的功能。
功能一:取某一时间段的值(对应PI Datalink中的compressed data功能)
- static _PIValuesPtr CompressedData (PIPointPtr spPoint, _variant_t starttime, _variant_t endtime)
- {
- return spPoint->Data->RecordedValues(&starttime, &endtime, BoundaryTypeConstants::btAuto, "", FilteredViewConstants::fvRemoveFiltered, NULL);
- }
这个函数看似简单,但其中的参数需要说明:
a. 参数starttime和endtime,都是variant &(引用)
b. BoundaryTypeConstants和FilteredViewConstants分别对应的功能就是PI Datalink中的边界类型和标记过滤值的功能
c. 比较不明显的,在参数中,有""参数,它代表的就是PI Datalink中的过滤条件,因为现在为测试,所以过滤条件在这里没有体现
功能二:按标准时间间隔显示数据(对应PI Datalink中的采样数据)
- static _PIValuesPtr SampledData (PIPointPtr spPoint, _variant_t starttime, _variant_t endtime)
- {
- return sampled->InterpolatedValues2(&starttime, &endtime, &vtinterval, "", FilteredViewConstants::fvRemoveFiltered, NULL);
- }
此使用的参数与前面一个基本相同,只是多了一个&vtinterval,这个参数同样是variant的引用,意义是采样频率。
功能三:数据计算,这部分使用数据在一段时间内,以一个采样频率求和的功能,其他的,类似最大值,最小值等,基本都是使用类似的方法
- void GetSummariesValues(PIPointPtr spPIPoint, _variant_t vtStart, _variant_t vtEnd, _bstr_t interval)
- {
- IPIData2Ptr ipdata2 = (IPIData2Ptr)spPIPoint->Data; // 使用PIData2接口类指针
- _NamedValuesPtr summary = ipdata2->Summaries2(vtStart, vtEnd,interval, ArchiveSummariesTypeConstants::asTotal,CalculationBasisConstants::cbEventWeighted,NULL); // 定义NamedValues指针类
- _variant_t reference = "Total";
- VARIANT vt_Item = reference; // 转换指针为引用
- NamedValuePtr total = summary -> GetItem(&vt_Item);
- spPIValues = (_PIValuesPtr)total->Value;
- }
这个函数略微有点复杂,原因在于,需要计算的,如和,最大值,最小值,方差等的信息,都存在NamedValues指针类。同时,我们看到了variant指针和variant引用之间的转换方式。
在NamedValue指针类中,使用summary函数,将给定PI点按照时间段和采样频率进行求和。
功能四:取值
刚才所有的功能,返回的值都是PIValues,也就是类似于一个数组,下面的功能是遍历这个数组中的每一个数:
- for(long i = 1; i <= spPIValues->Count; i++)
- {
- _PIValuePtr spPIValue = spPIValues->GetItem(i);
- }
这个做法很通俗,就不多讲了
功能五:数据更新,在此,默认数据类型是浮点型32位
- HRESULThr = spPIPoint->Data->UpdateValues(spPIValues, DataMergeConstants::dmInsertDuplicates, NULL);
数据更新的功能是向PI服务器更新或插入数据,这个函数的使用需要比较小心。
首先,在使用这个函数之前,接口与数据源的数据传递应符合数据源的数据传递协议。当数据到达快照之后,应先使用_PIValuePtr spPIValue = spPIPoint->Data->GetSnapshot()
获取点的数据;之后使用
spPIValues->put_ReadOnly(
false
)将PIValues
指针类的写权限打开;然后,
spPIValues->Add(
"*"
,spPIValue
->Value.fltVal + 1,spNVValAttr)将刚才的值写入PIValues
指针类;最后,
spPIValues->put_ReadOnly(
true
)将只读打开。
经过上述描述,相信大家已经明白数据更新的过程了。需要说明的是,
可以容纳很多的数据,也就是说,PIValues
指针类UpdateValues
可以支持多点的同时更新。
除了数据的插入,这个函数还可以用作数据替换。您可能已经注意到了dmInsertDuplicates
这个参数,同样,如果这个参数被替换成:dmReplaceDuplicates,那么,实现的功能就是替换给定时间的数据。这个时间的设定,就是在spPIValues->Add(
"*"
,
中,“*” 表示当前时间,同样,可以使用具体的时间戳进行替换,不过必不可少的就是variant类型的转换。spPIValue
->Value.fltVal + 1,spNVValAttr)
功能六:数据输出更新
PI系统的数据传输更新用于向外发送数据,主要使用EVENTPIPE这个工具。如果使用之传输数据,要分两步走
1. 创建EVENTPIPE
- static IEventPipe2Ptr Get_EventPipe (_PointListPtr spPointList)
- {
- IEventPipe2Ptr spEventPipe2 = (IEventPipe2Ptr)spPointList->Data->EventPipe; // 需要使用 IEventPipe2Ptr类型的指针,并且需要已经定义好的点表作为参数,用来明确需要哪些点的数据更新
- spEventPipe2->PollInterval = 2000; // 数据更新频率,单位毫秒
- return spEventPipe2; // 返回这个指针
- }
2. 获取数据:
- void GetValue_EventPipe (EventPipePtr spEventPipe)
- {
- while (spEventPipe->Count > 0)
- {
- _PIEventObjectPtr spEventObject = spEventPipe->Take(); // 定义一个PIEventObject类型的指针,获取刚才定义好的EVENTPIPE中的数据
- PointValuesPtr spPointValue = spEventObject->EventData; // 将这个数据传递给PointValues指针参数
- }
- }
EVENTPIPE的作用就像一个队列,可以将不同点,不同时间的数据进行存储,当有客户端需要数据时,就把这些数据一次性直接给这个客户端。
注释一:PI服务器的值,在C++中的处理
PI中存储的值,在C++中是以variant类型存在的,因此,如果需要普通类型的值,可以使用如下的例子,这个例子是OSIsoft德国办公室资深工程师Andreas写的,您可以浏览他的博客,本贴只是加中文注释
MyPIValue::MyPIValue (_PIValuePtr pv) { // 将PI的值指针传递进该类,并且对值指针中所包含的内容进行归类分解
codtTimeStamp = pv->TimeStamp->LocalDate;
bstrTimeStamp = (_bstr_t)codtTimeStamp.Format(_T("%d-%b-%Y %H:%M:%S"));
DigitalStatePtr tmpDigitalState = NULL;
IDispatchPtr tmpDispatch = NULL;
_PITimePtr tmpPITime = NULL;
COleDateTime tmpTS;
HRESULT hr = E_FAIL;
_variant_t vT = pv->Value; // 过去值指针中的点的数据
vt = vT.vt;
switch (vT.vt) {
case VT_I4: // variant VT_I4类存储的是整形32位
// Int32
intValue = vT.lVal;
dblValue = intValue;
bstrValue = (_bstr_t)intValue;
break;
case VT_I2: // variant VT_I2类存储的是整形16位
// Int16
intValue = vT.iVal;
dblValue = intValue;
bstrValue = (_bstr_t)intValue;
break;
case VT_R8: // variant VT_R8类存储的是浮点形64位
// Float64
dblValue = vT.dblVal;
intValue = (int)dblValue;
bstrValue = (_bstr_t)dblValue;
break;
case VT_R4: // variant VT_R4类存储的是浮点形32位
// Float16/Float32
dblValue = vT.fltVal;
intValue = (int)dblValue;
bstrValue = (_bstr_t)dblValue;
break;
case VT_BSTR: // variant VT_BSTR类存储的是字符串类
// String
bstrValue = vT.bstrVal;
dblValue = 0;
intValue = 0;
break;
case VT_DISPATCH: // variant VT_DISPATCH类存储的是数字类型,这是最复杂的
// Digital? // 首先需要拿到数字类型表示的内容
tmpDispatch = vT.pdispVal;
hr = tmpDispatch.QueryInterface(__uuidof(DigitalState),&tmpDigitalState);
if (hr == S_OK) {
bstrValue = tmpDigitalState->Name;
intValue = tmpDigitalState->Code;
dblValue = intValue;
}
// Timestamp? // 然后然后获取数字类型值的时间戳
hr = tmpDispatch.QueryInterface(__uuidof(_PITime),&tmpPITime);
if (hr == S_OK) {
tmpTS = tmpPITime->LocalDate;
bstrValue = (_bstr_t)tmpTS.Format(_T("%d %B %Y %H:%M:%S"));
intValue = 0;
dblValue = 0;
}
break;
default :
dblValue = 0.0;
intValue = 0;
bstrValue = "n/a";
break;
}
};
注释二:后续工作---指针清空,关闭COM
为了保证没有内存泄露的情况,在程序的最后,需要清空指针,还要进行:
- ::CoUninitialize();
用于关闭COM LIBARAY
以上是各个功能模块的介绍,下面是一个用PI SDK进行求和工作的完整程序,也是推荐的程序结构方式:
- #include "stdafx.h"
- #include <iostream>
- #include <string>
- #include "ATLComTime.h" //for COleDateTime
- #import "C:\Program Files\PIPC\PISDK\PISDKCommon.dll" no_namespace
- #import "C:\Program Files\PIPC\PISDK\PITimeServer.dll" no_namespace
- #import "C:\Program Files\PIPC\PISDK\PISDK.dll" rename("Connected", "PISDKConnected") no_namespace
- VOID WINAPI Sleep(_In_ DWORD dwMillisecons); // 以上为程序头文件
- class MyPIValue // 建立一个PIValue的默认类
- {
- _PIValuePtr spPIValue;
- public:
- MyPIValue (_PIValuePtr);
- double dblValue;
- int intValue;
- _bstr_t bstrValue;
- _bstr_t bstrTimeStamp;
- COleDateTime codtTimeStamp;
- VARTYPE vt;
- };
- MyPIValue::MyPIValue (_PIValuePtr pv) { // 建立一个翻译PIValue的类
- codtTimeStamp = pv->TimeStamp->LocalDate;
- bstrTimeStamp = (_bstr_t)codtTimeStamp.Format(_T("%d-%b-%Y %H:%M:%S"));
- DigitalStatePtr tmpDigitalState = NULL;
- IDispatchPtr tmpDispatch = NULL;
- _PITimePtr tmpPITime = NULL;
- COleDateTime tmpTS;
- HRESULT hr = E_FAIL;
- _variant_t vT = pv->Value;
- vt = vT.vt;
- switch (vT.vt) {
- case VT_I4:
- // Int32
- intValue = vT.lVal;
- dblValue = intValue;
- bstrValue = (_bstr_t)intValue;
- break;
- case VT_I2:
- // Int16
- intValue = vT.iVal;
- dblValue = intValue;
- bstrValue = (_bstr_t)intValue;
- break;
- case VT_R8:
- // Float64
- dblValue = vT.dblVal;
- intValue = (int)dblValue;
- bstrValue = (_bstr_t)dblValue;
- break;
- case VT_R4:
- // Float16/Float32
- dblValue = vT.fltVal;
- intValue = (int)dblValue;
- bstrValue = (_bstr_t)dblValue;
- break;
- case VT_BSTR:
- // String
- bstrValue = vT.bstrVal;
- dblValue = 0;
- intValue = 0;
- break;
- case VT_DISPATCH:
- // Digital?
- tmpDispatch = vT.pdispVal;
- hr = tmpDispatch.QueryInterface(__uuidof(DigitalState),&tmpDigitalState);
- if (hr == S_OK) {
- bstrValue = tmpDigitalState->Name;
- intValue = tmpDigitalState->Code;
- dblValue = intValue;
- }
- // Timestamp?
- hr = tmpDispatch.QueryInterface(__uuidof(_PITime),&tmpPITime);
- if (hr == S_OK) {
- tmpTS = tmpPITime->LocalDate;
- bstrValue = (_bstr_t)tmpTS.Format(_T("%d %B %Y %H:%M:%S"));
- intValue = 0;
- dblValue = 0;
- }
- break;
- default :
- dblValue = 0.0;
- intValue = 0;
- bstrValue = "n/a";
- break;
- }
- };
- IPISDKPtr spPISDK = NULL; /* The PISDK */ // 初始化所有需要用的指针
- PISDKVersionPtr spSDKVersion = NULL; /* PI SDK Version */
- ServerPtr spServer = NULL; /* The Server */
- PIPointPtr spPIPoint = NULL; /* The PI Point */
- _PIValuePtr spPIValue = NULL;
- _PIValuesPtr spPIValues = NULL; /* The PI value */
- _PITimeFormatPtr spStartTime = NULL;
- _PITimeFormatPtr spEndTime = NULL;
- void GetSummariesValues(PIPointPtr spPIPoint, _variant_t vtStart, _variant_t vtEnd, _bstr_t interval) // 创建子函数
- {
- IPIData2Ptr ipdata2 = (IPIData2Ptr)spPIPoint->Data;
- _NamedValuesPtr summary = ipdata2->Summaries2(vtStart, vtEnd,interval, ArchiveSummariesTypeConstants::asTotal,CalculationBasisConstants::cbEventWeighted
- ,NULL);
- _variant_t reference = "Total";
- VARIANT vt_Item = reference;
- NamedValuePtr total = summary -> GetItem(&vt_Item);
- spPIValues = (_PIValuesPtr)total->Value;
- for (long i = 1; i <= spPIValues->Count; i++)
- {
- spPIValue = spPIValues->GetItem(i);
- MyPIValue t(spPIValue);
- std::cout << t.bstrTimeStamp << " ";
- std::cout << t.bstrValue << std::endl;
- }
- total.Release();
- summary.Release();
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- // Initialize COM
- ::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);
- // Check the command line switches
- if (argc < 6) {
- std::cout << "Command Line:" << std::endl
- << (_bstr_t)argv[0] << " SERVERNAME TAGNAME starttime endtime interval";
- return (1);
- }
- try
- {
- // Create an instance of the PI SDK // 主函数中连接PI服务器,也可使用子函数调用的方式
- spPISDK.CreateInstance(__uuidof(PISDK));
- // Print out the PI SDK version
- spSDKVersion = spPISDK->PISDKVersion;
- std::cout << std::endl << "PI-SDK Version "
- << spSDKVersion->Version << " Build "
- << spSDKVersion->BuildID << std::endl;
- // get the PI Server
- spServer = spPISDK->GetServers()->GetItem((_bstr_t)argv[1]); // 从输入参数1中获取PI服务器名
- spPIPoint = spServer->PIPoints->GetItem((_bstr_t)argv[2]); // 从输入参数2中获取点名
- spStartTime.CreateInstance (__uuidof(PITimeFormat));
- spEndTime.CreateInstance (__uuidof(PITimeFormat));
- spStartTime->InputString = argv[3]; // 从输入参数3中获取起始时间
- spEndTime->InputString = argv[4]; // 从输入参数4中获取截止时间
- _bstr_t interval = argv[5]; // 从输入参数5中获取采样频率
- _variant_t vtStart;
- VariantInit (&vtStart);
- V_VT (&vtStart) = VT_DISPATCH;
- V_DISPATCH(&vtStart) = spStartTime;
- _variant_t vtEnd;
- VariantInit (&vtEnd);
- V_VT (&vtEnd) = VT_DISPATCH;
- V_DISPATCH(&vtEnd) = spEndTime;
- GetSummariesValues(spPIPoint, &vtStart, &vtEnd, interval);
- // You can use more than just one tagname
- /*for (int ii = 2; ii< argc; ii++) {
- // Tagname
- std::cout << (_bstr_t)argv[ii] << std::endl;
- spPIPoint = spServer->PIPoints->GetItem((_bstr_t)argv[ii]);
- // Snapshot
- spPIValue = spPIPoint->Data->Snapshot;
- MyPIValue mPV(spPIValue);
- std::cout << mPV.bstrTimeStamp << " ";
- std::cout << mPV.bstrValue << std::endl;
- }*/
- V_VT (&vtStart) = VT_EMPTY;
- spStartTime.Release();
- V_VT (&vtEnd) = VT_EMPTY;
- spEndTime.Release(); // 以下为指针释放,整个程序中最需要注意的部分
- spPIValue.Release();
- spPIValues.Release();
- spPIPoint.Release();
- spSDKVersion.Release();
- spPISDK.Release();
- }
- catch( _com_error Err )
- {
- std::cout << "Error: "
- << Err.Description()
- << " : "
- << Err.Error()
- << std::endl;
- return (1);
- }
- Sleep(5000);
- return 0;
- }
PI Square中文论坛: PI SDK 开发中级篇| PI Square的更多相关文章
- ESP8266 SDK开发: 外设篇-GPIO输入检测
前言 官方提供了以下函数检测引脚输入状态 检测GPIO5 if( GPIO_INPUT_GET(5) == 0 ) GPIO5当前为低电平 if( GPIO_INPUT_GET(5) == 1 ) G ...
- ESP8266 SDK开发: 外设篇-GPIO输出高低电平
前言 官方提供了两个函数 GPIO_OUTPUT_SET(gpio_no, bit_value) 设置GPIO2输出高电平 GPIO_OUTPUT_SET(2, 1); 设置GPIO2输出低电平 GP ...
- ESP8266 SDK开发: 外设篇-串口
串口分布 串口切换说明 1.默认所有的数据都使用串口0输出 官方提供了函数可以选择printf利用哪一个串口输出 配置printf使用串口1打印输出,波特率115200 (注:这样配置对于调试程序很有 ...
- MATLAB中文论坛帖子整理(GUI)
MATLAB中文论坛帖子整理(GUI) 目 录 1.GUI新手之——教你读懂GUI的M文件... 10 2.GUI程序中改变current directory引起的问题... 15 3.GUI中 ...
- Kinect for Windows SDK开发学习相关资源
Kinect for Windows SDK(K4W)将Kinect的体感操作带到了平常的应用学习中,提供了一种不同于传统的鼠标,键盘及触摸的无接触的交互方式,在某种程度上实现了自然交互界面的理想,即 ...
- wordpress及其simple_press插件完成 的中文论坛
wordpress 及 其simple_press插件的论坛功能 开发准备: 一直从事java及as3方面的开发,首次听同事提起PHP的wordpress,于是上网查了下, 才知道这款软件的强大,转而 ...
- TortoiseSVN安装以及淘宝 TAE SDK 开发环境的搭建
一.TortoiseSVN 的下载和安装 1.进入TortoiseSVN 官网下载地址http://tortoisesvn.net/downloads.html,根据自己的操作系统位数下载相应最新版本 ...
- matlab中文论坛视频谷普教程MATLAB压缩包介绍
matlab中文论坛视频谷普教程MATLAB压缩包介绍 我也正在学习这个软件 ,看到这个教程就在这里分享了,希望大家喜欢!Matlab 初学者视频教学1. Matlab视频:Matlab中文论坛为新手 ...
- TI CC1310 sub1G的SDK开发之入门
CC1310是TI新出的一款sub1G射频模块,具体参数见数据手册吧,这款芯片的SDK跑的是rtos系统,是基于free-rtos定制的ti-rtos,多任务运行.芯片集成了两个核,一个M3做控制MU ...
随机推荐
- mysql 批量kill
select concat('kill ',id,';') t from information_schema.processlist order by t
- Ubuntu 12.04不能在華碩F81se系列電腦上安裝解决辦法
本人華碩F81se系列的電腦,剛開始是裝的ubuntu 10.04的系統,周末閑的無聊,就想把系統換成ubuntu 12.04的,從ubuntu官網上下載了12.04的安裝包,下了個usb insta ...
- ___security_cookie机制
.text:00411500 ; int __cdecl wmainCRTStartup().text:00411500 _wmainCRTStartup proc near ...
- 测试那些事儿—浅谈TCP/IP协议
TCP/IP协议是一系列网络协议的总和,是构成网络通信的核心骨架. TCP/IP的工作原理通俗的讲就是一个主机的数据要经过哪些过程才能发送到对方的主机上. TCP/IP协议采用四层结构,分别为应用层, ...
- ccf-170902-公共钥匙盒(模拟)
这是一道典型的模拟题 首先我们把借钥匙和还钥匙切分成两个事件 保存于两个数组中 然后我对还钥匙的活动按照时间发生次序和还得钥匙序号排序,即按照题意对事件发生的次序排序 最后按照时间的进行 一个一个进行 ...
- 简单说明 Virtual DOM 为啥快
Virtual DOM 就是用 JS 的对象来描述 DOM 结构的一个 DOM 树.如: var element = { tagName: 'ul', // 节点标签名 props: { // DOM ...
- pageContext中page、request、session、application四种范围变量的用法。
在PageContext中有很多作用域 第一种:PageContext.PAGE_SCOPE适用于当前页面的作用域,其接受数据的代码是pageContext.getAttribute();访问页面也是 ...
- Lucene&Solr(索引) 暂空
1.案例分析:什么是全文检索,如何实现全文检索 2.Lucene实现全文检索的流程 a) 创建索引 b) 查询索引 3.配置开发环境 4.创建索引库 5.查询索引库 6 ...
- Docker快速搭建PHP+Nginx+Mysql环境(https://notemi.cn/docker-quickly-set-up-php-nginx-mysql-environment.html)
目录 1 · 目标 2 · 安装Docker 3 · 创建资源文件夹 4 · 部署Mysql · 1. 拉取镜像 · 2. 运行容器 · 3. 进入容器 · 4. 开启Mysql远程连接 5 · 部署 ...
- MySQL Binlog信息查看
##=====================================## ## 在MySQL内部查看binlog文件列表 ## SHOW BINARY LOGS; ##=========== ...