问题背景和目的:
我所尝试过的解决方法(没能行得通的)
最终可行的解决方法
2、src/main/resources下配置mybatis-config.xml
3、src/main/resources下配置logj4j.properties
4、进行部分代码覆盖重写,将参数填充至占位符?得到最终想要的结果
问题背景和目的:
问题背景照常还是要说一下的,因为不同的问题,解决方案往往是不同的。
想必很多开发者在debug一个业务的SQL时,参数太多往往降低开发效率,更容易导致出错,这篇博客刚好能提出一个这样的思路,最低成本的解决这个问题,也就是“绿色”方法。讲道理,这个方法应该适用于所有使用log4j作为日志输出的项目开发。
我要达到的目的如下:
==> Preparing: SELECT a."oid", a."delflag" FROM table a WHERE a."delflag" = 1 AND a."oid" = 1
<== Total: 0
我所尝试过的解决方法(没能行得通的)
网上有过加入log4j、slf4j-api全家桶这样成功的案例,我都配置好了,最后报not support oracle driver 1.0,折腾我将近7小时也未能解决这个问题
我尝试通过(网络上寻找的几个解决方法):
①添加tomcat-jdbc的依赖不得解;
②报错原因是因为数据库驱动不支持,更换了ojdbc6、druid版本后依然不得解;
③重新更换pom.xml中所有引入的log4j全家桶版本未网络上一致不得解(网络上的解决方法大多应用于MySQL);
④https://www.oschina.net/question/3739295_2308736中就是我的一些基本配置,通过询问网络也不得解
作罢,我觉得我应该换个思路,之前有瞟过一眼接下来的解决方法,觉得有点野路子,就没去测试。现在有点后悔没用思维导图工具来解决问题了,那样解决思路会清晰的很多,我这也算站在巨人的肩膀上了。
最终可行的解决方法
1、pom.xml添加log4j的依赖
springboot项目与传统的springMVC+Maven有点不同的是,我只添加了这一个log4j的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
2、src/main/resources下配置mybatis-config.xml
<configuration>
<!--
配置文件中各配置的位置必须符合要求,否则会报错,顺序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->
<settings>
<!-- 日志输出 -->
<setting name="logImpl" value="LOG4J2" />
<!-- mapper.xml中替代jdbctype的配置 -->
<setting name="jdbcTypeForNull" value="NULL" />
</settings>
</configuration>
3、src/main/resources下配置logj4j.properties
由于对log4j的研究不是很深,所以这些配置中可能存在错误和冗余项,日后再修改
#logFile
log4j.rootLogger=DEBUG,Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=INFO
log4j.appender.console.ImmediateFlush=true
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss}[%t] %l: %x%m%n
# 日志文件(logFile)
log4j.appender.logFile=org.apache.log4j.FileAppender
log4j.appender.logFile.Threshold=DEBUG
log4j.logger.org.apache=ERROR
log4j.logger.org.mybatis=ERROR
log4j.logger.org.springframework=ERROR
#这个需要
log4j.logger.log4jdbc.debug=ERROR
log4j.logger.jdbc.audit=ERROR
log4j.logger.jdbc.resultset=ERROR
#这个打印SQL语句非常重要
log4j.logger.jdbc.sqlonly=DEBUG
log4j.logger.jdbc.sqltiming=ERROR
log4j.logger.jdbc.connection=FATAL
数据库的配置可能有些朋友需要,这里就不给出怎么配置druid了。
spring:
datasource:
username: system
password: 123456
url: jdbc:oracle:thin:@//127.0.0.1:1521/orcl
driver-class-name: oracle.jdbc.OracleDriver
timeBetweenEvictionRunsMillis: 600000
testOnBorrow: true
testOnReturn: false
testWhileIdle: true
validationQuery: SELECT 1 FROM DUAL # Oracle的连接必须指定一个表名,DUAL是个默认的
validationQueryTimeout: 300000
filters: stat,wall,log4j2
initialSize: 5
minEvictableIdleTimeMillis: 300000
minIdle: 5
maxActive: 10
maxOpenPreparedStatements: 10
maxWait: 600000
poolPreparedStatements: false # 性能开关,可缓存preparedStatement(PSCache),因为Oracle支持游标
到目前的配置,log4j输出的语句应该类似于↓:
==> Preparing: SELECT a."oid", a."delflag" FROM table a WHERE a."delflag" = ? AND a."oid" = ?
==> Parameters: 0(Long), 1(Long)
<== Total: 0
4、进行部分代码覆盖重写,将参数填充至占位符?得到最终想要的结果
由于不懂log4j,以下部分根据一佚名码友提供的思路改写
①随便找个地方import org.apache.ibatis.logging.jdbc.BaseJdbcLogger,从而可打开复制全部内容;
②在src/main/java新建一个目录org.apache.ibatis.logging.jdbc,并new一个class粘贴刚刚复制的代码;
③找到protected void debug(String text, boolean input) 这个方法↓
protected void debug(String text, boolean input) {
if (statementLog.isDebugEnabled()) {
statementLog.debug(prefix(input) + text);
}
}
④将它修改为:(text:是需要打印的文本),这个逻辑可以非常清晰体现思路。(后面有修改201907241912)
protected void debug(String text, boolean input) {
text = text.trim();
if (statementLog.isDebugEnabled()) {
if (text.startsWith("Preparing:")) {
sql = text.substring(text.indexOf(":") + 1);
return;
}
if (text.startsWith("Parameters:")) {
String temp = text.substring(text.indexOf(":") + 1);
String[] split = temp.split(",");
if (split != null & split.length > 0) {
for (String string2 : split) {
String s = string2.trim();
sql = sql.replaceFirst("\\?", s.substring(0, s.indexOf("(")));
}
}
text = "Preparing:" + sql;
sql = "";
}
statementLog.debug(prefix(input) + text);
}
}
======修改为:=========
protected void debug(String text, boolean input) {
text = text.trim();
if (statementLog.isDebugEnabled()) {
if (text.startsWith("Preparing:")) {
sql = text.substring(text.indexOf(":") + 1);
return;
}
if (text.startsWith("Parameters:")) {
String temp = text.substring(text.indexOf(":") + 1);
String[] split = temp.split(",");
if (split != null & split.length > 0) {
for (String string2 : split) {
String s = string2.trim();
String replaceText = " ";
if(s.indexOf("(") == -1) {
//如果参数是null,是没有类型的,也就没有括号,如:33(Long), null,
if("null".equals(s))
replaceText = "NULL";
}else
replaceText = s.substring(0, s.indexOf("("));
sql = sql.replaceFirst("\\?", replaceText);
}
}
text = "Preparing:" + sql;
sql = "";
}
statementLog.debug(prefix(input) + text);
}
}
⑤调试一下可以看到成功了
==> Preparing: SELECT a."oid", a."delflag" FROM table a WHERE a."delflag" = 1 AND a."oid" = 1
<== Total: 0