Java tutorial
/** * Copyright (c) 2011-2020, hubin (jobob@qq.com). * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.mybatisX.plugins; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Properties; import org.apache.ibatis.builder.StaticSqlSource; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; import org.apache.ibatis.session.Configuration; import com.mybatisX.exceptions.MybatisXException; import com.mybatisX.toolkit.IOUtils; /** * <p> * SQL ?? ??? MYSQL-5.6.3 * </p> * * @author hubin * @Date 2016-08-16 */ @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) }) public class SqlExplainInterceptor implements Interceptor { private static final Log logger = LogFactory.getLog(SqlExplainInterceptor.class); /** * ? delete update ??? */ private boolean stopProceed = false; public Object intercept(Invocation invocation) throws Throwable { /** * ? DELETE UPDATE ? */ MappedStatement ms = (MappedStatement) invocation.getArgs()[0]; if (ms.getSqlCommandType() == SqlCommandType.DELETE || ms.getSqlCommandType() == SqlCommandType.UPDATE) { Configuration configuration = ms.getConfiguration(); Object parameter = invocation.getArgs()[1]; BoundSql boundSql = ms.getBoundSql(parameter); Executor exe = (Executor) invocation.getTarget(); Connection connection = exe.getTransaction().getConnection(); /** * SQL ? */ sqlExplain(configuration, ms, boundSql, connection, parameter); } return invocation.proceed(); } /** * <p> * ? SQL * </p> * * @param configuration * @param mappedStatement * @param boundSql * @param connection * @param parameter * @return * @throws Exception */ protected void sqlExplain(Configuration configuration, MappedStatement mappedStatement, BoundSql boundSql, Connection connection, Object parameter) { PreparedStatement stmt = null; ResultSet rs = null; try { StringBuilder explain = new StringBuilder("EXPLAIN "); explain.append(boundSql.getSql()); String sqlExplain = explain.toString(); StaticSqlSource sqlsource = new StaticSqlSource(configuration, sqlExplain, boundSql.getParameterMappings()); MappedStatement.Builder builder = new MappedStatement.Builder(configuration, "explain_sql", sqlsource, SqlCommandType.SELECT); builder.resultMaps(mappedStatement.getResultMaps()).resultSetType(mappedStatement.getResultSetType()) .statementType(mappedStatement.getStatementType()); MappedStatement query_statement = builder.build(); DefaultParameterHandler handler = new DefaultParameterHandler(query_statement, parameter, boundSql); stmt = connection.prepareStatement(sqlExplain); handler.setParameters(stmt); rs = stmt.executeQuery(); while (rs.next()) { if (!"Using where".equals(rs.getString("Extra"))) { String tip = " Full table operation is prohibited. SQL: " + boundSql.getSql(); if (this.isStopProceed()) { throw new MybatisXException(tip); } logger.error(tip); break; } } } catch (Exception e) { throw new MybatisXException(e); } finally { IOUtils.closeQuietly(rs, stmt); } } public Object plugin(Object target) { if (target instanceof Executor) { return Plugin.wrap(target, this); } return target; } public void setProperties(Properties prop) { // TODO } public boolean isStopProceed() { return stopProceed; } public void setStopProceed(boolean stopProceed) { this.stopProceed = stopProceed; } }