MyBatis最核心主要就是全局配置文件和映射配置文件,全局配置文件主要用于设置MyBatis框架整体行为和属性,映射配置文件目的是配置应用对象与数据库数据关联映射。
01 全局配置文件
全局配置文件主要用于设置MyBatis框架整体行为和属性,比如属性配置、设置默认行为属性值、插件和环境等内容配置。需要注意,全局配置文件是有严格配置顺序要求,随意配置会导致解析报错。
MyBatis配置文件节点顺序参考文档:mybatis-3-config.dtd
xml
<!-- 配置 -->
<configuration>
<!-- 属性配置 -->
<properties />
<!-- 设置配置 -->
<settings>
<setting />
</settings>
<!-- 类型别名配置 -->
<typeAliases>
<typeAlias />
<package />
</typeAliases>
<!-- 类型处理器 -->
<typeHandlers>
<package />
<typeHandler />
</typeHandlers>
<!-- 对象工厂 -->
<objectFactory />
<!-- 插件配置 -->
<plugins>
<plugin />
</plugins>
<!-- 环境配置 -->
<environments>
<environment>
<!-- 事务管理器 -->
<transactionManager/>
<!-- 连接池 -->
<dataSource />
</environment>
</environments>
<!-- 数据库厂商 -->
<databaseIdProvider type=""></databaseIdProvider>
<!-- 映射文件 -->
<mappers>
<mapper/>
</mappers>
</configuration>
1.1 configuration
XML文档<configuration>
节点为MyBatis全局配置文件根标签,解析对象就是核心配置类Configuration,内部标签解析后与Configuration内部属性一一对应。
1.2 properties
标签<properties>
用来配置参数,比如最常见的数据库连接信息。为了避免配置参数与XML全局配置文件绑定,可以通过单独<properties>
属性文件维护实现解耦,配置文件仅需通过${}
引用即可。属性文件不仅支持相对和绝对路径文件,还支持网络路径属性文件。
xml
<configuration>
<!-- 相对路径 -->
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
xml
<configuration>
<!-- 相对路径 -->
<properties>
<property name="jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
</properties>
</configuration>
1.3 settings
MyBatis通过<settings>
标签调整框架运行时行为,包括缓存、延迟加载和执行器类型等内容。
设置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局开启或关闭配置文件所有映射器已经配置缓存 | true/false | false |
lazyLoadingEnabled | 延迟加载全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系可通过设置fetchType属性覆盖开关状态 | true/false | false |
aggressiveLazyLoading | 主动惰性加载。当开启时,任何方法调用都会加载该对象所有延迟加载属性。 否则,都会按需加载延迟加载属性(参考 lazyLoadTriggerMethods )。需要注意的是,在3.4.1及之前版本,默认值为true |
true / false | false |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集(需要兼容驱动),已废弃 | true/false | false |
useColumnLabel | 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动相关文档,或通过对比测试来观察 | true/false | false |
useGeneratedKeys | 允许JDBC支持自动生成主键,需要数据库驱动支持。 设置为true,强制使用自动生成主键,尽管驱动不兼容但仍可正常工作(比如 Derby) | true/false | false |
autoMappingBehavior | 指定自动映射数据库列到字段或属性。 NONE取消自动射,PARTIAL自动映射没有定义嵌套结果集结果集, FULL自动映射任意复杂的结果集 | NONEPARTIALFULL | PARTIAL |
autoMappingUnknownColumnBehavior | 指定自动映射目标未知列或者未知属性类型行为。 NONE不做任何反应,WARNING输出提醒日志(org.apache.ibatis.session.AutoMappingUnknownColumnBehavior 日志等级必须设置为WARN ),FAILING:映射失败 (抛出 SqlSessionException )异常 |
NONEWARNINGFAILING | NONE |
defaultExecutorType | 配置默认执行器。SIMPLE普通执行器,REUSE执行器会重用预处理语句(PreparedStatement),BATCH执行器重用语句并执行批量更新 | SIMPLEREUSEBATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,决定驱动等待数据库响应秒数 | 正整数 | 未设置 |
defaultFetchSize | 设置驱动结果集获取数量(fetchSize)建议值。此参数只可在查询设置被覆盖 | 正整数 | 未设置 |
safeRowBoundsEnabled | 是否允许嵌套语句使用分页(RowBounds)。如果允许设置为false | true/false | false |
safeResultHandlerEnabled | 是否允许嵌套语句使用结果处理器(ResultHandler)。如果允许设置为false | true/false | false |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则映射 | true/false | False |
localCacheScope | 利用本地缓存机制(Local Cache)防止循环引用和加速重复嵌套查询。 SESSION为缓存会话执行所有查询,STATEMENT为本地缓存仅用于执行语句,相同SqlSession不同查询不会进行缓存 | SESSIONSTATEMENT | SESSION |
jdbcTypeForNull | 当没有提供特定JDBC类型时,指定空值JDBC类型 | NULLVARCHAROTHER | OTHER |
lazyLoadTriggerMethods | 指定哪个对象方法触发一次延迟加载。用逗equals,clone,hashCode,toString |
参考描述 | 参考描述 |
defaultScriptingLanguage | 指定动态SQL生成默认语言。一个类型别名或完全限定类名,默认值为org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
参考描述 | 参考描述 |
defaultEnumTypeHandler | 指定Enum默认类型处理器TypeHandler 。可以为一个类型别名或完全限定类名,默认值org.apache.ibatis.type.EnumTypeHandler (新增于3.4.5) |
参考描述 | 参考描述 |
callSettersOnNulls | 指定结果集值为null是否调用映射对象setter(map对象为 put)方法,如果有依赖Map.keySet() 或null 值进行初始化比较有用。需要注意的是,基本类型(int、boolean等)不能设置成null。 |
true / false | false |
returnInstanceForEmptyRow | 当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (i.e. collectioin and association)。(从3.4.2开始)返回行所有列为空时,是否默认返回null 。 如果开启设置,MyBatis会返回一个空实例。 注意的是,同样也适用于嵌套结果集(新增于3.4.2) |
true/false | false |
logPrefix | 指定MyBatis增加到日志名称前缀 | 字符串 | 未设置 |
logImpl | 指定所用日志具体实现,未指定时将自动查找。可选值包括SLF4J、LOG4J(3.5.9 起废弃)、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING和NO_LOGGING | 参考描述 | 未设置 |
proxyFactory | 指定创建具有延迟加载对象所用到的代理工具。可选值包括CGLIB (3.5.10 起废弃)和JAVASSIST/CGLIBJAVASSIST | JAVASSIST | |
vfsImpl | 指定VFS实现。可选值为自定义VFS实现类全限定名,以逗号分隔 | 参考描述 | 未设置 |
useActualParamName | 是否允许使用方法参数名作为语句参数名称。前置条件是采用Java 8加上-parameters 选项编译(新增于3.4.1) |
true / false | true |
configurationFactory | 指定提供Configuration 实例工厂的类,必须包含static Configuration getConfiguration() 方法,用于加载反序列化对象延迟加载属性值(新增于 3.2.3) |
类型别名或全类名 | 未设置 |
nullableOnForEach | 为 foreach标签nullable属性指定默认值(新增于 3.5.9) | true/false | false |
argNameBasedConstructorAutoMapping | 构造器是否基于参数名称自动映射,而不是依赖列顺序(新增于 3.5.10) | true/false | false |
1.4 typeAliases
TypeAlias也就是类型别名,与Linux系统alias一样,主要用来简化类名全路径拼写。需要注意,如果涉及多库场景,可能存在类型重名问题。
xml
<configuration>
<!-- 类型别名 -->
<typeAliases>
<typeAlias alias="user" type="com.feiyu.model.User" />
</typeAliases>
</configuration>
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.boge.mapper.UserMapper">
<!-- 开启二级缓存 -->
<cache/>
<resultMap id="BaseResultMap" type="user">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="userName" column="user_name" jdbcType="VARCHAR"/>
<result property="realName" column="real_name" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="age" column="age" jdbcType="INTEGER"/>
<result property="dId" column="d_id" jdbcType="INTEGER"/>
</resultMap>
<select id="selectUserByBean" parameterType="user" resultType="user">
select
*
from
t_user
where user_name = #{userName}
</select>
</mapper>
MyBatis通过TypeAliasRegistry类,预先维护很多系统类型别名。
java
public class TypeAliasRegistry {
private final Map<String, Class<?>> typeAliases = new HashMap<>();
public TypeAliasRegistry() {
registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
registerAlias("ResultSet", ResultSet.class);
}
}
1.5 typeHandler
TypeHandler也就是类型处理器,用于实现Java类型对象与数据库JDBC类型互相转化实现。默认情况下,Mybatis通过TypeHandlerRegistry已注册很多TypeHandler,这也就是为啥查询会自动处理各种数据类型。
java
public final class TypeHandlerRegistry {
private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
public TypeHandlerRegistry() {
this(new Configuration());
}
public TypeHandlerRegistry(Configuration configuration) {
this.unknownTypeHandler = new UnknownTypeHandler(configuration);
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new StringTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, unknownTypeHandler);
register(Object.class, JdbcType.OTHER, unknownTypeHandler);
register(JdbcType.OTHER, unknownTypeHandler);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());
register(Instant.class, new InstantTypeHandler());
register(LocalDateTime.class, new LocalDateTimeTypeHandler());
register(LocalDate.class, new LocalDateTypeHandler());
register(LocalTime.class, new LocalTimeTypeHandler());
register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());
register(OffsetTime.class, new OffsetTimeTypeHandler());
register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());
register(Month.class, new MonthTypeHandler());
register(Year.class, new YearTypeHandler());
register(YearMonth.class, new YearMonthTypeHandler());
register(JapaneseDate.class, new JapaneseDateTypeHandler());
// issue #273
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
}
}
java
public class MyTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
System.out.println("---------------setNonNullParameter1:"+parameter);
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String name = rs.getString(columnName);
if("sys".equals(name)){
return String.format("<%s>", name);
}
return name;
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String name = rs.getString(columnIndex);
if("sys".equals(name)){
return String.format("<%s>", name);
}
return name;
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String name = cs.getString(columnIndex);
if("sys".equals(name)){
return String.format("<%s>", name);
}
return name;
}
}
xml
<configuration>
<typeHandlers>
<typeHandler handler="com.feiyu.type.MyTypeHandler"/>
</typeHandlers>
</configuration>
1.6 objectFactory
获取到数据库结果集后就需要转换为实体对象实例,转换过程并不明确实体类型,也就不能直接使用new
方式创建,只能借助反射方式创建。所以,MyBatis提供ObjectFactory工厂类接口,用于实现实体类对象创建。
java
public interface ObjectFactory {
// 设置参数时调用
default void setProperties(Properties properties) {
// NOP
}
// 创建对象(调用无参构造函数)
<T> T create(Class<T> type);
// 创建对象(调用带参数构造函数)
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
// 判断是否集合类
<T> boolean isCollection(Class<T> type);
}
ObjectFactory默认提供实现类DefaultObjectFactory,底层也就是通过反射模式创建所需实体对象,不过用户可以自定义对象工厂。
xml
public class MyObjectFactory extends DefaultObjectFactory {
@Override
public Object create(Class type) {
System.out.println("创建对象方法: " + type);
if (type.equals(User.class)) {
User blog = (User) super.create(type);
blog.setUserName("feiyu factory");
blog.setId(1);
blog.setRealName("feiyu");
return blog;
}
Object result = super.create(type);
return result;
}
}
xml
<configuration>
<objectFactory type="com.feiyu.objectfactory.MyObjectFactory"/>
</configuration>
1.7 plugins
跟很多框架类似,MyBatis预留插件接口扩展实现执行器(Executor)、参数处理器(ParameterHandler)、结果处理器(ResultSetHandler)和Statement处理器(StatementHandler)。
官方参考文档地址:mybatis.org/mybatis-3/z...
1.8 environments
<environments>
标签用来管理数据库环境,比如配置开发、测试和生产环境数据库。<environment>
标签代表一个数据环境,可以配置对应事务管理器(<transactionManager>
)和数据源(<dataSource>
)。
<transactionManager>
标签:如果配置为JDBC,则会使用Connection对象commit、rollback和close管理事务。如果配置成MANAGED,会把事务交给容器来管理,比如JBOSS,Weblogic。
xml
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
1.9 databaseIdProvider
MyBatis可以根据不同数据库厂商执行不同语句,基于映射语句中databaseId属性支持。首先精确匹配databaseId属性语句,其次匹配不带databaseId属性配置语句。
xml
<configuration>
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
</configuration>
需要注意,数据库厂商是解析mybatis配置时根据数据库厂商驱动获取到,比如MySQL固定值就是MySQL
。
java
public class XMLConfigBuilder extends BaseBuilder {
private void databaseIdProviderElement(XNode context) throws Exception {
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
String type = context.getStringAttribute("type");
// awful patch to keep backward compatibility
if ("VENDOR".equals(type)) {
type = "DB_VENDOR";
}
Properties properties = context.getChildrenAsProperties();
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
databaseIdProvider.setProperties(properties);
}
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
configuration.setDatabaseId(databaseId);
}
}
}
1.10 mappers
<mappers>
标签配置映射器,也就是Mapper.xml路径,配置目的是让MyBatis启动扫描这些映射器创建映射关系。MyBatis提供四种方式配置,包括相对路径、绝对路径、Mapper类完全限定名和包路径。
MyBatis官方Mapper参考文档地址:mybatis.org/mybatis-3/z...
xml
<configuration>
<mappers>
<!-- 相对路径 -->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
xml
<configuration>
<mappers>
<!-- 相对路径 -->
<mapper resource="file:///app/mybatis/mappers/UserMapper.xml"/>
</mappers>
</configuration>
xml
<configuration>
<mappers>
<!-- 映射器接口包名 -->
<package class="com.feiyu.mapper"/>
</mappers>
</configuration>
xml
<configuration>
<mappers>
<!-- 映射器接口完全限定类名 -->
<mapper name="com.feiyu.mapper.UserMapper"/>
</mappers>
</configuration>
02 映射配置文件
MyBatis持久化框架提供查询、插入、更新和删除操作与Java方法映射,映射关系通过MyBatis映射文件维护,通常称为Mapper XML文件实现。
MyBatis官方映射文件路径:mybatis.org/mybatis-3/z...
功能 | 内容 |
---|---|
定义SQL查询和操作 | Mapper XML文件定义查询、插入、更新和删除操作,可以包含参数和结果映射 |
参数映射 | Mapper XML文件指定如何映射方法参数到SQL语句参数 |
结果映射 | 定义如何将SQL查询结果映射到Java对象 |
命名空间 | Mapper XML文件通过唯一命名空间标识Mapper作用域,Mapper接口通常与Mapper XML文件命名空间相对应 |
动态 SQL | Mapper XML文件支持动态SQL,能够根据条件生成不同SQL查询 |
xml
<mapper>
<!-- 命名空间缓存配置 -->
<cache/>
<!-- 引用其它命名空间缓存配置 -->
<cache-ref/>
<!-- 描述数据库结果集与加载对象映射 -->
<resultMap/>
<!-- 老式风格参数映射, 已被废弃 -->
<parameterMap/>
<!-- 可重用语句块, 可被其它语句引用 -->
<sql/>
<!-- 插入语句映射 -->
<insert/>
<!-- 更新语句映射 -->
<update/>
<!-- 删除语句映射 -->
<delete/>
<!-- 查询语句映射 -->
<query/>
</mapper>
2.1 cache
MyBatis内置一个强大事务性查询缓存机制,可以非常方便配置和定制。默认情况下,仅开启本地会话缓存,如果需要开启全局二级缓存,需要再映射配置文件添加<cache/>
标签开启。
xml
<cache />
选项 | 明细 |
---|---|
缓存效果 | 1、映射语句文件所有select语句结果都会被缓存 2、 映射语句文件所有insert、update和delete语句会刷新缓存 3、缓存会使用最近最少算法(LRU, Least Recently Used)清除不需要缓存 4、 缓存不会定时进行刷新(也就是说,没有刷新间隔) 5、缓存会保存列表或对象1024个引用 6、缓存会被视为读/写缓存,也就是缓存对象并不共享,修改属于线程安全 |
缓存算法 | 1、 LRU (最近最少使用):移除最长时间不被使用对象 2、FIFO (先进先出):按照对象进入缓存顺序移除 3、SOFT (软引用):基于垃圾回收器状态和软引用规则移除对象 4、WEAK (弱引用):更积极地基于垃圾收集器状态和弱引用规则移除对象 |
MyBatis也支持自定义缓存,或者使用第三方缓存方案创建适配器,配置自定义缓存处理器。 |
xml
<mapper>
<cache type="com.feiyu.model.MyCustomCache">
<property name="cacheFile" value="/tmp/my-custom-cache.tmp"/>
</cache>
</mapper>
2.2 cache-ref
默认情况下,某一命名空间语句,只会使用当前命名空间缓存进行缓存或刷新。如果需要使用其他命名空间缓存共享数据,就需要使用<cache-ref>
进行引用才能使用。
xml
<mapper>
<cache-ref namespace="com.feiyu.mapper.SomeMapper"/>
</mapper>
2.3 resultMap
<resultMap>
标签定义SQL查询结果字段与实体属性映射关系,实现查询SQL按照映射关系加载Java实体对象。
xml
<mapper>
<resultMap id="BaseResultMap" type="user">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="userName" column="user_name" jdbcType="VARCHAR"/>
<result property="realName" column="real_name" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="age" column="age" jdbcType="INTEGER"/>
</resultMap>
</mapper>
2.4 sql
<sql>
标签用来定义可重用SQL代码片段,以便在其它语句可以使用。 参数可以静态确定,通过不同<include>
标签定义不同参数值。
xml
<mapper>
<sql id="dynamicSql">${table}.id, ${table}.username, ${table}.password</sql>
<select id="selectUsers" resultType="map">
select
<include refid="dynamicSql"><property name="table" value="t1"/></include>
from t_user t1
</select>
</mapper>
2.5 select
xml
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY"/>
属性 | 描述 |
---|---|
id | 命名空间唯一标识符,对应接口方法 |
parameterType | 输入参数类型。默认为未设置,MyBatis能根据类型处理器(TypeHandler)推断参数类型 |
parameterMap | 输入参数映射,已被废弃 |
resultType | 输出结果类型 |
resultMap | 输出结果映射,不能同时与resultType一起使用 |
flushCache | 是否清空本地和二级缓存,默认为false |
useCache | 是否使用二级缓存,默认为true |
timeout | 执行SQL语句超时毫秒数,默认未设置(数据库配置决定) |
fetchSize | 每次拉取数据库结果集行数,默认未设置(数据库配置决定) |
statementType | 语句类型,可选项为STATEMENT、PREPARED或CALLABLE |
resultSetType | 数据库游标处理方式,可选项为FORWARD_ONLY、SCROLL_SENSITIVE、SCROLL_INSENSITIVE或DEFAULT(等价于未设置),默认未设置(数据库配置决定) |
databaseId | 数据库厂商标识,与<databaseIdProvider> 配置选择数据库类型 |
resultOrdered | 是否指定构造方法参数顺序,属于<resultMap>/<constructor> 标签属性,默认false |
resultSets | 指定存储过程多个结果集,多结果集使用英文逗号分隔 |
2.5.1 resultOrdered
resultOrdered
用于指定实体类构造方法参数顺序,位于<resultMap>/<constructor>
标签属性。
java
@Data
public class User {
private int id;
private String username;
private String password;
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
}
xml
ini
<resultMap id="userResultMap" type="com.feiyu.model.User">
<constructor resultOrdered="true">
<idArg column="id" javaProperty="id"/>
<arg column="username" javaProperty="username"/>
<arg column="password" javaProperty="password"/>
</constructor>
</resultMap>
2.5.2 resultSets
resultSets
用于存储过程指定多个结果集处理方式。普通查询通常只返回一个结果集,但存储过程可以返回多个结果集。
xml
<!-- 存储过程返回用户和订单两个结果集 -->
<select id="getUserAndOrders" statementType="CALLABLE" resultSets="UserResultMap,OrderResultMap">
{CALL getUserAndOrders(#{userId, jdbcType=INTEGER, mode=IN, javaType=int})}
</select>
<resultMap id="UserResultMap" type="com.feiyu.model.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
</resultMap>
<resultMap id="OrderResultMap" type="com.feiyu.model.Order">
<id property="id" column="id"/>
<result property="orderId" column="order_id"/>
<result property="amount" column="amount"/>
</resultMap>
2.5.3 resultSetType
resultSetType
指定如何处理数据库游标(结果集类型),影响结果集滚动和更新行为。常见值有FORWARD_ONLY
、SCROLL_INSENSITIVE
和SCROLL_SENSITIVE
。
FORWARD_ONLY
:结果集只能向前滚动(默认)SCROLL_INSENSITIVE
:结果集可以滚动,对结果集更改不敏感SCROLL_SENSITIVE
:结果集可以滚动,对结果集更改敏感
xml
<select id="get" resultSetType="SCROLL_INSENSITIVE" resultType="com.feiyu.model.User">
SELECT id, username, password FROM users WHERE id = #{id}
</select>
2.5.4 databaseId
xml
<mapper>
<select id="SelectTime" resultType="String" databaseId="mysql">
select now() from dual
</select>
<select id="SelectTime" resultType="String" databaseId="oracle">
select 'oralce' || to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual
</select>
</mapper>
2.6 insert
xml
<mapper>
<insert
id="insertAuthor"
parameterType="com.feiyu.model.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20"/>
</mapper>
属性 | 描述 |
---|---|
id | 命名空间唯一标识符,对应接口方法 |
parameterType | 输入参数类型。默认为未设置,MyBatis能根据类型处理器(TypeHandler)推断参数类型 |
parameterMap | 输入参数映射,已被废弃 |
flushCache | 是否清空本地和二级缓存,默认为true |
timeout | 执行SQL语句超时毫秒数,默认未设置(数据库配置决定) |
statementType | 语句类型,可选项为STATEMENT、PREPARED或CALLABLE |
useGeneratedKeys | 是否使用自动生成的主键,默认值false |
keyProperty | 主键属性名。如果不止生成一个列,可以用逗号分隔多个属性名称。默认未设置 |
keyColumn | 主键对应的数据库列名。如果不止生成一个列,可以用逗号分隔多个属性名称。 |
databaseId | 数据库厂商标识,与<databaseIdProvider> 配置选择数据库类型 |
2.7 update
xml
<mapper>
<update
id="updateAuthor"
parameterType="com.feiyu.model.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
</mapper>
属性 | 描述 |
---|---|
id | 命名空间唯一标识符,对应接口方法 |
parameterType | 输入参数类型。默认为未设置,MyBatis能根据类型处理器(TypeHandler)推断参数类型 |
parameterMap | 输入参数映射,已被废弃 |
flushCache | 是否清空本地和二级缓存,默认为true |
timeout | 执行SQL语句超时毫秒数,默认未设置(数据库配置决定) |
statementType | 语句类型,可选项为STATEMENT、PREPARED或CALLABLE |
useGeneratedKeys | 是否使用自动生成的主键,默认值false |
keyProperty | 主键属性名。如果不止生成一个列,可以用逗号分隔多个属性名称。默认未设置 |
keyColumn | 主键对应的数据库列名。如果不止生成一个列,可以用逗号分隔多个属性名称。 |
databaseId | 数据库厂商标识,与<databaseIdProvider> 配置选择数据库类型 |
2.8 delete
xml
<mapper>
<delete
id="deleteAuthor"
parameterType="com.feiyu.model.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
</mapper>
属性 | 描述 |
---|---|
id | 命名空间唯一标识符,对应接口方法 |
parameterType | 输入参数类型。默认为未设置,MyBatis能根据类型处理器(TypeHandler)推断参数类型 |
parameterMap | 输入参数映射,已被废弃 |
flushCache | 是否清空本地和二级缓存,默认为true |
timeout | 执行SQL语句超时毫秒数,默认未设置(数据库配置决定) |
statementType | 语句类型,可选项为STATEMENT、PREPARED或CALLABLE |
useGeneratedKeys | 是否使用自动生成的主键,默认值false |
databaseId | 数据库厂商标识,与<databaseIdProvider> 配置选择数据库类型 |