热点新闻
Mybatis 工作原理以及拓展方法
2023-07-12 04:35  浏览:1690  搜索引擎搜索“手机易展网”
温馨提示:信息一旦丢失不一定找得到,请务必收藏信息以备急用!本站所有信息均是注册会员发布如遇到侵权请联系文章中的联系方式或客服删除!
联系我时,请说明是在手机易展网看到的信息,谢谢。
展会发布 展会网站大全 报名观展合作 软文发布

1、 Mybatis的工作流程

  • 1、读取配置文件,根据XML配置文件创建Conifuration
  • 2、根据配置信息 创建SqlSessionFactory,SqlSessionFactory的生命周期是程序级,程序运行的时候建立起来,程序结束的时候消亡
  • 3、SqlSessionFactory 创建 SqlSession,SqlSession是过程级,一个方法开始时建立,方法结束应该关闭
  • 4、获取mapper接口的代理对象(DefaultSqlSession.getMapper()拿到Mapper接口对应的MapperProxy)
  • 5、执行增删改查方法
    5.1 调用DefaultSqlSession的增删改查(Executor);
    5.2 会创建一个StatementHandler对象(同时也会创建出ParameterHandler和ResultSetHandler);
    5.3 调用StatementHandler预编译参数以及设置参数值(使用ParameterHandler来给sql设置参数);
    5.4 调用StatementHandler的增删改查方法;
    5.5 ResultSetHandler封装结果;



image.png

2、Mybatis 核心对象

  • Configuration: MyBatis所有的配置信息都维持在Configuration对象之中
  • SqlSession: 负责和数据库进行交互,实现完成常对数据操作的增删改查功能
  • Executor: Mybatis执行器,调度的核心,负责SQL语句的生成和维护
  • StatementHandler :封装并操作Jdbc statement,例如设置参数,将statement结果集转化为List集合
  • ParameterHandler: 负责将用户传递的参数转换为Jdbc statement所需要的参数进行传递
  • ResultSetHandler: 负责将Jdbc返回的ResultSet结果集对象转换为List类型的集合
  • TypeHandler: 负责将java数据类型和Jdbc数据类型之间的转换和映射
  • MappedStatement: MappedStatement维护了一条mapper.xml文件里面 select 、update、delete、insert节点的封装
  • BoundSql: 表示动态生成的SQL语句以及相应的参数信息

3、Mybatis拦截器

在很多业务场景下我们需要去拦截sql,达到不入侵原有代码业务处理一些东西,比如:分页操作,数据权限过滤操作,SQL执行时间性能监控等等,Mybatis拦截器设计的思路是为了供用户灵活的实现自己的逻辑,而不动mybatis固有的逻辑。通过Mybatis拦截器我们能拦截某些方法的调用,我们可以选择在这些被拦截方法执行前后加上我们自己的逻辑,达到丰富方法的效果;也可以在执行这些方法的时候拦截住,转而实现自己设计的方法,而最后不执行被拦截的方法。

在mybatis中可被拦截的类型有四种(按照拦截顺序):

  • Executor:拦截执行器的方法;
  • ParameterHandler:拦截参数的处理;
  • ResultHandler:拦截结果集的处理;
  • StatementHandler:拦截Sql语法构建的处理;

拦截器一般在业务处理中用于:

  • 1、分页查询
  • 2、多租户添加条件过滤,即数据权限过滤操作
  • 3、对返回结果,过滤掉审计字段,敏感字段(比如手机号)
  • 4、对返回结果中的加密数据进行解密
  • 5、对新增数据自动添加创建人,创建时间,更新时间,更新人 ,对更新数据自动新增更新时间,更新人
  • 6、打印SQL执行日志、执行时间

3.1 分页拦截器

mybatisplus 分页拦截器 PaginationInnerInterceptor

// 使用 Page<Produce> producePage = new Page<>(1,1); Page<Produce> page = produceService.selectList(producePage);

拦截器的核心如下图,当我们的select方法的入参 属于(instanceof) IPage时(如上面的 producePage ),
才会执行分页;或者是当入参为Map时,查询map中是否存在属于(instanceof) IPage 的对象。




image.png

优点:通过Page<>泛型,使用简单,性能好;

缺点:如果项目中有很多以Map<String, Object>作为入参的查询方法,就算不是分页接口,每次都会被拦截过滤,影响性能,由于是对于高并发接口。
对于在Mapper 入参中使用 @Param 的查询方法,也会被拦截到,这会导致性能问题。

