使用AI 编写一个Mybatis SQL日志解析工具
背景
尝试使用智谱清言 AI 编写一个工具,将Mybatis SQL日志解析为可以执行的SQL语句。
操作
准备初始代码
首先网站上找了一个有BUG的简单的实现 https://blog.csdn.net/x541211190/article/details/107410409
用提示词让AI分析代码
将以上代码贴给AI,并增加提示词分析上面代码的的功能
,让AI分析代码。
分析结果如下:
这段HTML代码定义了一个简单的网页界面,目的是为了解析Mybatis框架的SQL日志,并将其转换为可执行的SQL语句。下面是代码的详细分析:
1. **HTML结构**:- 定义了一个标题“输入Mybatis SQL日志:”,和一个多行文本输入框`<textarea>`用于用户粘贴Mybatis的SQL日志。- 提供了两个按钮,“清空”用于清除文本框内容,“解析SQL”用于触发SQL解析功能。- 另有一个标题“解析为可执行SQL:”,和一个用于显示解析后SQL语句的多行文本框。- 提供了一个“复制SQL”按钮,用于将解析后的SQL语句复制到剪贴板。- 最后有一个`<div>`元素用于显示复制成功的提示信息。
2. **JavaScript功能**:- `f(obj)`函数:此函数接收textarea对象作为参数,提取其中的文本值,然后解析出SQL语句和参数。- 定位SQL语句的开始和结束位置,并提取出来。- 定位参数的开始和结束位置,并提取参数列表。- 遍历参数列表,根据参数的类型(字符串或时间戳为字符串类型,其他为数值类型),替换SQL语句中的占位符`?`。- 将解析后的SQL语句显示在页面上。- `copySQL()`函数:此函数用于将解析后的SQL语句复制到剪贴板。- 通过`select()`方法选择文本。- 使用`document.execCommand("Copy")`执行复制命令。- 显示复制成功的提示信息,并设置3秒后消失。- `clearLog(obj)`函数:此函数用于清空textarea中的内容。
3. **样式**:- 使用内联样式定义了文本框和按钮的大小、颜色等视觉样式。- 使用了`<font>`标签来定义标题的颜色,虽然这不是HTML5推荐的写法,但它仍然有效。
4. **用户交互**:- 用户可以将Mybatis的SQL日志粘贴到第一个文本框。- 点击“解析SQL”按钮后,JavaScript函数会解析日志,并将可执行的SQL语句显示在第二个文本框中。- 用户可以点击“复制SQL”按钮将解析后的SQL语句复制到剪贴板。
整体而言,这个网页界面是一个实用的工具,可以帮助开发者快速从Mybatis的日志中提取并转换出可执行的SQL语句,方便数据库的调试和优化。
用提示词让AI 找出代码的问题
分析解析日志的算法存在哪些问题?
,分析结果如下:
解析日志的算法存在以下问题:
1. **假设日志格式固定**:算法假设日志的格式是固定的,例如,`Preparing:`和`Parameters:`后面的内容格式和位置都是固定的。如果日志格式发生变化,例如空格数不同、换行位置变化或者增加了新的日志信息,算法可能无法正确解析。
2. **缺乏错误处理**:算法中没有错误处理机制。如果日志中不存在`Preparing:`或`Parameters:`,或者格式不正确,算法将无法正常工作,且不会提供任何错误信息。
3. **对参数类型的处理有限**:算法只处理了`String`和`Timestamp`类型的参数,将其用单引号括起来,其他类型直接替换。这种处理方式忽略了其他可能需要特殊处理的类型,例如`Date`或`Boolean`,也没有考虑到数值类型可能需要防止SQL注入的问题。
4. **参数解析不准确**:算法中参数解析的部分使用了`substring`和`indexOf`来提取参数值和类型,但如果参数值本身包含括号或者逗号,这将导致错误的解析。
5. **性能问题**:算法中使用了多次循环和字符串操作来解析日志,这可能在处理大量数据时导致性能问题。
6. **SQL注入风险**:算法直接将参数值替换到SQL语句中,对于数值类型没有进行任何转义或处理,这可能导致SQL注入攻击。
7. **缺乏对复杂SQL语句的支持**:如果SQL语句中本身就包含问号(?),算法会将这些问号错误地认为是参数占位符。
为了改进这个算法,可以考虑以下措施:
- 使用正则表达式来解析日志,这样可以更准确地处理不同格式的日志。
- 添加错误处理逻辑,对于无法解析的日志提供明确的错误信息。
- 对于不同类型的参数,使用适当的处理方式,例如对于数值类型使用参数化查询来防止SQL注入。
- 对于可能包含特殊字符的参数值,使用更可靠的解析方法,例如先提取所有参数,然后根据位置来替换SQL语句中的占位符。
- 提高算法性能,例如通过减少不必要的字符串操作和循环。
- 确保算法能够处理复杂的SQL语句,包括那些本身就包含问号的语句。
用提示词让AI修复代码的指定问题
修复其中的2,3,4,5,7的问题
修复后的结果
<!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('Preparing: '); // Split by "Preparing: "var results = [];logs.forEach(function(log) {// Check if this line contains "Preparing:" or "Parameters:"if (log.indexOf('Preparing:') === -1 && log.indexOf('Parameters:') === -1) {return; // Skip this line if it doesn't contain "Preparing:" or "Parameters:"}// 获取带问号的SQL语句var statementStartIndex = log.indexOf('Preparing: ');if (statementStartIndex !== -1) {var statementStr = log.substring(statementStartIndex + "Preparing: ".length).trim();} else {throw new Error("未找到SQL语句");}// 获取参数var parametersStartIndex = log.indexOf('Parameters: ');if (parametersStartIndex !== -1) {var parametersStr = log.substring(parametersStartIndex + "Parameters: ".length).trim();} else {// If "Parameters:" is not found, we assume there are no parametersparametersStr = "null";}// 解析参数var parameters = parametersStr.split(/,(?![^()]*\))/g); // 使用正则表达式正确分割参数// 替换SQL语句中的占位符for (var i = 0; i < parameters.length; i++) {var paramValue = parameters[i].trim();if (paramValue === "null") {// 如果参数是null,直接替换为NULLstatementStr = statementStr.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("'", "''") + "'";}statementStr = statementStr.replace("?", paramValue);}}results.push(statementStr);});document.getElementById("d1").innerHTML = 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="13" cols="140" style="font-size:20px"></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="13" cols="140" style="font-size:20px"></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>
用提示词让AI 继续分析代码
分析的结果如下:
上面的代码是一个HTML页面,包含JavaScript脚本,用于解析Mybatis SQL日志并生成可执行的SQL语句。具体功能如下:
1. 页面中包含一个文本域(sqlLog),用于输入Mybatis SQL日志。
2. 点击"解析SQL"按钮,会触发f()函数,对输入的SQL日志进行解析。
3. f()函数首先使用split()方法按"Preparing: "分割输入的日志字符串,然后遍历分割后的日志数组。
4. 对于每个日志条目,判断是否包含"Preparing:"或"Parameters:",如果不包含则跳过。
5. 获取带问号的SQL语句和参数,然后解析参数。
6. 对于SQL语句中的每个问号占位符,根据参数的类型替换为实际的参数值。
7. 将解析后的SQL语句显示在另一个文本域(d1)中。
8. 点击"复制SQL"按钮,会触发copySQL()函数,将解析后的SQL语句复制到剪切板。
9. 点击"清空"按钮,会清空sqlLog文本域中的内容。
10. 解析过程中如果发生错误,会弹出错误提示框。
用提示词让AI修改为支持多组日志的版本
需要修改为支持多组Mybatis SQL日志的解析,并且提供的日志中可能有非Mybatis SQL日志的行
。
AI 输出的版本如下:
<!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 newlinevar 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 resultsresults.push(currentStatement);}// Start a new statementcurrentStatement = 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 parametersvar parametersStr = log.substring(log.indexOf('Parameters:') + "Parameters:".length).trim();var parameters = parametersStr.split(/,(?![^()]*\))/g); // Use regex to split correctlyfor (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 currentStatementresults.push(currentStatement);currentStatement = null;}});// If there's a remaining statement, push it to the resultsif (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="13" cols="140" style="font-size:20px"></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="13" cols="140" style="font-size:20px"></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>
测试验证
将代码保存为一个后缀为html
的文件,用浏览器打开,随便复制一段Mybatis SQL日志,测试效果基本没问题。