技术分享:MyBatis SQL 日志解析脚本
- [1. 脚本功能概述](#1. 脚本功能概述)
- [2. 实现细节](#2. 实现细节)
-
- [2.1 HTML 结构](#2.1 HTML 结构)
- [2.2 JavaScript 逻辑](#2.2 JavaScript 逻辑)
- [3. 脚本代码](#3. 脚本代码)
- [4. 使用方法](#4. 使用方法)
-
- [4.1 示例](#4.1 示例)
- [5. 总结](#5. 总结)
在日常开发中,使用 MyBatis 作为持久层框架时,我们经常需要查看 SQL 日志以调试和优化查询。然而,MyBatis 的日志输出通常包含占位符和参数信息,这使得直接执行这些 SQL 语句变得困难。为了解决这个问题,我们开发了一个简单的 HTML 和 JavaScript 脚本,用于解析 MyBatis 的 SQL 日志并生成可执行的 SQL 语句。
1. 脚本功能概述
该脚本的主要功能是:
- 解析 SQL 日志:从 MyBatis 日志中提取 SQL 语句和参数。
- 参数替换 :将 SQL 语句中的占位符
?
替换为实际的参数值。 - 生成可执行 SQL:输出完整的 SQL 语句,便于在数据库中直接执行。
2. 实现细节
2.1 HTML 结构
脚本的 HTML 部分提供了一个简单的用户界面,包含输入区域、解析按钮和输出区域。
- 输入区域:用户可以在此粘贴 MyBatis 的 SQL 日志。
- 解析按钮:点击后触发 JavaScript 函数进行解析。
- 输出区域:显示解析后的可执行 SQL 语句。
2.2 JavaScript 逻辑
JavaScript 部分实现了日志解析的核心逻辑:
- 日志分割:通过换行符将日志分割为多行,逐行处理。
- SQL 语句提取 :识别包含
Preparing:
的行,提取 SQL 语句。 - 参数解析 :识别包含
Parameters:
的行,提取参数并根据类型进行处理。- 字符串和时间戳:用单引号包裹,处理转义字符。
- 空值 :替换为
NULL
。 - 其他类型:直接替换。
- 结果输出:将替换后的 SQL 语句显示在输出区域。
3. 脚本代码
创建一个.html文件,编辑,将脚本内容贴至文件内,保存,用浏览器打开文件即可使用
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mybatis SQL日志解析</title>
<script type="text/javascript">
function f(obj) {
try {
var textVa = obj.value;
var logs = textVa.split('\n'); // Split by newline
var results = [];
var currentStatement = null;
logs.forEach(function(log) {
// Check if this line contains "Preparing:" or "Parameters:"
if (log.indexOf('Preparing:') !== -1) {
if (currentStatement !== null) {
// If we have a current statement, push it to the results
results.push(currentStatement);
}
// Start a new statement
currentStatement = log.substring(log.indexOf('Preparing:') + "Preparing:".length).trim();
} else if (log.indexOf('Parameters:') !== -1 && currentStatement !== null) {
// If we find parameters and have a current statement, parse the parameters
var parametersStr = log.substring(log.indexOf('Parameters:') + "Parameters:".length).trim();
var parameters = parametersStr.split(/,(?![^()]*\))/g); // Use regex to split correctly
for (var i = 0; i < parameters.length; i++) {
var paramValue = parameters[i].trim();
if (paramValue === "null") {
currentStatement = currentStatement.replace("?", "NULL");
} else {
var typeStr = paramValue.substring(paramValue.indexOf("(") + 1, paramValue.indexOf(")"));
paramValue = paramValue.substring(0, paramValue.indexOf("(")).trim();
if (typeStr === "String" || typeStr === "Timestamp") {
paramValue = "'" + paramValue.replace("'", "''") + "'";
}
currentStatement = currentStatement.replace("?", paramValue);
}
}
// Add the final statement to the results and reset currentStatement
results.push(currentStatement);
currentStatement = null;
}
});
// If there's a remaining statement, push it to the results
if (currentStatement !== null) {
results.push(currentStatement);
}
document.getElementById("d1").value = results.join("\n\n");
} catch (e) {
console.error(e);
alert("解析SQL时发生错误:" + e.message);
}
}
function copySQL() {
var SQL = document.getElementById("d1");
navigator.clipboard.writeText(SQL.value).then(function() {
var msg = document.getElementById("msg");
msg.innerHTML = "已复制到剪切板";
setTimeout(function () {
msg.innerHTML = "";
}, 3000);
}).catch(function(err) {
console.error("复制失败:", err);
alert("复制SQL时发生错误:" + err.message);
});
}
function clearLog(obj) {
obj.value = "";
}
</script>
</head>
<body>
<h2><font color="#00bfff"> 输入Mybatis SQL日志:</font></h2>
<textarea id="sqlLog" rows="12" cols="140" style="font-size:12px;font-family: 'CourierNew';font-weight: bold;width: 98%;"></textarea>
<div style="border:0px deepskyblue solid;width:1425px;height:50px;text-align:right;">
<button style="color:mediumblue;width:100px;height:60px" type="button" onclick="clearLog(document.getElementById('sqlLog'))">清空</button>
<button style="color:mediumblue;width:100px;height:60px" type="submit" onclick="f(document.getElementById('sqlLog'))">解析SQL</button>
</div>
<h2><font color="#32cd32">解析为可执行SQL:</font></h2>
<textarea id="d1" rows="12" cols="140" style="font-size:12px;font-family: 'CourierNew';font-weight: bold;width: 98%;"></textarea>
<div style="border:0px deepskyblue solid;width:1425px;height:50px;text-align:right;">
<button style="color:mediumblue;width:100px;height:60px" type="button" onclick="copySQL()">复制SQL</button>
</div>
<div id="msg" style="color:cornflowerblue;border:0px black solid;width:800px;height:20px;text-align:right;font-style: initial;font-size: large"></div>
</body>
</html>
4. 使用方法
- 将 MyBatis 的 SQL 日志粘贴到输入区域。
- 点击"解析SQL"按钮。
- 在输出区域查看并复制解析后的 SQL 语句。
4.1 示例
假设输入的日志为:
Preparing: INSERT INTO users (name, email) VALUES (?, ?)
Parameters: John(String), null
解析后的输出为:
INSERT INTO users (name, email) VALUES ('John', NULL)

5. 总结
通过这个简单的脚本,我们可以快速将 MyBatis 的 SQL 日志转换为可执行的 SQL 语句,极大地方便了开发和调试工作。希望这个工具能对你有所帮助!