001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.db; 017 018import com.jfinal.log.Log; 019import com.jfinal.plugin.activerecord.Config; 020import io.jboot.Jboot; 021import io.jboot.utils.DateUtil; 022import io.jboot.utils.StrUtil; 023 024import java.sql.SQLException; 025import java.util.Date; 026import java.util.regex.Matcher; 027 028/** 029 * @author michael yang (fuhai999@gmail.com) 030 * @Date: 2019/12/12 031 */ 032public class SqlDebugger { 033 034 035 private static SqlDebugPrinter printer = SqlDebugPrinter.DEFAULT_PRINTER; 036 037 public static SqlDebugPrinter getPrinter() { 038 return printer; 039 } 040 041 public static void setPrinter(SqlDebugPrinter printer) { 042 SqlDebugger.printer = printer; 043 } 044 045 public static <T> T run(SqlRunner<T> runner, Config config, String sql, Object... paras) throws SQLException { 046 if (!printer.isPrintEnable(config)) { 047 return runner.run(); 048 } else { 049 long timeMillis = System.currentTimeMillis(); 050 try { 051 return runner.run(); 052 } finally { 053 doDebug(System.currentTimeMillis() - timeMillis, sql, paras); 054 } 055 } 056 } 057 058 059 private static void doDebug(Long tookTimeMillis, String sql, Object... paras) { 060 if (paras != null) { 061 for (Object value : paras) { 062 // null 063 if (value == null) { 064 sql = sql.replaceFirst("\\?", "null"); 065 } 066 // number 067 else if (value instanceof Number || value instanceof Boolean) { 068 sql = sql.replaceFirst("\\?", value.toString()); 069 } 070 // numeric 071 else if (value instanceof String && StrUtil.isNumeric((String) value)) { 072 sql = sql.replaceFirst("\\?", (String) value); 073 } 074 // other 075 else { 076 StringBuilder sb = new StringBuilder(); 077 sb.append("'"); 078 if (value instanceof Date) { 079 sb.append(DateUtil.toDateTimeString((Date) value)); 080 } else { 081 sb.append(value); 082 } 083 sb.append("'"); 084 sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(sb.toString())); 085 } 086 } 087 } 088 089 printer.print(sql, tookTimeMillis); 090 } 091 092 093 public interface SqlDebugPrinter { 094 095 SqlDebugPrinter DEFAULT_PRINTER = new SqlDebugPrinter() { 096 097 private boolean printSqlEnable = Jboot.isDevMode(); 098 099 @Override 100 public void setPrintEnable(boolean enable) { 101 this.printSqlEnable = enable; 102 } 103 104 @Override 105 public boolean isPrintEnable(Config config) { 106 return printSqlEnable; 107 } 108 109 @Override 110 public void print(String sql, Long tookTimeMillis) { 111 if (tookTimeMillis != null) { 112 System.out.println("Jboot exec sql took " + tookTimeMillis + " ms >>> " + sql); 113 } else { 114 System.out.println("Jboot exec sql >>> " + sql); 115 } 116 } 117 }; 118 119 SqlDebugPrinter LOG_PRINTER = new SqlDebugPrinter() { 120 121 private boolean printSqlEnable = Jboot.isDevMode(); 122 private Log log = Log.getLog("SqlDebugPrinter.LogPrinter"); 123 124 @Override 125 public void setPrintEnable(boolean enable) { 126 this.printSqlEnable = enable; 127 } 128 129 @Override 130 public boolean isPrintEnable(Config config) { 131 return printSqlEnable; 132 } 133 134 @Override 135 public void print(String sql, Long tookTimeMillis) { 136 if (tookTimeMillis != null) { 137 log.debug("Jboot exec sql took " + tookTimeMillis + " ms >>> " + sql); 138 } else { 139 log.debug("Jboot exec sql >>> " + sql); 140 } 141 } 142 }; 143 144 void setPrintEnable(boolean enable); 145 146 boolean isPrintEnable(Config config); 147 148 void print(String sql, Long tookTimeMillis); 149 } 150 151 public interface SqlRunner<V> { 152 V run() throws SQLException; 153 } 154}