github分页拦截器 PageInterceptor

Page<Object> pageHelper = PageHelper.startPage(pageNumber, pageSize, true); List<MallGoods> downDateList = mallGoodManager.queryDownGoodsList();

PageHelper 在startPage时,把分页信息写入 ThreadLocal,然后在拦截器中从ThreadLocal获取Page信息,如果存在,则是分页查询;不存在,则是普通查询




image.png




image.png




image.png




image.png




image.png

优点:不会校验普通查询;

缺点:使用ThreadLocal作为存储,需要先 set,然后get,最后remove;对于高并发接口,会有性能问题。

总结:对比上面两种分页的优缺点,还是使用github分页拦截器(使用PageHelper)比较好,但是对于高并发接口,最好是手动写分页,即手动写 select count(*)

3.2 metaObjectHandler 自定义字段自动填充处理类

metaObjectHandler接口是mybatisPlus为我们提供的的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值。常见的比如createTm modifyTm creator modifier

@Configuration public class MymetaObjectHandler implements metaObjectHandler { private static final Logger log = LoggerFactory.getLogger(MymetaObjectHandler.class); private static final Integer NOT_DELETED = 0; public MymetaObjectHandler() { } public void insertFill(metaObject metaObject) { String createDate = "createDate"; boolean hasCreateDate = this.hasProperty(metaObject, createDate); if (hasCreateDate) { this.setFieldValByName(createDate, new Date(), metaObject); } String createTm = "createTm"; boolean hasCreateTm = this.hasProperty(metaObject, createTm); if (hasCreateTm) { this.setFieldValByName(createTm, new Date(), metaObject); } String updateDate = "updateDate"; boolean hasUpdateDate = this.hasProperty(metaObject, updateDate); if (hasUpdateDate) { this.setFieldValByName(updateDate, new Date(), metaObject); } String modifyTm = "modifyTm"; boolean hasModifyTm = this.hasProperty(metaObject, modifyTm); if (hasModifyTm) { this.setFieldValByName(modifyTm, new Date(), metaObject); } String deleteFlag = "deleteFlag"; boolean hasDeleteFlag = this.hasProperty(metaObject, deleteFlag); if (hasDeleteFlag) { this.setFieldValByName(deleteFlag, NOT_DELETED, metaObject); } String empNum = ContextHoldUtil.getEmpNum(); if (SfStrUtil.isNotBlank(empNum)) { String createUser = "createUser"; boolean hasCreateUser = this.hasProperty(metaObject, createUser); if (hasCreateUser) { this.setFieldValByName(createUser, empNum, metaObject); } String creator = "creator"; boolean hasCreator = this.hasProperty(metaObject, creator); if (hasCreator) { this.setFieldValByName(creator, empNum, metaObject); } String updateUser = "updateUser"; boolean hasUpdateUser = this.hasProperty(metaObject, updateUser); if (hasUpdateUser) { this.setFieldValByName(updateUser, empNum, metaObject); } String modifier = "modifier"; boolean hasModifier = this.hasProperty(metaObject, modifier); if (hasModifier) { this.setFieldValByName(modifier, empNum, metaObject); } } } public void updateFill(metaObject metaObject) { String updateDate = "updateDate"; boolean hasUpdateDate = this.hasProperty(metaObject, updateDate); if (hasUpdateDate) { this.setFieldValByName(updateDate, new Date(), metaObject); } String modifyTm = "modifyTm"; boolean hasModifyTm = this.hasProperty(metaObject, modifyTm); if (hasModifyTm) { this.setFieldValByName(modifyTm, new Date(), metaObject); } String empNum = ContextHoldUtil.getEmpNum(); if (SfStrUtil.isNotBlank(empNum)) { String updateUser = "updateUser"; boolean hasUpdateUser = this.hasProperty(metaObject, updateUser); if (hasUpdateUser) { this.setFieldValByName(updateUser, empNum, metaObject); } String modifier = "modifier"; boolean hasModifier = this.hasProperty(metaObject, modifier); if (hasModifier) { this.setFieldValByName(modifier, empNum, metaObject); } } } private boolean hasProperty(metaObject metaObject, String fieldName) { return metaObject.hasGetter(fieldName) || metaObject.hasGetter("et." + fieldName); } }

3.3 1、日志拦截器 —— 用于测试环境,sql美化,sql执行时间

