暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

java研发瑞士军刀系列之MyBatis(十六)

燕山雷震子 2021-06-27
838

    通过前文十五篇的介绍,已经将myabtis的一些原生概念和myabtis的工作流程进行了一番讲解,想必各位看官已经有所感悟。为了帮助大家更好的深入理解myabtis,雷记近期在整理素材,想做一篇关于mybatis源码图文版本的解析,结合之前更新中聊到的一些设计模式,可以帮助大家更好的理解关于mybatis的一切,还望各位届时多多捧场。好了话不多少,继续今天的myabtis关于sql构建器和日志处理的讲解,这也是关于myabtis系列的最后一篇!



产生问题的场景



    雷记在昨天开发时,遇见一个批量更新的问题,公司的项目被不同人在不同阶段采用mybatisplus和myabtisxml混合开发的模式,雷记负责的模块需要对一个映射关系集合做批量更新,如果采用mybatisplus的话,可以直接通过batchupdatebyid()这一sqlsession层封装好的方法直接操作,但是恰巧不巧的是,这里之前开发的老弟使用的原生mybatis的xml配置方式处理,为了早点搞完开始摸鱼,雷记选择采用了@update+<script>jpa方式,进行了动态sql拼接,实在是痛苦又酸爽,搞完之后的代码形如这样:

    写的过程有些痛苦,相信大家也有类似的经历。与使用mybatisplus进行对比之后,可以直观感受到mybatis具备强大的sql动态生成能力。当我们因为种种原因需要在java代码中构建sql语句时,仍然无法避免空格,加号,引号,换行,格式化的问题的,当然还有嵌入条件的逗号管理以及and,简直是痛苦的经历!我们必须干掉这跟题!


关于sql语句构建器



mybatis3中提供了方便的工具类,让我们代码先行,来直观感受一下:

/ 匿名内部类风格public String deletePersonSql() {
  return new SQL() {{
    DELETE_FROM("PERSON");
    WHERE("ID = #{id}");
  }}.toString();}
  // Builder / Fluent 风格
  public String insertPersonSql() {
  String sql = new SQL()
    .INSERT_INTO("PERSON")
    .VALUES("ID, FIRST_NAME", "#{id}, #{firstName}")
    .VALUES("LAST_NAME", "#{lastName}")
    .toString();
  return sql;}
  // 动态条件(注意参数需要使用 final 修饰,以便匿名内部类对它们进行访问)
  public String selectPersonLike(final String id, final String firstName, final String lastName) {
  return new SQL() {{
    SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
    FROM("PERSON P");
    if (id != null) {
      WHERE("P.ID like #{id}");
    }
    if (firstName != null) {
      WHERE("P.FIRST_NAME like #{firstName}");
    }
    if (lastName != null) {
      WHERE("P.LAST_NAME like #{lastName}");
    }
    ORDER_BY("P.LAST_NAME");
  }}.toString();}
  public String deletePersonSql() {
  return new SQL() {{
    DELETE_FROM("PERSON");
    WHERE("ID = #{id}");
  }}.toString();}
  public String insertPersonSql() {
  return new SQL() {{
    INSERT_INTO("PERSON");
    VALUES("ID, FIRST_NAME", "#{id}, #{firstName}");
    VALUES("LAST_NAME", "#{lastName}");
  }}.toString();}
  public String updatePersonSql() {
  return new SQL() {{
    UPDATE("PERSON");
    SET("FIRST_NAME = #{firstName}");
    WHERE("ID = #{id}");
  }}.toString();}

    令人头疼的and+where拼接已经不见了,是否在这个炎炎夏日感受到一丝凉爽?这就是sql类的作用!需要注意的是SQL 类将原样插入 LIMIT、OFFSET、OFFSET n ROWS 以及 FETCH FIRST n ROWS ONLY 子句。换句话说,类库不会为不支持这些子句的数据库执行任何转换。因此使用前该要了解目标数据库是否支持这些子句,如果目标数据库不支持这些子句,产生的 SQL 可能会引起运行错误。



mybatis的日志处理



    mybatis通过使用内置的日志工厂提供日志功能,内置日志工厂将会把日志工作委托给slf4j、apache commons logging、log4j2、log4j、jdk logging其中之一,mybatis内置日志工厂会基于运行时检测信息选择日志委托实现,默认使用第一个查找到的实现,当没有找到时会禁用日志功能;

    


    关于myabtis日志使用出现的问题


 

   有时你已经手工配置了mybatis的日志配置,但是在使用时mybatis却没有按配置进行处理日志,这种问题在于一些服务器如tomcat、websphere的类路径中已经包含了commons logging,作为第一个被发现的日志组件,所以将会使用commons logging,避免该种问题的方式是在mybaits-config.xml配置文件中添加如下修改:


<configuration>
  <settings>
    ...    <setting name="logImpl" value="LOG4J"/>
  </settings>
</configuration>
可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING,或者是实现了 org.apache.ibatis.logging.Log 接口,且构造方法以字符串为参数的类完全限定名
org.apache.ibatis.logging.LogFactory.useSlf4jLogging();
org.apache.ibatis.logging.LogFactory.useLog4JLogging();
org.apache.ibatis.logging.LogFactory.useJdkLogging();
org.apache.ibatis.logging.LogFactory.useCommonsLogging();
org.apache.ibatis.logging.LogFactory.useStdOutLogging();
在调用其它 MyBatis 方法之前调用以上的某个方法,仅当运行时类路径中存在该日志实现时,日志实现的切换才会生效。如果环境中并不存在 Log4J,却试图调用了相应的方法,MyBatis 就会忽略这一切换请求,并将以默认的查找顺序决定使用的日志实现。



配置mybaits的日志


    

    可以通过在包、映射类的全限定名、命名空间或全限定语句名上开启日志功能,来查看 MyBatis 的日志语句,具体配置步骤取决于日志实现,接下来会以 Log4J 作为示范:


添加log4j的jar包

    log4j的jar包可以在其官网下载,然后添加至应用的类路径即可,对于web应用或企业级应用,可以将其添加至web-inf/lib下,对于独立应用可以添加到jvm的-classpath启动参数中


配置log4j

    现假设需要记录下列映射器的日志:

package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}

在应用的类路径中创建一个名为log4j.properties文件,内容:

# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

    上述配置将使 Log4J 详细打印 org.mybatis.example.BlogMapper 的日志,对于应用的其它部分,只打印错误信息。为了实现更细粒度的日志输出,也可以只打印特定语句的日志。以下配置将只打印语句 selectBlog 的日志:

log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE

或者也可以打印一组映射器的日志,只需要打开映射器所在的包的日志功能即可:

log4j.logger.org.mybatis.example=TRACE

    某些查询可能会返回庞大的结果集。可能我们只关注看 SQL 语句,而忽略返回的结果集。为此SQL 语句将会在 DEBUG 日志级别下记录(JDK 日志则为 FINE)。返回的结果集则会在 TRACE 日志级别下记录(JDK 日志则为 FINER)。只要将日志级别调整为 DEBUG 即可(如果要为映射器 XML 文件打印日志时,与映射器处理一样):

log4j.logger.org.mybatis.example=DEBUG


    今天的分享就到这里,我是雷记,专注于分享关于开发编程相关的技术干货,如果今日的分享对您有帮助的话,还望不吝关注点赞,这对我很重要!如果各位在开发过程中遇到棘手问题,可以扫描下图二维码群,和雷记与其他小伙伴一起探讨解决,让我们努力让每一个问题都得到解决!


java研发瑞士军刀系列之MyBatis(十三)
java研发瑞士军刀系列之MyBatis(十二)
java研发瑞士军刀系列之MyBatis(十一)
java研发瑞士军刀系列之MyBatis(十)
java研发瑞士军刀系列之MyBatis(九)
java研发瑞士军刀系列之MyBatis(八)
java研发瑞士军刀系列之MyBatis(七)
java研发瑞士军刀系列之MyBatis(六)
java研发瑞士军刀系列之MyBatis(五)
java研发瑞士军刀系列之MyBatis(四)
java研发瑞士军刀系列之MyBatis(三)
java研发瑞士军刀系列之MyBatis(二)
java研发瑞士军刀系列之MyBatis(一)
文章转载自燕山雷震子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论