使用AI 编写一个Mybatis SQL日志解析工具

使用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 parameters
						parametersStr = "null";
					}
					// 解析参数
					var parameters = parametersStr.split(/,(?![^()]*\))/g); // 使用正则表达式正确分割参数
					// 替换SQL语句中的占位符
					for (var i = 0; i < parameters.length; i++) {
						var paramValue = parameters[i].trim();
						if (paramValue === "null") {
							// 如果参数是null,直接替换为NULL
							statementStr = 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 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="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日志,测试效果基本没问题。

  • 25
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值