三、配置介绍
由于数据库存在各种各样的差异,因此有些时候要做一些必要的配置。
此外通用 Mapper 还提供了一些控制参数和一些和主键策略相关的参数。
文档提供的参数基于 4.0 及以后的版本
有些参数仍然存在,但是由于不推荐使用,这里不会介绍(如 UUID)。
提醒:看配置前,一定要看第二章的对象关系映射,否则不会明白这些参数的用途。
参数的配置方式在第一章中,针对不同的集成环境都写了详细的文档。
通用 Mapper 提供了下面这些参数:
- mappers
- IDENTITY
- ORDER(别名: order, before)
- catalog
- schema
- notEmpty
- style
- enableMethodAnnotation
- useSimpleType
- usePrimitiveType
- simpleTypes
- enumAsSimpleType
- wrapKeyword
- checkExampleEntityClass
- safeDelete
- safeUpdate
- useJavaType
下面分别对这些参数进行介绍。
3.1 mappers
在 4.0 以前这是一个非常重要的参数,当时只有通过 mappers 配置过的接口才能真正调用,由于很多人不注意看文档,通用 Mapper 90% 的问题都出在这个参数上。
4.0 之后,增加了一个 @RegisterMapper
注解,通用 Mapper 中提供的所有接口都有这个注解,有了该注解后,通用 Mapper 会自动解析所有的接口,如果父接口(递归向上找到的最顶层)存在标记该注解的接口,就会自动注册上。因此 4.0 后使用通用 Mapper 提供的方法时,不需要在配置这个参数。
当你自己扩展通用接口时,建议加上该注解,否则就要配置 mappers
参数。
3.2 IDENTITY
取回主键的方式,可以配置的值如 2.3.2 中所列的数据库类型:
- DB2:
VALUES IDENTITY_VAL_LOCAL()
- MYSQL:
SELECT LAST_INSERT_ID()
- SQLSERVER:
SELECT SCOPE_IDENTITY()
- CLOUDSCAPE:
VALUES IDENTITY_VAL_LOCAL()
- DERBY:
VALUES IDENTITY_VAL_LOCAL()
- HSQLDB:
CALL IDENTITY()
- SYBASE:
SELECT @@IDENTITY
- DB2_MF:
SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1
- INFORMIX:
select dbinfo('sqlca.sqlerrd1') from systables where tabid=1
配置时,写为:
IDENTITY=MYSQL
这个参数配置的同时,还经常伴着 3.2 中的 ORDER 参数。
3.3 ORDER(别名: order, before)
<selectKey>
中的order
属性,可选值为BEFORE
和AFTER
。
后来为了方便在 Spring Boot 中配置该参数,符合 Boot 的规范,增加了 order
和 before
两个别名。
在 3.1 的配置以及 2.3.2 和 2.3.3 中都提到了这个参数。
在支持主键递增,满足 2.3.2 中的情况时,配置如下:
//Properties 方式配置时
ORDER=AFTER
//还可以
order=AFTER
//或
before=false
//Spring Boot 中,比上面多个前缀,并且 ORDER 不能使用
mapper.order=AFTER
//或者(Spring Boot)
mapper.before=false
在类似Oracle序列或者通用的 UUID 时,配置如下:
//Properties 方式配置时
ORDER=BEFORE
//还可以
order=BEFORE
//或
before=true
//Spring Boot 中,比上面多个前缀,并且 ORDER 不能使用
mapper.order=BEFORE
//或者(Spring Boot)
mapper.before=true
上面示例中有多种写法,使用时按照需要选择一种即可,切勿同时配置!
3.4 catalog
数据库的catalog
,如果设置该值,查询的时候表名会带catalog
设置的前缀。
3.5 schema
同catalog
,catalog
优先级高于schema
。
3.6 notEmpty
insertSelective
和 updateByPrimaryKeySelective
中,是否判断字符串类型 !=''
。
配置方式:
notEmpty=true
3.7 style
实体和表转换时的默认规则,在 2.2 和 2.2.1 中都提到了这个参数,可选值如下:
- normal:原值
- camelhump:驼峰转下划线
- uppercase:转换为大写
- lowercase:转换为小写
- camelhumpAndUppercase:驼峰转下划线大写形式
- camelhumpAndLowercase:驼峰转下划线小写形式
配置方式如下:
style=camelhumpAndUppercase
3.8 enableMethodAnnotation
可以控制是否支持(getter 和 setter)在方法上使用注解,默认false
。
配置方式如下:
enableMethodAnnotation=true
启用后,可以按照下面方式使用:
private String name;
@Column(name = "user_name")
public void setName(String name){
this.name = name;
}
3.9 useSimpleType
默认 true
,启用后判断实体类属性是否为表字段时校验字段是否为简单类型,如果不是就忽略该属性,这个配置优先级高于所有注解。
注意:byte, short, int, long, float, double, char, boolean 由于存在默认值,这里不会作为简单类型对待!也就是默认情况下,这些字段不会和表字段进行映射。2.2.5 中也强调了这一点。
配置方式如下:
useSimpleType=true
3.10 usePrimitiveType
为了方便部分还在使用基本类型的实体,增加了该属性,只有配置该属性,并且设置为 true
才会生效,启用后,会扫描 8 种基本类型。
配置方式如下:
usePrimitiveType=true
3.11 simpleTypes
默认的简单类型在 SimpleTypeUtil
中,使用该参数可以增加额外的简单类型,通过逗号隔开的全限定类名添加。
配置方式如:
simpleTypes=xxx.GenderEnum,xxx.JobEnum
3.12 enumAsSimpleType
用于配置是否将枚举类型当成基本类型对待。
默认 simpleType 会忽略枚举类型,使用 enumAsSimpleType 配置后会把枚举按简单类型处理,需要自己配置好 typeHandler
。
配置方式如下:
enumAsSimpleType=true
3.13 wrapKeyword
配置后会自动处理关键字,可以配的值和数据库有关。
例如 sqlserver 可以配置为 [{0}]
,使用 {0}
替代原来的列名。
MySql 对应的配置如下:
wrapKeyword=`{0}`
使用该配置后,类似 private String order
就不需要通过 @Column
来指定别名。
3.14 checkExampleEntityClass
默认 false
用于校验通用 Example
构造参数 entityClass
是否和当前调用的 Mapper<EntityClass>
类型一致。
假设存在下面代码:
Example example = new Example(City.class);
example.xxx...;//设置条件的方法
countryMapper.selectByExample(example);
注意,这里使用 City
创建的 Example
,本该使用 cityMapper
来调用,但是这里使用了 countryMapper
,默认情况下会出现字段不匹配的错误,更特殊的情况下会正好匹配字段,但是却操作错了表!
配置该字段为 true
后就会对不匹配的情况进行校验!
配置如下:
checkExampleEntityClass=true
3.15 safeDelete
配置为 true 后,delete 和 deleteByExample 都必须设置查询条件才能删除,否则会抛出异常。
配置如下:
safeDelete=true
使用效果:
Caused by: tk.mybatis.mapper.MapperException: 通用 Mapper 安全检查: 当前操作的方法没有指定查询条件,不允许执行该操作!
at tk.mybatis.mapper.util.OGNL.notAllNullParameterCheck(OGNL.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.ibatis.ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:899)
at org.apache.ibatis.ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1544)
... 53 more
3.16 safeUpdate
配置为 true 后,updateByExample 和 updateByExampleSelective 都必须设置查询条件才能删除,否则会抛出异常(org.apache.ibatis.exceptions.PersistenceException
)。
updateByPrimaryKey 和 updateByPrimaryKeySelective 由于要求必须使用主键,不存在这个问题。
配置如下:
safeUpdate=true
使用效果:
Caused by: tk.mybatis.mapper.MapperException: 通用 Mapper 安全检查: 当前操作的方法没有指定查询条件,不允许执行该操作!
at tk.mybatis.mapper.util.OGNL.notAllNullParameterCheck(OGNL.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.ibatis.ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:899)
at org.apache.ibatis.ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1544)
... 53 more
3.17 useJavaType
设置 true 时,参数中会增加 javaType 设置,如 {id, javaType=java.lang.Long}
。在 <resultMap>
中也会设置 javaType
属性。
配置如下:
useJavaType=true
对于使用 User extends Pk<Long>
形式时,需要设置,否则 mybatis 低版本(<3.4.0) 无法识别类型。
建议升级到 mybatis 3.4.x 的最新版本
例如:
class Pk<T> {
private T id;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
}
class User extends Pk<Long> {
private String name;
}
如果不设置 javaType,低版本的 MyBatis 会认为 id 的类型为 Object。升级 MyBatis 到 3.4.0+ 最好。
设置 useJavaType
只对通用 Mapper 自己方法有效,自己写的其他方法还需要自己指定。
特别注意
使用 useJavaType=true 后,调用
ByPrimaryKey
类的方法时,需要按照实体中对应的类型来指定,例如主键类型为Long
时,必须mapper.selectByPrimaryKey(1L)
。不配置时,没有这个限制,可以使用
mapper.selectByPrimaryKey(1)
或mapper.selectByPrimaryKey("1")
等类型。