Table of Contents

一、mybatis-config.xml 配置详解

image-20211230093924648

1.1 属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:

1
2
3
4
<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

然后其中的属性就可以在整个配置文件中被用来替换需要动态配置的属性值。比如:

1
2
3
4
5
6
<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

这个例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换。 driver 和 url 属性将会由 config.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。

还可以再 SqlSessionFactoryBuilder.build() 方法中传入属性值。

1
2
3
4
5
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);

// ... 或者 ...

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);

image-20211230094653960

如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:

  • 1)在 properties 元素体内指定的属性首先被读取。
  • 2)然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
  • 3)最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的是 properties 属性中指定的属性。

1.2 设置(Settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

官网给出了设置项 https://mybatis.org/mybatis-3/zh/configuration.html

截取了部分:

image-20211230095637253

其中重要的有:

img

在Orical数据库中,都用LAST_NAME这种方式设置列名。

1
2
3
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

1.3 类型别名(typeAliases)

类型别名是为 Java 类型命名的一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。

  • 方式一

    1
    2
    3
    4
    5
    6
    7
    8
    
    <typeAliases>
      <typeAlias alias="Author" type="domain.blog.Author"/>
      <typeAlias alias="Blog" type="domain.blog.Blog"/>
      <typeAlias alias="Comment" type="domain.blog.Comment"/>
      <typeAlias alias="Post" type="domain.blog.Post"/>
      <typeAlias alias="Section" type="domain.blog.Section"/>
      <typeAlias alias="Tag" type="domain.blog.Tag"/>
    </typeAliases>
    

    当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。

    缺点:每个pojo类都要去配置。 解决方案:使用扫描包,扫描指定包下的所有类,扫描之后的别名就是类名(不区分大小写),建议使用的时候和类名一致。

  • 方式二

    也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

    1
    2
    3
    
    <typeAliases>
      <package name="domain.blog"/>
    </typeAliases>
    

    第二种不可以DIY别名,如果要该,需要在实体类上增加注解。

    1
    2
    3
    4
    
    @Alias("author")
    public class Author {
        ...
    }
    

1.4 插件(plugins)

img

现在一些MyBatis 插件比如PageHelper都是基于这个原理,有时为了监控sql执行效率,也可以使用插件机制原理

1.5 环境配置(environments)

MyBatis 可以配置成适应多种环境,例如,开发、测试和生产环境需要有不同的配置; 尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。 虽然,这种方式也可以做到很方便的分离多个环境,但是实际使用场景下,我们更多的是选择使用spring来管理数据源,来做到环境的分离。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>
  </environment>
</environments>

注意一些关键点:

  • 默认使用的环境 ID(比如:default=“development”)。
  • 每个 environment 元素定义的环境 ID(比如:id=“development”)。
  • 事务管理器的配置(比如:type=“JDBC”)。
  • 数据源的配置(比如:type=“POOLED”)。

事务管理器:在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")

数据源:unpooled, pooled, JNDI

1.6 映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

使用class 方式注意点:

  • 接口和他的Mapper 配置文件必须同名!
  • 接口和他的Mapper 配置文件必须在同一个包下!

使用 包的方式也有上面的注意点。推荐使用的方式就是resource的方式。

二、日志使用 log4j

  • 什么是log4j?

    • Apache Log4j是一个基于Java日志记录工具。它是由瑞士程序员Ceki Gülcü于2001年首创的,现在则是Apache软件基金会的一个项目。 log4j是几种Java日志框架之一。2021年12月9日,Log4j 2.0的一个零日远程代码执行漏洞被报告,其被称为“Log4Shell”,公共漏洞和暴露编号为CVE-2021-44228[6]。它被定性为“过去十年来最大、最关键的漏洞”[7]
    • 我们也可以控制每一条日志的输出格式;
    • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志地生成过程;
    • 通过一个配置文件来灵活进行配置,而不需要修改应用的代码;
  • 导入依赖

    1
    2
    3
    4
    5
    
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  • log4j.properties

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    
    # priority  :debug<info<warn<error
    #you cannot specify every priority with different file for log4j 
    log4j.rootLogger=debug,stdout,info,debug,warn,error 
    
    #console
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
    log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
    #info log
    log4j.logger.info=info
    log4j.appender.info=org.apache.log4j.DailyRollingFileAppender 
    log4j.appender.info.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.info.File=./src/com/hp/log/info.log
    log4j.appender.info.Append=true
    log4j.appender.info.Threshold=INFO
    log4j.appender.info.layout=org.apache.log4j.PatternLayout 
    log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #debug log
    log4j.logger.debug=debug
    log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender 
    log4j.appender.debug.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.debug.File=./src/com/hp/log/debug.log
    log4j.appender.debug.Append=true
    log4j.appender.debug.Threshold=DEBUG
    log4j.appender.debug.layout=org.apache.log4j.PatternLayout 
    log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #warn log
    log4j.logger.warn=warn
    log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender 
    log4j.appender.warn.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.warn.File=./src/com/hp/log/warn.log
    log4j.appender.warn.Append=true
    log4j.appender.warn.Threshold=WARN
    log4j.appender.warn.layout=org.apache.log4j.PatternLayout 
    log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #error
    log4j.logger.error=error
    log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.error.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.error.File = ./src/com/hp/log/error.log 
    log4j.appender.error.Append = true
    log4j.appender.error.Threshold = ERROR 
    log4j.appender.error.layout = org.apache.log4j.PatternLayout
    log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    
  • 配置mybatis

    1
    2
    3
    
    <settings>
    	<setting name="logImpl" value="LOG4J"/>
    </settings>
    
  • 简单使用

    1
    2
    3
    4
    5
    6
    7
    8
    
    private static Logger logger = Logger.getLogger(Test.class);
    
    logger.debug("This is debug message.");  
    // 记录info级别的信息  
    logger.info("This is info message.");  
    // 记录error级别的信息  
    logger.error("This is error message.");