Mybatis 获取最终可执行SQL语句

一、问题提出

从且只从一个PreparedStatement中获取执行的sql语句(包括运行时绑定的参数值),是实际工作中经常遇到的一个问题。

网上很多文章提到用自定义的增强类或中间件(p6spy, log4jdbc)来实现,但这需要对现有代码进行修改,工作量很大,能不能有更直接的办法?

由于java.sql.PreparedStatement并没有提供相应接口,此功能是否实现及如何实现,不同数据库的JDBC是不一样的。PostgreSQL和MySQL的DBC用toString接口实现了此功能;但对于Oracle,问题比较棘手。

二、PostgreSQL和MySQL

PostgreSQL和MySQL可以直接使用toString接口获取sql,且会得到绑定的参数值。两者的区别在于:MySQL会在前面加上类名。

PreparedStatement ps = con.prepareStatement("SELECT value from sys_param where name=?");
ps.setString(1, "UNIT_CODE");
System.out.println(ps.toString());

PostgreSQL的输出是:SELECT value from sys_param where name=‘UNIT_CODE’,可以直接使用。

MySQL的输出是:com.mysql.cj.jdbc.ClientPreparedStatement: SELECT value from sys_param where name=‘UNIT_CODE’,此时,只需将“: ”前部分截断即可。

但Oracle的输出则是:oracle.jdbc.driver.OraclePreparedStatementWrapper@7b98f307,无法使用。

三、Oracle

经过仔细分析Oracle JDBC的类,发现oracle.jdbc.internal.OraclePreparedStatement(注意不能是oracle.jdbc.OraclePreparedStatement)提供了一个接口getOriginalSql()。用它进行尝试:

    PreparedStatement ps = con.prepareStatement("SELECT value from sys_param where name=?");
    ps.setString(1, "UNIT_CODE");
    if (ps instanceof OraclePreparedStatement) {
   
   
        OraclePreparedStatement ops = (OraclePreparedStatement)ps;
        System.out.println(ops.getOriginalSql());
    }

输出是:SELECT value from sys_param where name=?,只差绑定的参数值了。

那么,能不能进一步将绑定参数也解析出来?从目前掌握的信息看,Oracle还做不到。

四、通用方法
根据以上,可以构造一个从PreparedStatement获取sql的通用方法,如下:

public String getSql(PreparedStatement ps) throws SQLException
{
   
   
    if (ps==null || ps.getConnection()==null)
        return null;
switch (ps.getConnection().getMetaData().getDatabaseProductName().toUpperCase())
    {
   
   
    case "ORACLE":
        OraclePreparedStatement ops 
### 查看 MyBatis 实际执行的 SQL 语句 在开发过程中,为了更好地调试和优化查询性能,开发者通常需要查看由 MyBatis 动态生成的实际 SQL 语句。以下是实现这一目标的主要方法: #### 方法一:通过日志配置输出 SQL MyBatis 支持多种日志框架(如 Log4j、SLF4J 等),可以通过这些框架来记录并打印出实际执行的 SQL 语句。 ##### 配置示例 (Log4j) 如果使用的是 Log4j 日志框架,则可以在 `log4j.properties` 文件中设置如下内容以启用 SQL 输出[^1]: ```properties log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG ``` 上述配置会将 MyBatis 中生成的 SQL 语句以及参数绑定过程打印到控制台或指定的日志文件中。 #### 方法二:利用数据库驱动程序捕获 SQL 某些 JDBC 数据库驱动支持拦截器功能,可以用来捕获发送给数据库服务器的具体 SQL 请求。例如,在 MySQL 连接字符串中添加特定属性即可开启此功能: 连接 URL 示例: ```java jdbc:mysql://localhost:3306/your_database?useServerPrepStmts=false&rewriteBatchedStatements=true&logger=com.mysql.cj.log.Slf4JLogger&profileSQL=true ``` 这里启用了基于 Slf4J 的日志记录机制,并且允许跟踪所有的 SQL 调用链路。 #### 方法三:借助插件工具分析运行时行为 除了调整应用层面上的日志级别外,还可以采用第三方监控软件像 P6Spy 或者.DataSourceProxy 来进一步增强透明度。它们能够自动附加至现有的数据源对象之上从而收集详细的交互细节包括但不限于完整的 DML/DQL 命令及其耗时时长统计信息等. 对于简单的项目来说, 只需引入依赖项便可快速集成: Maven坐标定义样例: ```xml <dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactid> <version>3.x.x</version><!--具体版本号视情况而定--> </dependency> ``` 完成安装之后按照官方文档指示修改相应的配置选项就能达到预期效果. --- ### 示例代码展示 下面给出一段 Java 测试类片段用于验证以上提到的技术手段之一即通过标准输出流观察最终形成的查询表达式: ```java import org.apache.ibatis.session.SqlSession; import com.example.mapper.UserMapper; public class Main { public static void main(String[] args){ try(SqlSession session = MyBatisUtil.getSqlSessionFactory().openSession()){ UserMapper mapper = session.getMapper(UserMapper.class); // 此处调用任意接口触发内部逻辑构建对应关系映射后的SQL串 List<User> users = mapper.selectAllUsers(); System.out.println("Total Records Found:" + users.size()); } } } ``` 注意当设置了合适的 logging level 后每次实例化 Mapper 接口成员函数都会伴随相应描述性的 debug message 显示出来便于后续排查定位潜在问题所在位置.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林志鹏JAVA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值