MyBatis(2)——MyBatis 深入学习

编写日志输出环境配置文件

在开发过程中,最重要的就是在控制台查看程序输出的日志信息,在这里我们选择使用 log4j 工具来输出:

  • 准备工作: 将【MyBatis】文件夹下【lib】中的 log4j 开头的 jar 包都导入工程并添加依赖。
    在【src】下新建一个文件 log4j.properties 资源:
# Global logging configuration
# 在开发环境下日志级别要设置成 DEBUG ,生产环境设为 INFO 或 ERROR
log4j.rootLogger=DEBUG, stdout
# Console output...
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.rootLogger=DEBUG, stdout” 指的是日志输出级别,一共有 7 个级别(OFF、 FATAL、 ERROR、 WARN、 INFO、 DEBUG、 ALL)。

  • 一般常用的日志输出级别分别为 DEBUG、 INFO、 ERROR 以及 WARN,分别表示 “调试级别”、 “标准信息级别”、 “错误级别”、 “异常级别”。如果需要查看程序运行的详细步骤信息,一般选择 “DEBUG” 级别,因为该级别在程序运行期间,会在控制台才打印出底层的运行信息,以及在程序中使用 Log 对象打印出调试信息。
  • 如果是日常的运行,选择 “INFO” 级别,该级别会在控制台打印出程序运行的主要步骤信息。“ERROR” 和 “WARN” 级别分别代表 “不影响程序运行的错误事件” 和 “潜在的错误情形”。
  • 文件中 “stdout” 这段配置的意思就是将 DEBUG 的日志信息输出到 stdout 参数所指定的输出载体中。

第二条配置语句 “log4j.appender.stdout=org.apache.log4j.ConsoleAppender” 的含义是,设置名为 stdout 的输出端载体是哪种类型。

  • 目前输出载体有
    ConsoleAppender(控制台)
    FileAppender(文件)
    DailyRollingFileAppender(每天产生一个日志文件)
    RollingFileAppender(文件大小到达指定大小时产生一个新的文件)
    WriterAppender(将日志信息以流格式发送到任意指定的地方)
  • 这里要将日志打印到 IDEA 的控制台,所以选择 ConsoleAppender

第三条配置语句 “log4j.appender.stdout.layout=org.apache.log4j.PatternLayout” 的含义是,名为 stdout 的输出载体的 layout(即界面布局)是哪种类型。

  • 目前输出端的界面类型分为
    HTMLLayout(以 HTML 表格形式布局)
    PatternLayout(可以灵活地指定布局模式)
    SimpleLayout(包含日志信息的级别和信息字符串)
    TTCCLayout(包含日志产生的时间、线程、类别等信息)
  • 这里选择灵活指定其布局类型,即自己去配置布局。

第四条配置语句 “log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n” 的含义是,如果 layout 界面布局选择了 PatternLayout 灵活布局类型,要指定的打印信息的具体格式。

  • 格式信息配置元素大致如下:
    %m 输出代码中的指定的信息
    %p 输出优先级,即 DEBUG、 INFO、 WARN、 ERROR 和 FATAL
    %r 输出自应用启动到输出该 log 信息耗费的毫秒数
    %c 输出所属的类目,通常就是所在类的全名
    %t 输出产生该日志事件的线程名
    %n 输出一个回车换行符,Windows 平台为 “rn”,UNIX 平台为 “n
    %d 输出日志时的时间或日期,默认个事为 ISO8601,也可以在其后指定格式,比如 %d{yyy MMM dd HH:mm:ss},输出类似:2018 年 4 月18 日 10:32:00
    %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数

MyBatis 高级映射

在上一篇文章中,我们讲解了一个 MyBatis 的入门程序的开发,了解了 MyBatis 开发的基本内容。今天我们先来了解一下 MyBatis 是如何处理多张数据库表之间的关联关系,其中包括:

  • 一对一的查询
  • 一对多查询
  • 多对多查询
  • 延迟加载

一对一查询

首先我们先来建立一个数据模型(删掉之前创建的 student 表):

use mybatis;
CREATE TABLE student (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(255) DEFAULT NULL,
  card_id int(11) NOT NULL,
  PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE card (
  id int(11) NOT NULL AUTO_INCREMENT,
  number int(11)  NOT NULL,
  PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO student VALUES (1,'student1',1);
INSERT INTO student VALUES (2,'student2',2);

INSERT INTO card VALUES (1,1111);
INSERT INTO card VALUES (2,2222);
  • 注意: 这里并没有在数据库中设置外键,而是让 MyBatis 去处理多表之间的关系。事实上,外键只是用来保证数据一致性,在某些特殊的情况下(例如高并发秒杀系统中),会专门设置不适用外键,因为存在一定的性能损耗。

然后我们要来确认我们查询的 SQL 语句,我们或许可以简单的写成下面这样:

SELECT
    student.*,
    card.*
FROM
    student,card
WHERE student.card_id = card.id AND card.number = #{value}
  • 提示: 在日常开发中,总是先确定业务的具体 SQL ,再将此 SQL 配置在 Mapper 文件中

确定了主要的查询 SQL 后,接下来我们分别使用 resultType 和 resultMap 来实现这个一对一查询的实例。

1. 使用 resultType 实现

首先创建学生 student 表所对应的 Java 实体类 Student,其中封装的属性信息为响应数据库中的字段:

package pojo;

public class Student {

    int id;
    String name;
    int card_id;

    /* getter and setter */
}

最终我们执行查询(上述的 SQL 语句)的结果如下:

由于最终的查询的结果是由 resultType 指定的,也就是只能映射一个确定的 Java 包装类,上面的 Stuent 类只包含了学生的基本信息,并没有包含 Card 的信息,所以我们要创建一个最终映射类,以 Student 类为父类,然后追加 Card 的信息:

package pojo;

public class StudentAndCard extends Student {
    private int number;

    /* getter and setter /*
}

然后在 Student.xml 映射文件中定义