DM Logmnr是达梦数据库的日志分析工具,包括JNI接口和C接口,DM Logmnr JNI接口由位于DM安装目录的jar文件夹下com.dameng.logmnr.jar包提供,logmnr.jar包括LogmnrDll和LogmnrRecord两个类。LogmnrDll提供日志挖掘分析的所有接口,LogmnrRecord用于存放调用LogmnrDll日志分析后的结果数据(日志分析结果数据保存在LogmnrRecord的成员变量中)。
在使用 Logmnr 包中的接口之前,需要先开启两个日志相关参数:一是开启归档(设置
INI 参数 ARCH_INI 为 1);二是开启在日志中记录逻辑操作的功能(设置 INI 参数
RLOG_APPEND_LOGIC 为 1、2 或者 3)。
在SYSDBA用户下创建t_testlogmnr表,插入表数据,并测试更新和删除和truncate操作,sql语句如下:
create table t_testlogmnr(id int,name varchar(50));
insert into t_testlogmnr values(1,'杨明');
insert into t_testlogmnr values(2,'达梦');
insert into t_testlogmnr values(3,'测试');
insert into t_testlogmnr values(4,'韩梅梅');
insert into t_testlogmnr values(5,'李四');
insert into t_testlogmnr values(6,'王五');
insert into t_testlogmnr values(7,'Jack');
update t_testlogmnr set id=id+10 where id<10;
delete t_testlogmnr where id in(11,12);
commit;
truncate table t_testlogmnr;
更新归档
alter system ARCHIVE log current;
查看归档,此时查看V$ARCHIVED_LOG视图可获取最新归档日志(序列号最大的为最新归档日志),假设获取的最新归档日志为“F:\dmdbms_190Pack4\data\DAMENG\arch_local\ARCHIVE_LOCAL1_0x5D02A98E[0]_2021-06-24_15-56-09.log”
select sequence# seq, name , to_char(first_time,'yyyy-mm-dd hh24:mi:ss') first_time, to_char(next_time,'yyyy-mm-dd hh24:mi:ss') next_time, first_change# , next_change# from v$archived_log;
LogmnrDll类定义的是静态方法,所有方法都可以直接通过类名方式调用。详细接口参数说明可参考《DM8程序员手册》。
接口调用步骤讲解DM LOGMNR JNI接口的使用方法。
函数原型 | 功能说明 | 参数说明 | 返回值 |
int LogmnrDll.initLogmnr(); | 初始化 LOGMNR 环境。 | 无。 | 0:初始化成功; < 0 的值和异常:初始化失败。 |
long LogmnrDll.createConnect(String hostName, int port, String userName, String password); | 创建一个分析日志的连接。 | hostName:ip 或主库名。 port:端口号。 userName:用户名。 password:密码。 | 创建的数据库连接标识 ID |
int LogmnrDll.addLogFile(long connId, String logFileName, int option); | 添加需要分析的归档日志文件。 | connId:数据库连接标识 ID。 logFileName:需要分析的归档日志文件名(绝对路径)。 option:可选配置参数。包括以下值: 1:结束当前日志挖掘(隐式调用 endLogmnr,以前添加的归档日志文件将被清除), 并增加新的归档日志文件。 2:删除日志文件。 3:增加的归档日志文件名。 | 0:添加成功; < 0 的值和异常:添加失败。注意事项 如果当前已经 startLogmnr,则 addLogFile 将报错,如果需要添加新的日志文件,需要 先调用 endLogmnr 结束当前日志分析后再添加文件。 |
int LogmnrDll.removeLogFile(long connId, String logFileName); | 移除指定的归档日志文件。 | connId:数据库连接标识 ID。 logFileName:需要移除档日志文件名(绝对路径)。 | 0:移除成功; < 0 的值和异常:移除失败。同 addLogFile 一样,如果当前已经 startLogmnr,则 removeLogFile 将报错,如果需要移 除日志文件,需要先调用 endLogmnr 结束当前日志分析后再移除文件。 |
int LogmnrDll.startLogmnr(long connId, long trxid, String startTime, String endTime); | 启动当前会话的归档日志文件分析,对添加的归档日志文件进行日志分析。 | connId:数据库连接标识 ID。 trxid:分析归档日志的事务 id 号,默认为-1,表示不区分事务号。 startTime:分析归档日志的起始时间,默认 1988/1/1。 endTime:分析归档日志的结束时间,默认 2110/12/31。 | 0:启动成功; < 0 的值和异常:启动失败。 |
LogmnrRecord[]LogmnrDll.getData(long connId, int rownum); | 获取日志文件分析结果数据。 | connId:数据库连接标识 ID。 rownum:获取行数。 | 获取的 logmnr 记录,为LogmnrRecord 对象数组 |
int LogmnrDll.endLogmnr(long connId, int option); | 终止当前会话的归档日志文件分析。 | connId:数据库连接标识 ID。 options:可选模式如下: 0:清除当前会话的归档日志文件分析环境,再次分析时需要重新 add_logfile。 1:保留当前会话的归档日志文件分析环境,不需要重新 add_logfile。 | 0:终止成功; < 0 的值和异常:终止失败。 |
int LogmnrDll.closeConnect(long connId); | 关闭当前连接,清理字典缓存等。 | connId:数据库连接标识 ID。 | 0:关闭成功; < 0 的值和异常:关闭失败。 |
boolean LogmnrDll.deinitLogmnr(); | 销毁 LOGMNR 环境。 | 无。 | 0:添加销毁; < 0 的值和异常:销毁失败。 |
int LogmnrDll.setAttr(long connId, int attr, int attr_value) | 设置属性。 有如下三个属性可以配置: LogmnrDll.LOGMNR_ATTR_PARALLEL_NUM 并行线程数 有效值(2, 16); LogmnrDll.LOGMNR_ATTR_BUFFER_NUM 任务缓存节点数 有效值(8, 1024); LogmnrDll.LOGMNR_ATTR_CONTENT_NUM 结果缓存节点数 有效值(256, 2048)。 | connId:数据库连接标识 ID。 attr:属性名。 attr_value:属性值。 | 0:添加成功; < 0 的值和异常:添加失败。 |
LogmnrRecord 对象支持的成员变量如下表所示。获取和设置这些变量可以使用相应的
“get+成员变量”和“set+成员变量”方法。
成员 | 变量 | 类型 说明 |
scn | long | 当前记录的 LSN |
startScn | long | 当前事务的起始 LSN |
commitScn | long | 当前事务的截止 LSN |
timestamp | String | 当前记录的创建时间 |
startTimestamp | String | 当前事务的起始时间 |
commitTimestamp | String | 当前事务的截止时间 |
xid | String | 当前记录的事务 ID 号 |
operation | String | 操作类型包括 start、insert、update、delete、commit、rollback 等语句 |
operationCode | String | 操作类型。插入操作值为 1,更新操作值为 3,删除操作值为 2,事务起始语句值为 6,提交操作值为7,回滚操作值为 36 |
rollBack | int | 当前记录是否被回滚(1 是 0 否) |
segOwner | String | 执行这条语句的用户名 |
tableName | String | 操作的表名 |
rowId | String | 对应记录的行号 |
rbasqn | int | 对应的归档日志文件号 |
rbablk | int | RBASQN 所指日志文件的块号从 0 开始 |
rbabyte | int | RBABLK 所指块号的块内偏移 |
dataObj | int | 对象 ID 号 |
dataObjv | int | 对象版本号 |
sqlRedo | String | 当前记录对应的 sql 语句 |
rsId | Stirng | 记录集 ID |
ssn | int | 连续 sql 标志。如果 sql 长度超过单个 sql_redo 字段能存储的长度,则 sql 会被截断成多个 sql 片段在结果集中“连续”返回 |
csf | int | 与 SSN 配合。最后一个片段的 csf 值为 0,其余片段的值均为 1。没因超长发生截断的 sql 该字段值均为 0 |
status | int | 日志状态。默认为 0 |
在Eclipse界面将com.dameng.logmnr.jar包添加到程序中。在Eclipse工程中,右键工程选择【构建路径】->【配置构建路径】,打开JAVA构建配置页面,在“库(Library)”页签中,点击【添加外部JAR】,选择com.dameng.logmnr.jar包,并选择本地库位置(因Logmnr是JNI接口,运行时需调用达梦动态库dll文件,所以需要配置本地库路径,否则无法正常运行),点击【编辑】,填写达梦数据库(驱动)安装bin目录,依次点击【确定】。如下图所示。
在JAVA工程中新建TestLogmnr类,代码中指定需要分析的归档日志文件“F:\dmdbms_190Pack4\data\DAMENG\arch_local\ARCHIVE_LOCAL1_0x5D02A98E[0]_2021-06-24_15-56-09.log”,并将分析的归档日志结果数据输出至文件“F:\dmdbms_190Pack4\result.txt”中,每一行表示一个操作语句,不同属性用“|”分割,换行符为“回车换行”,代码参考如下。
package cn.com.test;
import java.io.File;
import java.io.FileOutputStream;
import com.dameng.logmnr.LogmnrDll;
import com.dameng.logmnr.LogmnrRecord;
public class dbmslog {
public static void main(String[] args) {
try
{
//初始化LOGMNR环境
LogmnrDll.initLogmnr();
//创建连接
long connid = LogmnrDll.createConnect("localhost", 5230, "SYSDBA", "SYSDBA");
//添加归档日志文件
LogmnrDll.addLogFile(connid,"F:\\dmdbms_190Pack4\\data\\DAMENG\\arch_local\\ARCHIVE_LOCAL1_0x5D02A98E[0]_2021-06-24_15-56-09.log",3);
//启动日志分析
LogmnrDll.startLogmnr(connid, -1, null, null);
//获取数据
LogmnrRecord[] arr = LogmnrDll.getData(connid, 100);
/* 将获取的归档日志信息输出至文件中 */
File file = new File("F:\\dmdbms_190Pack4\\result.txt");
FileOutputStream out = new FileOutputStream(file);
StringBuffer sb = new StringBuffer();
String lineendstr = "\r\n";//定义转换字符
String split = "|";//定义分隔符
//定义表头
sb.append("Xid|Operation|OperationCode|Scn|StartScn|CommitScn|Timestamp"
+ "|SegOwner|TableName|RowId|Rbasqn|rsId|sqlRedo"+lineendstr);
System.out.println("日志分析结果打印:");
for (int i = 0; i < arr.length; i++) {
//if(arr[i].getTableName().equals("T_TESTLOGMNR")){
sb.append(arr[i].getXid()+split);
sb.append(arr[i].getOperationCode()+split);
sb.append(arr[i].getOperation()+split);
sb.append(arr[i].getScn()+split);
sb.append(arr[i].getStartScn()+split);
sb.append(arr[i].getCommitScn()+split);
sb.append(arr[i].getTimestamp()+split);
sb.append(arr[i].getSegOwner()+split);
sb.append(arr[i].getTableName()+split);
sb.append(arr[i].getRowId()+split);
sb.append(arr[i].getRbasqn()+split);
sb.append(arr[i].getRsId()+split);
sb.append(arr[i].getSqlRedo()+lineendstr);
//}
}
System.out.println("结果打印完毕");
out.write(sb.toString().getBytes("GBK"));
out.flush();
out.close();
LogmnrDll.endLogmnr(connid, 0);
LogmnrDll.closeConnect(connid);
LogmnrDll.deinitLogmnr();
}catch (Exception e) {
e.printStackTrace();
}
}
}
运行后生成的本地文件如下: