mybatis-03 Mybatis 配置
mybatis-03 Mybatis 配置
概述
虽说约定大于配置,已经是框架开发演进的方向,但掌握核心的配置往往能最大化地榨干框架的性能,满足我们的需求。目前对于 Mybatis 来说,我面临最大的一个问题就是:无法查看执行的 SQL 语句!这是致命的。但是,配置好 Mybatis 的日志实现后,就能在指定位置看到拼接出的 SQL 语句、查询结果、执行时间……
官网对配置的介绍都在这个页面上:https://mybatis.org/mybatis-3/zh/configuration.html
配置详解
环境配置(environments)
MyBatis 可以配置多套使用环境,但每个 SqlSessionFactory 实例只能选择一种环境。所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例……为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果忽略了环境参数,那么将会加载默认环境:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
environments 元素定义了如何配置环境。
<environments default="development">
<environment id="development">
<transactionmanager type="JDBC">
<property name="..." value="...">
</property></transactionmanager>
<datasource type="POOLED">
<property name="driver" value="${driver}">
<property name="url" value="${url}">
<property name="username" value="${username}">
<property name="password" value="${password}">
</property></property></property></property></datasource>
</environment>
</environments>
注意一些关键点:
- 默认使用的环境 ID(比如:default="development")。
- 每个 environment 元素定义的环境 ID(比如:id="development")。
- 事务管理器的配置(比如:type="JDBC")。
- 数据源的配置(比如:type="POOLED")。
其中较为陌生的概念大致有如下几条:
- 事务管理器:https://www.cnblogs.com/yanze/p/10249617.html
- 数据源:Mybatis 配置官方说明文档
目前只需要记住的就是:
- 在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")
- Mybatis 默认连接方式是 pooled,事务处理器为 JDBC
属性(properties)
可以通过这个属性来引用外部配置文件,编写一个配置文件,后续可以按照${属性名}
的格式取出
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?&useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=wal14.
要在 xml 配置文件中使用外部配置文件,只需要使用 properties 标签,并且用 resource 属性指明外部配置文件位置,之后就可以按照规约使用了:
<!--?xml version="1.0" encoding="UTF8" ?-->
<configuration>
<!-- 引入外部配置文件-->
<properties resource="db.properties">
<!-- 下面的配置会覆盖 db.properties 配置文件中对 url 的赋值-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?&useSSL=true&useUnicode=true&characterEncoding=utf8">
</property></properties>
<typealiases>
<!-- <typeAlias type="com.ermao.pojo.User" alias="User"/>-->
<package name="com.ermao.pojo">
</package></typealiases>
<environments default="development">
<environment id="development">
<transactionmanager type="JDBC">
<datasource type="POOLED">
<property name="driver" value="${driver}">
<property name="url" value="${url}">
<property name="username" value="${username}">
<property name="password" value="${password}">
</property></property></property></property></datasource>
</transactionmanager></environment>
</environments>
<mappers>
<mapper resource="com/ermao/dao/UserMapper.xml">
</mapper></mappers>
</configuration>
要在构建 SqlSessionFactory 对象的时候直接使用外部配置 properties,而非使用写定在 xml 文件中的 development 环境配置,可以这样:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props); // 没有使用 environment 配置而使用了 properties 里的外部配置
// ... 或者 ...
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props); // 两者都使用
对于同时使用外部配置文件和 xml 环境配置时的优先级,也就是说如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:
- 首先读取在 properties 元素体内指定的属性(也就是 xml 文件里明文配置的属性)。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 xml 配置,意在减少全限定类名书写。例如:
<typealiases>
<typealias type="com.ermao.pojo.User" alias="User">
<typealias alias="Post" type="domain.blog.Post">
<typealias alias="Section" type="domain.blog.Section">
<typealias alias="Tag" type="domain.blog.Tag">
</typealias></typealias></typealias></typealias></typealiases>
但我们一般也不会按照上述方法行动,而是直接扫描一个包,包中的所有类都会以首字母小写和大写为别名(引用这些类的时候尽量用小写)。
另外可以使用Alias注解配合使用package来指定别名
@Alias("myUser")
public class User {
private int id;
private String name;
private String pwd;
}
<select id="getUserList" resulttype="myUser">
select * from mybatis.user
</select>
Mybatis 也为我们做好了 java 内置的一些基本数据类型的映射,要注意的是带下划线的别名映射的是基本类型,没有下划线的是对象类型:
_int --> int
int --> Integer
_double --> double
double --> Double
设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
这个链接中的表格指定了各个设置的含义:https://mybatis.org/mybatis-3/zh/configuration.html#settings。挑几个迄今为止有所遇见和使用的进行简单的说明:
- cacheEnabled
- 是否启用缓存。
- lazyLoadingEnabled
- 是否懒加载
- useGeneratedKeys
- 配置自动生成并且返回主键。
- 参考:https://www.cnblogs.com/nuccch/p/9069644.html
- autoMappingBehavior
- 指定 MyBatis 应如何自动映射列到字段或属性。
- autoMappingUnknownColumnBehavior
- 发现无法映射字段时的行为。
- defaultExecutorType
- 执行器模式,在执行 Batch 类型的语句的时候可以进行相关的配置。
- mapUnderscoreToCamelCase
- 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
- localCacheScope
- 缓存相关
- callSettersOnNulls
- 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。
- logImpl
- 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
- 配置的值只能从候选项中选择,且大小写敏感。
- useActualParamName
- 允许使用方法签名中的名称作为 SQL 语句参数名称,并且通过
#{参数名}
获取得到。默认开启,这也是我们不需要在函数签名中使用 @Param 注解,但是仍然可以在 SQL 语句中通过参数名引用参数值的原因所在。 - 参考:https://blog.csdn.net/qq_15038565/article/details/115414387
- 允许使用方法签名中的名称作为 SQL 语句参数名称,并且通过
类型处理器(typeHandlers)
MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。具体的处理器见这张表:https://mybatis.org/mybatis-3/zh/configuration.html#typeHandlers。
这也是 ResultMap 结果集映射实现的依据之处,有非常高的灵活度。
插件(plugins)
拦截器,很容易让人同 MybatisPlus 中的拦截器联想起来,可以在 SQL 执行前后等其它时刻进行拦截并进行相应修改,MP 对 Mybatis 的部分扩展似乎就是从这里入手的。
映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符,或类名和包名等。例如:
方式一:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="com/ermao/dao/UserMapper.xml">
</mapper></mappers>
方式二
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper">
<mapper class="org.mybatis.builder.BlogMapper">
<mapper class="org.mybatis.builder.PostMapper">
</mapper></mapper></mapper></mappers>
这种方式要求映射器接口和映射器文件必须同名,且接口和xml文件必须在同一个包下。
方式三
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder">
</package></mappers>
这种方式要求映射器接口和映射器文件必须同名,且接口和xml文件必须在同一个包下。
关键对象的作用域和生命周期
理解我们之前讨论过的不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder:
- 一旦创建了 SqlSessionFactory 就不再被需要。
- 局部变量。
SqlSessionFactory:
- 可以理解成一个连接池。
- 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另外一个实例。
- 所以它的最佳作用域为应用 scope。
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession
- 连接到连接池的 session。
- 需要被开启和及时关闭。
- 线程不安全,不应该被共享。
- 最佳作用域为方法代码块。
日志
目前对于日志最迫切的需求就是:在控制台输出映射器中的 SQL 语句。
日志工厂
在配置详解的 settings 中提到了名为 logImpl 的选项,它的候选项目前只有下列几个,且默认是不实现:
- SLF4J
- LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING
- NO_LOGGING
如果没有特殊的要求(只是简单的控制台观察),可以使用标准日志工厂的实现,不需要额外的配置:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING">
</setting></settings>
Log4j 实现
- og4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等。
- 我们也可以控制每一条日志的输出格式。
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
先导入 Log4j 的依赖:
<dependency>
<groupid>log4j</groupid>
<artifactid>log4j</artifactid>
<version>1.2.17</version>
</dependency>
编写配置文件,文件名为 log4j.properties,直接放置在 resources 目录下。
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/ermao.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
可以直接使用了: