醋醋百科网

Good Luck To You!

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>

关键配置:

  1. transactionManager(事务管理器)
  2. type:JDBC或MANAGED
  3. JDBC:使用JDBC的事务管理
  4. MANAGED:容器管理事务
  5. 建议:Spring集成时通常不需要配置,由Spring管理事务
  6. dataSource(数据源)
  7. type:UNPOOLED|POOLED|JNDI
  8. UNPOOLED:不使用连接池
  9. POOLED:使用MyBatis内置连接池
  10. JNDI:容器提供数据源
  11. 专业建议:生产环境推荐使用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

语句类型(
STATEMENT/PREPARED/CALLABLE)

PREPARED

通常保持默认

resultSetType

结果集类型(
FORWARD_ONLY/SCROLL_INSENSITIVE/SCROLL_SENSITIVE)

驱动默认

大数据量考虑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>

元素详解:

  1. constructor - 用于实例化类时注入结果到构造方法
  2. idArg:ID参数,标记结果作为ID
  3. arg:普通注入到构造方法的参数
  4. id & result - 基本映射
  5. property:Java属性名
  6. column:数据库列名
  7. javaType:Java类型
  8. jdbcType:JDBC类型
  9. typeHandler:类型处理器
  10. association - 复杂类型关联(一对一)
  11. 可以使用resultMapselect实现延迟加载
  12. collection - 集合关联(一对多)
  13. ofType:集合中元素的类型
  14. 同样支持延迟加载
  15. discriminator - 鉴别器(根据值映射不同结果)
  16. 实现类似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的技术杂货库”,后期会有更多的干货以及资料下载。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言