在测试环境,通常我们会配置SQL日志打印,用于调试。
1、原生 org.apache.ibatis.logging.stdout.StdOutImpl

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@38cd0f91] was not registered for synchronization because synchronization is not active JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7182d8bf] will not be managed by Spring ==> Preparing: select g.name as goodsName, g.goods_type as goodsType, g.goods_no as goodsNo, g.current_store as currentStore, gi.img_url as goodsImage, g.point_price as pointPrice, g.discount_price as discountPrice, g.rise_date as exchangeBeginTime, g.original_price as originPrice, g.category_code as categoryCode, g.sub_category_code as subCategoryCode, g.serial_num as serialNum, g.purchase_price as purchasePrice, g.exchange_mem_level as exchangeLevelLimit, g.sale_channel as saleChannel, g.label as label, g.like_amount as likeAmount, g.state as state from mall_goods g left join mall_goods_img gi on g.goods_no = gi.goods_no and gi.img_type = 1 where g.category_code = ? and g.state = 1 and g.mall = 'Point_Mall' and g.if_life_privilege in (0,2) and (g.current_store>0 or g.current_store=-1) order by g.serial_num asc,g.id desc limit ?,? ==> Parameters: XPZQ(String), 1(Integer), 10(Integer) <== Columns: goodsName, goodsType, goodsNo, currentStore, goodsImage, pointPrice, discountPrice, exchangeBeginTime, originPrice, categoryCode, subCategoryCode, serialNum, purchasePrice, exchangeLevelLimit, saleChannel, label, likeAmount, state <== Row: 唯品会券对接_0803 , SFSJ, GOODS20220803185335009, 499996, https://fff, 2, 0, 2022-08-03 18:53:37.0, 2000, XPZQ, null, 1, 0, 0, 0, [{"type":3}], 0, 1 <== Row: 井1, SFM, GOODS20220713112243913, 17, https://aaa, 1, 0, 2022-08-03 19:04:20.0, 100, XPZQ, null, 1, 0, 0, 0, [{"type":3}], 4, 1 <== Row: #14, SFM, GOODS20220707181501415, 19, bbb, 10, 0, 2022-07-30 15:17:04.0, 10000, XPZQ, null, 1, 0, 0, 0, [{"type":3}], 1, 1 <== Row: 0601版本券码导入10W张验证, SFW, GOODS20220713181357698, 500000, https:/ccc, 1, 0, 2022-07-29 15:07:13.0, 12, XPZQ, null, 2, 0, 0, 0, [{"type":3}], 0, 1 <== Row: 礼包名称-实物xy, SFM, GOODS20220713075614668, 20, https://ddd, 1, 0, 2022-07-29 15:34:31.0, 100, XPZQ, null, 2, 0, 0, 0, [{"type":3}], 0, 1 <== Row: #15, SFM, GOODS20220705173709700, 14, https://eee, 1, 0, 2022-07-30 11:42:00.0, 10000, XPZQ, null, 3, 0, 0, 0, [{"type":3}], 6, 1 <== Total: 6 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@38cd0f91]

优点:配置简单
缺点:SQL语句和参数分开,且结果直接打印,不直观

2、mybatisplus 支持p6spy




image.png

优点:配置复杂
缺点:SQL语句没有美化

3、手动开发 MybatisLogInterceptor

@Intercepts({@Signature( type = Executor.class, method = "update", args = {MappedStatement.class, Object.class} ), @Signature( type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} ), @Signature( type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class} )}) @Component public class MybatisLogInterceptor implements Interceptor { private static final Logger log = LoggerFactory.getLogger(MybatisLogInterceptor.class); private Properties properties; private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final String DEFAULT_SQL_LOG_SHOW_SWITCH = "false"; @Value("${sqlLogShowSwitch}") private String sqlLogShowSwitch; public MybatisLogInterceptor() { } public Object intercept(Invocation invocation) throws Throwable { if (StrUtil.equals(this.sqlLogShowSwitch, "false")) { return invocation.proceed(); } else { try { Object[] args = invocation.getArgs(); MappedStatement mappedStatement = (MappedStatement)args[0]; Object parameter = null; if (args.length > 1) { parameter = args[1]; } String sqlId = mappedStatement.getId(); BoundSql boundSql = null; if (args.length == 6) { boundSql = (BoundSql)args[5]; } if (boundSql == null) { boundSql = mappedStatement.getBoundSql(parameter); } Configuration configuration = mappedStatement.getConfiguration(); long start = System.currentTimeMillis(); Object returnValue = invocation.proceed(); long end = System.currentTimeMillis(); long time = end - start; String sql = getSql(configuration, boundSql, sqlId, time); log.info("开始执行sql==> " + sql.split("(\\^ZHIKE\\^)")[0] + "\n" + "执行SQL==>" + (new PrettyFormatterSqlUtil()).getPrettySql(sql.split("(\\^ZHIKE\\^)")[1]) + "\n" + "<==执行总耗时【 " + time + " ms】\n"); String returnStr = ""; if (returnValue != null) { returnStr = SfJsonUtil.toJsonStr(returnValue); } log.info("执行sql结果:{}", returnStr.length() >= 2000 ? returnStr.substring(0, 2000) : returnStr); return returnValue; } catch (Throwable var17) { log.error("执行sql报错!errMsg:{}", var17.getMessage(), var17); return invocation.proceed(); } } } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { this.properties = properties; } public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId, long time) { String sql = showSql(configuration, boundSql); StringBuilder builder = new StringBuilder(100); builder.append(sqlId); builder.append("^ZHIKE^"); builder.append(sql); builder.append("^ZHIKE^"); builder.append(time); builder.append("ms"); return builder.toString(); } private static String getParameterValue(Object obj) { String value; if (obj instanceof String) { value = "'" + obj.toString() + "'"; } else if (obj instanceof Date) { value = "'" + SIMPLE_DATE_FORMAT.format(obj) + "'"; } else if (obj != null) { value = obj.toString(); } else { value = ""; } return value; } public static String showSql(Configuration configuration, BoundSql boundSql) { try { Object parameterObject = boundSql.getParameterObject(); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); String sql = boundSql.getSql().replaceAll("[\\s]+", " "); if (parameterMappings.size() > 0 && parameterObject != null) { TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { sql = sql.replaceFirst("\\?", getParameterValue(parameterObject)); } else { metaObject metaObject = configuration.newmetaObject(parameterObject); Iterator var7 = parameterMappings.iterator(); while(var7.hasNext()) { ParameterMapping parameterMapping = (ParameterMapping)var7.next(); String propertyName = parameterMapping.getProperty(); Object obj; if (metaObject.hasGetter(propertyName)) { obj = metaObject.getValue(propertyName); sql = sql.replaceFirst("\\?", getParameterValue(obj)); } else if (boundSql.hasAdditionalParameter(propertyName)) { obj = boundSql.getAdditionalParameter(propertyName); sql = sql.replaceFirst("\\?", getParameterValue(obj)); } } } } return sql; } catch (Exception var11) { return ""; } } }

SQL美化工具类

