【Mybatis】04 官方文档指北阅读 vol2 配置 其一
https://mybatis.org/mybatis-3/zh/configuration.html
配置
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
配置文档的顶层结构如下:
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
属性(properties)
这些属性可以在外部进行配置,并可以进行动态替换。
你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
例如:
<properties resource="org/mybatis/example/config.properties"> <property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/> </properties>
设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。
比如:
<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() 方法中传入属性值。
例如:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props); // ... 或者 ... SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:
- 首先读取在 properties 元素体内指定的属性。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
因此,
通过方法参数传递的属性具有最高优先级,
resource/url 属性中指定的配置文件次之,
最低优先级的则是 properties 元素中指定的属性。
测试
【我们测试这个配置标签】
<properties resource="mybatis.properties"> </properties>
【mybatis.properties文件 [ src\main\resources\mybatis.properties ]】
【注意!键名就是${key} 对应的键】
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
username = root
password = 123456
【更换默认环境】
【测试连接】
官方的说明中properties标签自己也可以设置配置参数,
但是配置文件的参数要优先于标签参数
不建议在标签里配置参数
【另外这个标签允许设置成自闭和标签】
<properties resource="mybatis.properties"/>
占位符配置默认参数
从 MyBatis 3.4.2 开始,
你可以为占位符指定一个默认值。
例如:
<dataSource type="POOLED"> <!-- ... --> <property name="username" value="${username:ut_user}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' --> </dataSource>
这个特性默认是关闭的。
要启用这个特性,需要添加一个特定的属性来开启这个特性。
例如:
<properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- 启用默认值特性 --> </properties>
【就在我们的mybatis.properties标签内设置】
我们把这个密码在properties配置文件删除后,使用默认占位符,依然能够正常使用
OGNL 表达式的三元运算符
如果你在属性名中使用了 ":" 字符(如:db:username),
或者在 SQL 映射中使用了 OGNL 表达式的三元运算符
(如: ${tableName != null ? tableName : 'global_constants'}),
就需要设置特定的属性来修改分隔属性名和默认值的字符。
例如:
<properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- 修改默认值的分隔符 --> </properties>
然后写三元占位符
<dataSource type="POOLED"> <!-- ... --> <property name="username" value="${db:username?:ut_user}"/> </dataSource>
【太长了我都得换个截图了】
一个配置完整的 settings 元素的示例如下:
<settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="autoMappingBehavior" value="PARTIAL"/> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> <setting name="defaultFetchSize" value="100"/> <setting name="safeRowBoundsEnabled" value="false"/> <setting name="mapUnderscoreToCamelCase" value="false"/> <setting name="localCacheScope" value="SESSION"/> <setting name="jdbcTypeForNull" value="OTHER"/> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> </settings>
【全写是不可能的,这辈子都不可能的】
【调几个重点的东西就行了】
- cacheEnabled 开启缓存 默认TRUE
- lazyLoadingEnabled 开启懒加载 默认FALSE
- mapUnderscoreToCamelCase 开启驼峰命名自动映射 默认FALSE
- logImpl 日志实现 未配置,需要手动
后面再一一使用
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。
它仅用于 XML 配置,意在降低冗余的全限定类名书写。
例如:
<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>
【type是完整的类限定名,alias表示对应的别名,在对实体类设置后,你既可以使用别名,也可以使用完全名,这没有问题】
当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases> <package name="domain.blog"/> </typeAliases>
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,
会使用 Bean 的首字母小写的非限定类名来作为它的别名。
比如 domain.blog.Author 的别名为 author;
【直接扫描这个包,里面的类名,即是别名,例如:cn.dai.pojo 然后在写SQL的参数属性时,直接写首字母小写的类名即可】
注解别名
若有注解,则别名为其注解值。见下面的例子:
@Alias("author") public class Author { ... }
Java常用类型别名
下面是一些为常见的 Java 类型内建的类型别名。
它们都是不区分大小写的,
注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
【也就是基本类型使用了前缀的下划线,其他类型统一小写】
类型处理器(typeHandlers)
MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时,
都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。
下表描述了一些默认的类型处理器。
提示 从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API)
你可以重写已有的类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。
具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口,
或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler,
并且可以(可选地)将它映射到一个 JDBC 类型。比如:
// ExampleTypeHandler.java @MappedJdbcTypes(JdbcType.VARCHAR) public class ExampleTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } }
在核心配置中声明
<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/> </typeHandlers>
使用上述的类型处理器将会覆盖已有的处理 Java String 类型的属性以及 VARCHAR 类型的参数和结果的类型处理器。
要注意 MyBatis 不会通过检测数据库元信息来决定使用哪种类型,
所以你必须在参数和结果映射中指明字段是 VARCHAR 类型,
以使其能够绑定到正确的类型处理器上。
这是因为 MyBatis 直到语句被执行时才清楚数据类型。
通过类型处理器的泛型,MyBatis 可以得知该类型处理器处理的 Java 类型,
不过这种行为可以通过两种方法改变:
- 在类型处理器的配置元素(typeHandler 元素)上增加一个 javaType 属性(比如:javaType="String");
- 在类型处理器的类上增加一个 @MappedTypes 注解指定与其关联的 Java 类型列表。 如果在 javaType 属性中也同时指定,则注解上的配置将被忽略。
可以通过两种方式来指定关联的 JDBC 类型:
- 在类型处理器的配置元素上增加一个 jdbcType 属性(比如:jdbcType="VARCHAR");
- 在类型处理器的类上增加一个 @MappedJdbcTypes 注解指定与其关联的 JDBC 类型列表。 如果在 jdbcType 属性中也同时指定,则注解上的配置将被忽略。
当在 ResultMap 中决定使用哪种类型处理器时,
此时 Java 类型是已知的(从结果类型中获得),
但是 JDBC 类型是未知的。
因此 Mybatis 使用 javaType=[Java 类型], jdbcType=null 的组合来选择一个类型处理器。
这意味着使用 @MappedJdbcTypes 注解可以限制类型处理器的作用范围,
并且可以确保,除非显式地设置,
否则类型处理器在 ResultMap 中将不会生效。
如果希望能在 ResultMap 中隐式地使用类型处理器,
那么设置 @MappedJdbcTypes 注解的 includeNullJdbcType=true 即可。
然而从 Mybatis 3.4.0 开始,如果某个 Java 类型只有一个注册的类型处理器,
即使没有设置 includeNullJdbcType=true,
那么这个类型处理器也会是 ResultMap 使用 Java 类型时的默认处理器。
最后,可以让 MyBatis 帮你查找类型处理器:
<!-- mybatis-config.xml --> <typeHandlers> <package name="org.mybatis.example"/> </typeHandlers>
注意在使用自动发现功能的时候,只能通过注解方式来指定 JDBC 的类型。
你可以创建能够处理多个类的泛型类型处理器。
为了使用泛型类型处理器, 需要增加一个接受该类的 class 作为参数的构造器,
这样 MyBatis 会在构造一个类型处理器实例的时候传入一个具体的类。
//GenericTypeHandler.java public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> { private Class<E> type; public GenericTypeHandler(Class<E> type) { if (type == null) throw new IllegalArgumentException("Type argument cannot be null"); this.type = type; } ...
EnumTypeHandler 和 EnumOrdinalTypeHandler 都是泛型类型处理器,
我们将会在接下来的部分详细探讨。
处理枚举类型
若想映射枚举类型 Enum,
则需要从 EnumTypeHandler 或者 EnumOrdinalTypeHandler 中选择一个来使用。
比如说我们想存储取近似值时用到的舍入模式。
默认情况下,MyBatis 会利用 EnumTypeHandler 来把 Enum 值转换成对应的名字。
注意 EnumTypeHandler 在某种意义上来说是比较特别的,
其它的处理器只针对某个特定的类,而它不同,它会处理任意继承了 Enum 的类。
不过,我们可能不想存储名字,相反我们的 DBA 会坚持使用整形值代码。
那也一样简单:在配置文件中把 EnumOrdinalTypeHandler 加到 typeHandlers 中即可,
这样每个 RoundingMode 将通过他们的序数值来映射成对应的整形数值。
<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/> </typeHandlers>
但要是你想在一个地方将 Enum 映射成字符串,在另外一个地方映射成整形值呢?
自动映射器(auto-mapper)会自动地选用 EnumOrdinalTypeHandler 来处理枚举类型,
所以如果我们想用普通的 EnumTypeHandler,就必须要显式地为那些 SQL 语句设置要使用的类型处理器。
(下一节才开始介绍映射器文件,如果你是首次阅读该文档,你可能需要先跳过这里,过会再来看。)
注意,这里的 select 语句必须指定 resultMap 而不是 resultType。
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.apache.ibatis.submitted.rounding.Mapper"> <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="funkyNumber" property="funkyNumber"/> <result column="roundingMode" property="roundingMode"/> </resultMap> <select id="getUser" resultMap="usermap"> select * from users </select> <insert id="insert"> insert into users (id, name, funkyNumber, roundingMode) values ( #{id}, #{name}, #{funkyNumber}, #{roundingMode} ) </insert> <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="funkyNumber" property="funkyNumber"/> <result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/> </resultMap> <select id="getUser2" resultMap="usermap2"> select * from users2 </select> <insert id="insert2"> insert into users2 (id, name, funkyNumber, roundingMode) values ( #{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler} ) </insert> </mapper>