MyBatis配置详解:从入门到精通
MyBatis是一款优秀的持久层框架,其核心配置文件(通常是mybatis-config.xml)包含了框架运行所需的各种设置。下面我将详细解析MyBatis的核心配置属性,并提供专业分析和使用建议。
一、 配置文件基本结构
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <!-- 配置内容 -->
</configuration>二、核心配置属性详解
2.1 properties(属性)
<properties resource="db.properties">
  <property name="username" value="dev_user"/>
</properties>属性:
- resource:指定外部properties文件的位置
 - url:通过URL指定外部properties文件的位置
 
子元素:
- property:定义单个属性
 
分析:
- 属性可以外部化配置,便于不同环境切换
 - 加载顺序:先读取properties元素体内的属性,然后读取resource/url指定的属性,后者的属性会覆盖前者
 - 专业建议:生产环境推荐使用外部properties文件,避免将敏感信息硬编码在配置文件中
 
2.2 settings(设置)
<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <!-- 更多设置 -->
</settings>重要设置详解:
设置名  | 描述  | 默认值  | 建议值  | 
cacheEnabled  | 全局开启或关闭缓存  | true  | 生产环境建议true  | 
lazyLoadingEnabled  | 延迟加载的全局开关  | false  | 根据业务需求  | 
aggressiveLazyLoading  | 当开启时,任何方法的调用都会加载该对象的所有属性  | false  | 建议false  | 
mapUnderscoreToCamelCase  | 自动将数据库下划线命名转为Java驼峰命名  | false  | 建议true  | 
jdbcTypeForNull  | 当没有为参数指定jdbcType时,空值的默认JDBC类型  | OTHER  | 建议NULL  | 
logImpl  | 指定MyBatis所用日志的具体实现  | 无  | SLF4J或Log4j2  | 
专业分析:
- 延迟加载设置需要权衡性能与N+1查询问题
 - 缓存设置对性能影响重大,需结合二级缓存策略
 - 日志实现建议使用现代日志框架如SLF4J
 
2.3 typeAliases(类型别名)
<typeAliases>
  <typeAlias alias="User" type="com.example.model.User"/>
  <package name="com.example.model"/>
</typeAliases>属性:
- alias:别名
 - type:Java类全限定名
 - package:指定包名,自动扫描该包下的类,别名默认为类名(首字母小写)
 
分析:
- 减少全限定类名的冗余输入
 - 自动扫描功能在大型项目中特别有用
 - 注意:别名冲突时,后定义的会覆盖先定义的
 
2.4 typeHandlers(类型处理器)
<typeHandlers>
  <typeHandler handler="com.example.MyTypeHandler"/>
  <package name="com.example.handlers"/>
</typeHandlers>作用:
- 用于Java类型与JDBC类型之间的转换
 - 可以自定义处理器处理特殊类型
 
专业建议:
- 优先使用MyBatis内置的类型处理器
 - 自定义处理器应确保线程安全
 - 复杂类型转换推荐使用自定义处理器
 
2.5 objectFactory(对象工厂)
<objectFactory type="com.example.MyObjectFactory">
  <property name="someProperty" value="100"/>
</objectFactory>作用:
- 创建结果集对象的实例
 - 可以自定义以实现依赖注入等高级功能
 
分析:
- 大多数情况下不需要自定义
 - 与Spring等DI框架集成时可能有用
 
2.6 plugins(插件)
<plugins>
  <plugin interceptor="com.example.MyPlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins>作用:
- 通过拦截器实现MyBatis核心行为的拦截和增强
 - 可用于分页、性能监控、SQL改写等
 
专业分析:
- 插件是MyBatis最强大的扩展点之一
 - 实现原理基于JDK动态代理
 - 注意拦截方法的性能影响
 - 多个插件执行顺序与配置顺序相同
 
2.7 environments(环境配置)
<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
      <!-- 数据源配置 -->
    </dataSource>
  </environment>
</environments>关键配置:
- transactionManager(事务管理器)
 - type:JDBC或MANAGED
 - JDBC:使用JDBC的事务管理
 - MANAGED:容器管理事务
 - 建议:Spring集成时通常不需要配置,由Spring管理事务
 - dataSource(数据源)
 - type:UNPOOLED|POOLED|JNDI
 - UNPOOLED:不使用连接池
 - POOLED:使用MyBatis内置连接池
 - JNDI:容器提供数据源
 - 专业建议:生产环境推荐使用DBCP2、HikariCP等专业连接池
 
2.8 databaseIdProvider(数据库厂商标识)
<databaseIdProvider type="DB_VENDOR">
  <property name="MySQL" value="mysql"/>
  <property name="Oracle" value="oracle"/>
</databaseIdProvider>作用:
- 支持多数据库厂商
 - 可根据不同数据库执行不同SQL
 
分析:
- 适用于需要支持多数据库的产品
 - 结合XML中的databaseId属性使用
 
2.9 mappers(映射器)
<mappers>
  <mapper resource="com/example/mapper/UserMapper.xml"/>
  <mapper class="com.example.mapper.UserMapper"/>
  <package name="com.example.mapper"/>
</mappers>配置方式:
- resource:类路径下的XML文件
 - url:文件系统或网络路径的XML文件
 - class:Mapper接口
 - package:包扫描
 
专业建议:
- 推荐使用包扫描方式,结合注解或XML
 - 接口与XML文件应保持相同目录结构
 - 注意避免XML与注解同时使用导致的冲突
 
三、Mapper.xml配置详解
3.1 Mapper 文件基本结构
<?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.example.mapper.UserMapper">
  <!-- SQL 映射定义 -->
</mapper>3.2 核心元素详解
3.2.1 select 查询语句
<select 
  id="selectUser" 
  parameterType="int" 
  resultType="User"
  resultMap="userResultMap"
  flushCache="false"
  useCache="true"
  timeout="10"
  fetchSize="256"
  statementType="PREPARED"
  resultSetType="FORWARD_ONLY"
  databaseId="mysql"
  lang="xml"
  resultOrdered="false">
  SELECT * FROM user WHERE id = #{id}
</select>属性详解:
属性  | 描述  | 默认值  | 最佳实践  | 
id  | 方法名,必须与接口方法名一致  | 无  | 保持命名一致性  | 
parameterType  | 参数类型  | 无  | 可省略,MyBatis会自动推断  | 
resultType  | 返回结果类型  | 无  | 简单类型时使用  | 
resultMap  | 复杂结果映射引用  | 无  | 复杂映射时优先使用  | 
flushCache  | 执行后清空本地/二级缓存  | false  | 查询通常设为false  | 
useCache  | 是否使用二级缓存  | true  | 频繁查询且不常改的数据可启用  | 
timeout  | 查询超时时间(秒)  | 无  | 根据DB性能设置  | 
fetchSize  | 获取记录数提示  | 无  | 大数据量查询优化  | 
statementType  | 语句类型(  | PREPARED  | 通常保持默认  | 
resultSetType  | 结果集类型(  | 驱动默认  | 大数据量考虑SCROLL  | 
databaseId  | 数据库厂商标识  | 无  | 多数据库支持时使用  | 
lang  | 动态SQL语言  | xml  | 自定义语言时使用  | 
resultOrdered  | 嵌套结果排序  | false  | 解决嵌套结果问题时使用  | 
专业分析:
- resultMap vs resultType:复杂对象关联映射必须使用resultMap
 - 缓存控制:对于实时性要求高的数据,可设置useCache="false"
 - 性能优化:大数据量查询适当设置fetchSize可减少内存消耗
 
3.2.2 insert/update/delete DML语句
<insert 
  id="insertUser" 
  parameterType="User"
  flushCache="true"
  timeout="20"
  statementType="PREPARED"
  useGeneratedKeys="true"
  keyProperty="id"
  keyColumn="id"
  databaseId="mysql">
  INSERT INTO user(name,email) VALUES(#{name},#{email})
</insert>特有属性:
属性  | 描述  | 默认值  | 最佳实践  | 
useGeneratedKeys  | 使用JDBC获取自增主键  | false  | 自增主键表必须设为true  | 
keyProperty  | 主键属性名  | 无  | 与实体类属性名一致  | 
keyColumn  | 主键列名  | 无  | 与数据库列名一致  | 
flushCache  | 执行后清空缓存  | true(insert/update/delete)  | 通常保持默认  | 
批量插入示例:
<insert id="batchInsert" useGeneratedKeys="true" keyProperty="id">
  INSERT INTO user (name,email) VALUES
  <foreach collection="list" item="item" separator=",">
    (#{item.name},#{item.email})
  </foreach>
</insert>专业建议:
- 批量操作使用foreach标签
 - Oracle等序列数据库需使用<selectKey>获取主键
 - 重要业务数据考虑添加@Transactional注解
 
3.2.3 resultMap 结果映射
<resultMap id="userResultMap" type="User">
  <constructor>
    <idArg column="id" name="id" javaType="int"/>
    <arg column="username" name="name" javaType="String"/>
  </constructor>
  <id property="id" column="id"/>
  <result property="username" column="name"/>
  <association property="role" javaType="Role" resultMap="roleResultMap"/>
  <collection property="posts" ofType="Post" select="selectPostsByUser"/>
  <discriminator javaType="int" column="type">
    <case value="1" resultMap="adminResultMap"/>
    <case value="2" resultMap="userResultMap"/>
  </discriminator>
</resultMap>元素详解:
- constructor - 用于实例化类时注入结果到构造方法
 - idArg:ID参数,标记结果作为ID
 - arg:普通注入到构造方法的参数
 - id & result - 基本映射
 - property:Java属性名
 - column:数据库列名
 - javaType:Java类型
 - jdbcType:JDBC类型
 - typeHandler:类型处理器
 - association - 复杂类型关联(一对一)
 - 可以使用resultMap或select实现延迟加载
 - collection - 集合关联(一对多)
 - ofType:集合中元素的类型
 - 同样支持延迟加载
 - discriminator - 鉴别器(根据值映射不同结果)
 - 实现类似switch-case的逻辑
 
专业建议:
- 复杂对象图优先使用resultMap而非嵌套select
 - N+1查询问题可通过联合查询+结果映射解决
 - 延迟加载对性能影响较大,需实际测试
 
3.2.4 sql 可重用SQL片段
<sql id="userColumns">id,username,email</sql>
<select id="selectUsers" resultType="User">
  SELECT <include refid="userColumns"/> FROM user
</select>最佳实践:
- 提取公共列名、条件语句
 - 支持<property>传递参数
 - 大型项目中可集中管理SQL片段
 
3.2.5 parameterMap (已废弃)
<!-- 不推荐使用 -->
<parameterMap id="userParamMap" type="User">
  <parameter property="id" jdbcType="INTEGER"/>
</parameterMap>注意:
- MyBatis 3已废弃parameterMap
 - 推荐使用内联参数映射
 
3.3 动态SQL标签
3.2.1 if 条件判断
<select id="findActiveUser" resultType="User">
  SELECT * FROM user WHERE state = 'ACTIVE'
  <if test="name != null">
    AND name LIKE #{name}
  </if>
</select>3.3.2 choose/when/otherwise 多重选择
<select id="findUser" resultType="User">
  SELECT * FROM user WHERE state = 'ACTIVE'
  <choose>
    <when test="id != null">
      AND id = #{id}
    </when>
    <when test="name != null">
      AND name LIKE #{name}
    </when>
    <otherwise>
      AND email IS NOT NULL
    </otherwise>
  </choose>
</select>3.3.3 trim/where/set 智能处理
<select id="findUser" resultType="User">
  SELECT * FROM user
  <where>
    <if test="id != null">id = #{id}</if>
    <if test="name != null">AND name LIKE #{name}</if>
  </where>
</select>
<update id="updateUser">
  UPDATE user
  <set>
    <if test="name != null">name = #{name},</if>
    <if test="email != null">email = #{email},</if>
  </set>
  WHERE id = #{id}
</update>3.3.4 foreach 循环遍历
<select id="selectUsersInIds" resultType="User">
  SELECT * FROM user WHERE id IN
  <foreach item="id" collection="list" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>参数说明:
- collection:集合属性名(可传List、Set、Map、数组)
 - item:当前元素变量名
 - index:索引变量名
 - open/close:包装符号
 - separator:分隔符
 
3.3.5 bind 变量绑定
<select id="selectUsers" resultType="User">
  <bind name="pattern" value="'%' + name + '%'"/>
  SELECT * FROM user WHERE name LIKE #{pattern}
</select>3.4 高级映射技巧
3.4.1 嵌套结果 vs 嵌套查询
嵌套结果(联合查询):
<resultMap id="blogResultMap" type="Blog">
  <id property="id" column="blog_id"/>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author" resultMap="authorResultMap"/>
</resultMap>
<select id="selectBlog" resultMap="blogResultMap">
  SELECT 
    b.id as blog_id,
    b.title as blog_title,
    a.id as author_id,
    a.name as author_name
  FROM blog b LEFT JOIN author a ON b.author_id = a.id
  WHERE b.id = #{id}
</select>嵌套查询(分次查询):
<resultMap id="blogResultMap" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>
<select id="selectBlog" resultMap="blogResultMap">
  SELECT * FROM blog WHERE id = #{id}
</select>
<select id="selectAuthor" resultType="Author">
  SELECT * FROM author WHERE id = #{id}
</select>对比分析:
- 嵌套结果:单次查询,性能更好,适合简单关联
 - 嵌套查询:支持延迟加载,适合复杂对象图
 - N+1问题:嵌套查询需注意关联查询次数
 
3.4.2 鉴别器高级用法
<resultMap id="vehicleResultMap" type="Vehicle">
  <discriminator javaType="String" column="vehicle_type">
    <case value="CAR" resultMap="carResultMap"/>
    <case value="TRUCK" resultMap="truckResultMap"/>
  </discriminator>
</resultMap>应用场景:
- 继承结构的数据库表示
 - 单表存储多种类型数据
 - 类似面向对象的多态行为
 
3.5 缓存配置
3.5.1 二级缓存配置
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"
  type="com.example.MyCustomCache"/>属性说明:
- eviction:回收策略(LRU/FIFO/SOFT/WEAK)
 - flushInterval:刷新间隔(ms)
 - size:缓存对象数量
 - readOnly:是否只读(性能更好)
 - type:自定义缓存实现
 
专业建议:
- 频繁读取很少修改的数据适合缓存
 - 注意缓存一致性,更新操作要清空缓存
 - 分布式系统需要实现自定义缓存
 
四、高级配置与最佳实践
4.1 多环境配置策略
<environments default="${environment}">
  <environment id="development">
    <!-- 开发环境配置 -->
  </environment>
  <environment id="production">
    <!-- 生产环境配置 -->
  </environment>
</environments>最佳实践:
- 使用properties文件管理环境变量
 - 结合Maven profiles实现构建时环境切换
 
4.2 自定义类型处理器
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {
  // 实现方法
}应用场景:
- 加密/解密字段
 - 特殊格式处理(如JSON、XML字段)
 - 枚举类型的自定义存储
 
4.3 插件开发要点
@Intercepts({
  @Signature(type= Executor.class, method="query", 
    args={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class ExamplePlugin implements Interceptor {
  // 实现方法
}关键点:
- 明确拦截的目标和方法
 - 注意拦截器链的执行顺序
 - 避免在插件中执行耗时操作
 
五、性能调优相关配置
5.1 缓存配置优化
<settings>
  <setting name="localCacheScope" value="SESSION"/>
</settings>选项:
- SESSION:缓存一个会话中执行的所有查询(默认)
 - STATEMENT:仅缓存单条语句
 
分析:
- SESSION级别在事务型应用中表现更好
 - STATEMENT级别可减少内存使用
 
5.2 批量操作优化
<settings>
  <setting name="defaultExecutorType" value="BATCH"/>
</settings>执行器类型:
- SIMPLE:普通执行器(默认)
 - REUSE:重用预处理语句
 - BATCH:批量更新优化
 
建议:
- 批量操作时使用BATCH执行器
 - 可通过SqlSessionFactory.openSession(ExecutorType.BATCH)临时切换
 
六、安全相关配置
6.1 SQL注入防护
- 始终使用#{}参数语法而非${}拼接
 - 对必须使用${}的场景进行严格过滤
 
6.2 敏感信息保护
- 数据库密码等敏感信息应使用加密properties文件
 - 或通过JNDI由容器管理数据源
 
关注我?别别别,我怕你笑出腹肌找我赔钱。
头条对markdown的文章显示不太友好,想了解更多的可以关注微信公众号:“Eric的技术杂货库”,后期会有更多的干货以及资料下载。
相关文章
- Spring Boot中对接Twilio以实现发送验证码和验证短信码
 - Spring Boot 3.5:这次更新让你连配置都不用写了,惊不惊喜?
 - Spring Boot+Pinot实战:毫秒级实时竞价系统构建
 - SpringBoot敏感配置项加密与解密实战
 - SpringBoot 注解最全详解,建议收藏!
 - Spring Boot 常用注解大全:从入门到进阶
 - SpringBoot启动之谜:@SpringBootApplication如何让配置化繁为简
 - Springboot集成Kafka原理_spring集成kafka的原理
 - Spring Boot中@Data注解的深度解析与实战应用
 - 大佬用1000字就把SpringBoot的配置文件讲的明明白白!
 