import java.util.HashSet; import java.util.linkedList; import java.util.Set; import java.util.StringTokenizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PrettyFormatterSqlUtil { private static final Logger log = LoggerFactory.getLogger(PrettyFormatterSqlUtil.class); private static final Set<String> BEGIN_CLAUSES = new HashSet(); private static final Set<String> END_CLAUSES = new HashSet(); private static final Set<String> LOGICAL = new HashSet(); private static final Set<String> QUANTIFIERS = new HashSet(); private static final Set<String> DML = new HashSet(); private static final Set<String> MISC = new HashSet(); public static final String WHITESPACE = " \n\r\f\t"; static final String INDENT_STRING = " "; static final String INITIAL = "\n "; public PrettyFormatterSqlUtil() { } public String getPrettySql(String source) { return (new PrettyFormatterSqlUtil.FormatProcess(source)).perform(); } static { BEGIN_CLAUSES.add("left"); BEGIN_CLAUSES.add("right"); BEGIN_CLAUSES.add("inner"); BEGIN_CLAUSES.add("outer"); BEGIN_CLAUSES.add("group"); BEGIN_CLAUSES.add("order"); END_CLAUSES.add("where"); END_CLAUSES.add("set"); END_CLAUSES.add("having"); END_CLAUSES.add("join"); END_CLAUSES.add("from"); END_CLAUSES.add("by"); END_CLAUSES.add("join"); END_CLAUSES.add("into"); END_CLAUSES.add("union"); LOGICAL.add("and"); LOGICAL.add("or"); LOGICAL.add("when"); LOGICAL.add("else"); LOGICAL.add("end"); QUANTIFIERS.add("in"); QUANTIFIERS.add("all"); QUANTIFIERS.add("exists"); QUANTIFIERS.add("some"); QUANTIFIERS.add("any"); DML.add("insert"); DML.add("update"); DML.add("delete"); MISC.add("select"); MISC.add("on"); } private static class FormatProcess { boolean beginLine = true; boolean afterBeginBeforeEnd = false; boolean afterByOrSetOrFromOrSelect = false; boolean afterValues = false; boolean afterOn = false; boolean afterBetween = false; boolean afterInsert = false; int inFunction = 0; int parensSinceSelect = 0; private linkedList<Integer> parenCounts = new linkedList(); private linkedList<Boolean> afterByOrFromOrSelects = new linkedList(); int indent = 1; StringBuilder result = new StringBuilder(); StringTokenizer tokens; String lastToken; String token; String lcToken; public FormatProcess(String sql) { this.tokens = new StringTokenizer(sql, "()+*/-=<>'`\"[], \n\r\f\t", true); } public String perform() { this.result.append("\n "); while(this.tokens.hasMoreTokens()) { this.token = this.tokens.nextToken(); this.lcToken = this.token.toLowerCase(); String t; if ("'".equals(this.token)) { do { t = this.tokens.nextToken(); this.token = this.token + t; } while(!"'".equals(t) && this.tokens.hasMoreTokens()); } else if ("\"".equals(this.token)) { do { t = this.tokens.nextToken(); this.token = this.token + t; } while(!"\"".equals(t)); } if (this.afterByOrSetOrFromOrSelect && ",".equals(this.token)) { this.commaAfterByOrFromOrSelect(); } else if (this.afterOn && ",".equals(this.token)) { this.commaAfterOn(); } else if ("(".equals(this.token)) { this.openParen(); } else if (")".equals(this.token)) { this.closeParen(); } else if (PrettyFormatterSqlUtil.BEGIN_CLAUSES.contains(this.lcToken)) { this.beginNewClause(); } else if (PrettyFormatterSqlUtil.END_CLAUSES.contains(this.lcToken)) { this.endNewClause(); } else if ("select".equals(this.lcToken)) { this.select(); } else if (PrettyFormatterSqlUtil.DML.contains(this.lcToken)) { this.updateOrInsertOrDelete(); } else if ("values".equals(this.lcToken)) { this.values(); } else if ("on".equals(this.lcToken)) { this.on(); } else if (this.afterBetween && "and".equals(this.lcToken)) { this.misc(); this.afterBetween = false; } else if (PrettyFormatterSqlUtil.LOGICAL.contains(this.lcToken)) { this.logical(); } else if (isWhitespace(this.token)) { this.white(); } else { this.misc(); } if (!isWhitespace(this.token)) { this.lastToken = this.lcToken; } } return this.result.toString(); } private void commaAfterOn() { this.out(); --this.indent; this.newline(); this.afterOn = false; this.afterByOrSetOrFromOrSelect = true; } private void commaAfterByOrFromOrSelect() { this.out(); this.newline(); } private void logical() { if ("end".equals(this.lcToken)) { --this.indent; } this.newline(); this.out(); this.beginLine = false; } private void on() { ++this.indent; this.afterOn = true; this.newline(); this.out(); this.beginLine = false; } private void misc() { this.out(); if ("between".equals(this.lcToken)) { this.afterBetween = true; } if (this.afterInsert) { this.newline(); this.afterInsert = false; } else { this.beginLine = false; if ("case".equals(this.lcToken)) { ++this.indent; } } } private void white() { if (!this.beginLine) { this.result.append(" "); } } private void updateOrInsertOrDelete() { this.out(); ++this.indent; this.beginLine = false; if ("update".equals(this.lcToken)) { this.newline(); } if ("insert".equals(this.lcToken)) { this.afterInsert = true; } } private void select() { this.out(); ++this.indent; this.newline(); this.parenCounts.addLast(this.parensSinceSelect); this.afterByOrFromOrSelects.addLast(this.afterByOrSetOrFromOrSelect); this.parensSinceSelect = 0; this.afterByOrSetOrFromOrSelect = true; } private void out() { this.result.append(this.token); } private void endNewClause() { if (!this.afterBeginBeforeEnd) { --this.indent; if (this.afterOn) { --this.indent; this.afterOn = false; } this.newline(); } this.out(); if (!"union".equals(this.lcToken)) { ++this.indent; } this.newline(); this.afterBeginBeforeEnd = false; this.afterByOrSetOrFromOrSelect = "by".equals(this.lcToken) || "set".equals(this.lcToken) || "from".equals(this.lcToken); } private void beginNewClause() { if (!this.afterBeginBeforeEnd) { if (this.afterOn) { --this.indent; this.afterOn = false; } --this.indent; this.newline(); } this.out(); this.beginLine = false; this.afterBeginBeforeEnd = true; } private void values() { --this.indent; this.newline(); this.out(); ++this.indent; this.newline(); this.afterValues = true; } private void closeParen() { --this.parensSinceSelect; if (this.parensSinceSelect < 0) { --this.indent; this.parensSinceSelect = (Integer)this.parenCounts.removeLast(); this.afterByOrSetOrFromOrSelect = (Boolean)this.afterByOrFromOrSelects.removeLast(); } if (this.inFunction > 0) { --this.inFunction; this.out(); } else { if (!this.afterByOrSetOrFromOrSelect) { --this.indent; this.newline(); } this.out(); } this.beginLine = false; } private void openParen() { if (isFunctionName(this.lastToken) || this.inFunction > 0) { ++this.inFunction; } this.beginLine = false; if (this.inFunction > 0) { this.out(); } else { this.out(); if (!this.afterByOrSetOrFromOrSelect) { ++this.indent; this.newline(); this.beginLine = true; } } ++this.parensSinceSelect; } private static boolean isFunctionName(String tok) { char begin = tok.charAt(0); boolean isIdentifier = Character.isJavaIdentifierStart(begin) || '"' == begin; return isIdentifier && !PrettyFormatterSqlUtil.LOGICAL.contains(tok) && !PrettyFormatterSqlUtil.END_CLAUSES.contains(tok) && !PrettyFormatterSqlUtil.QUANTIFIERS.contains(tok) && !PrettyFormatterSqlUtil.DML.contains(tok) && !PrettyFormatterSqlUtil.MISC.contains(tok); } private static boolean isWhitespace(String token) { return " \n\r\f\t".indexOf(token) >= 0; } private void newline() { this.result.append("\n"); for(int i = 0; i < this.indent; ++i) { this.result.append(" "); } this.beginLine = true; } } }

打印结果:

2022-09-09 20:49:47.768[http-nio-9026-exec-1] MybatisLogInterceptor.intercept(81) INFO [c3c83832b58f49579561e92bceafdec1] :开始执行sql==> com.sf.cemp.goods.mallgoods.repository.mapper.MallGoodsMapper.selectPointMallListForApp 执行SQL==> select g.name as goodsName, g.goods_type as goodsType, g.goods_no as goodsNo, g.current_store as currentStore, gi.img_url as goodsImage, g.point_price as pointPrice, g.discount_price as discountPrice, g.rise_date as exchangeBeginTime, g.original_price as originPrice, g.category_code as categoryCode, g.sub_category_code as subCategoryCode, g.serial_num as serialNum, g.purchase_price as purchasePrice, g.exchange_mem_level as exchangeLevelLimit, g.sale_channel as saleChannel, g.label as label, g.like_amount as likeAmount, g.state as state from mall_goods g left join mall_goods_img gi on g.goods_no = gi.goods_no and gi.img_type = 1 where g.category_code = 'XPZQ' and g.state = 1 and g.mall = 'Point_Mall' and g.if_life_privilege in ( 0,2 ) and ( g.current_store>0 or g.current_store=-1 ) order by g.serial_num asc, g.id desc limit 1, 10 <==执行总耗时【 281 ms】 2022-09-09 20:52:03.886[http-nio-9026-exec-3] MybatisLogInterceptor.intercept(88) INFO [1a97f40126b9410aad411dc4bc327eca] :执行sql结果:[{"categoryCode":"XPZQ","currentDate":1662727923886,"currentStore":499995,"discountPrice":0,"exchangeBeginTime":1661242860000,"exchangeLevelLimit":0,"goodsImage":"https://cemp.sit.sf-express.com/packetImg/853523/202208/20220823161800408.png","goodsName":"商品预热验证-cyr","goodsNo":"GOODS20220823161825360","goodsType":"SFW","label":"[{\"type\":3}]","likeAmount":0,"originPrice":3300,"pointPrice":33,"purchasePrice":0,"saleChannel":"0","serialNum":1,"state":1}]

总结:自定义SQL日志拦截器使用最方便

发布人:959b****    IP:117.173.23.***     举报/删稿
展会推荐
让朕来说2句
评论
收藏
点赞
转发