mybatis - [08] mybatis-config.xml 详解
mybatis-config.xml中的标签需要按照一定顺序配置,否则会有以下提示。
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
001 || properties(属性)
(1)属性可以放在jdbc.properties
中,也可以写在<property>
标签中
<!-- 第一种写法 -->
<properties resource="jdbc.properties"/>
<!-- 第二种写法 -->
<properties resource="jdbc.properties">
<property name="username" value="harley686"/>
<property name="password" value="harley666"/>
</properties>
(2)jdbc.properties
中进行如下配置
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456
(3)无论在<properties>
标签中引入.properties
配置文件还是使用<property>
标签设置的属性,都使用${value}
的方式取值
<?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>
<properties resource="jdbc.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>
<!-- 配置mapper.xml -->
<mappers>
<mapper resource="com/harley/dao/UserMapper.xml"/>
</mappers>
</configuration>
(4)测试结果
002 || settings(设置)
参考:https://mybatis.org/mybatis-3/zh_CN/configuration.html#settings
<settings>
<setting name="cacheEnabled" value="true"/> <!-- 缓存是否开启 -->
<setting name="lazyLoadingEnabled" value="true"/> <!--懒加载是否开启-->
<setting name="aggressiveLazyLoading" value="true"/> <!--开启时,任何方法的调用都会加载该对象的所有延迟加载属性。否则,每个延迟加载属性会按需加载。-->
<setting name="multipleResultSetsEnabled" value="true"/> <!--允许或禁止使用多结果集-->
<setting name="useColumnLabel" value="true"/> <!--使用列标签代替列名-->
<setting name="useGeneratedKeys" value="false"/> <!--自动生成主键是否开启,需要驱动支持-->
<setting name="autoMappingBehavior" value="PARTIAL"/><!--MyBatis 自动映射行为-->
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/><!--指定发现自动映射目标未知列(或未知属性类型)的行为-->
<setting name="defaultExecutorType" value="SIMPLE"/><!--配置默认的执行器。SIMPLE是普通的执行器;REUSE会复用预处理语句;BATCH可以实现批处理。-->
<setting name="defaultStatementTimeout" value="25"/><!--设置超时时间,它决定驱动等待数据库响应的秒数。-->
<setting name="defaultFetchSize" value="100"/><!--为驱动设置默认的fetchSize-->
<setting name="safeRowBoundsEnabled" value="false"/><!--允许在嵌套语句中使用分页-->
<setting name="safeResultHandlerEnabled" value="true"/><!--允许在嵌套语句中使用结果处理器-->
<setting name="mapUnderscoreToCamelCase" value="false"/> <!--是否开启自动驼峰命名规则映射-->
<setting name="localCacheScope" value="SESSION"/><!--利用本地缓存机制(Local Cache)防止循环引用和加速重复嵌套查询-->
<setting name="jdbcTypeForNull" value="OTHER"/><!--指定当JDBC参数为null时使用的JDBC类型-->
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/><!--指定哪些方法触发延迟加载-->
<setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver"/><!--指定默认的脚本语言-->
<setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/><!--指定默认的枚举类型处理器-->
<setting name="callSettersOnNulls" value="false"/><!--指定当结果集中值为null时,是否调用对象的 setter 方法-->
<setting name="returnInstanceForEmptyRow" value="false"/><!--当查询结果为空时,是否返回对象实例-->
<setting name="logPrefix" value="exampleLogPreFix_"/><!--指定 MyBatis 日志的前缀-->
<setting name="logImpl" value="SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING"/><!--指定 MyBatis 的日志实现-->
<setting name="proxyFactory" value="CGLIB | JAVASSIST"/><!--指定 MyBatis 创建动态代理对象的工厂-->
<setting name="vfsImpl" value="org.mybatis.example.YourselfVfsImpl"/><!--指定自定义的VFS实现类,默认为null-->
<setting name="useActualParamName" value="true"/><!--允许使用方法参数的真实名称-->
<setting name="configurationFactory" value="org.mybatis.example.ConfigurationFactory"/><!--指定一个ConfigurationFactory类,用于创建Configuration对象-->
</settings>
003 || typeAliases(类型别名)
mapper.xml
中会有很多resultType="com.harley.pojo.User"
,结果集类型填写的是Pojo类的全限定名,全限定名比较长,为了使用方便,为Pojo类设置类型别名。
(1)在mybatis-config.xml
中为Pojo类配置别名
<typeAliases>
<typeAlias alias="User" type="com.harley.pojo.User"/>
</typeAliases>
(2)在mapper.xml中使用别名
<select id="getUserLike" resultType="User">
select * from user where name like '%${value}%'
</select>
(3)测试结果
除了可以给类设置别名,还可以为包名设置别名
(1)为pojo类所在包设置别名
<typeAliases>
<package name="com.harley.pojo"/>
</typeAliases>
(2)可以在mapper.xml
中resultType="User"
(User必须和类名一致),也可以使用@Alias("harleyUser")
为pojo包下的实体类设置别名
注:使用lombok的注解
@AllArgsConstructor
、@NoArgsConstructor
、@Data
、@ToString
,可以省略getter/setter
、有参/无参构造方法、toString
方法的编写
(3)mapper.xml
中resultType="User"
需要和@Alias("User")
对应,别名是小写,mapper.xml中使用时也必须是小写!
<select id="getUserLike" resultType="harleyUser">
select * from user where name like '%${value}%'
</select>
(4)测试结果
总结:
(1)如果实体类数量比较少,使用第一种方式;如果实体类数量比较多,则使用第二种方式。
(2)第一种可以自定义别名,第二种不行。如果非要改,需要在实体类上加注解
@Alias("别名")
004 || typeHandlers(类型处理器)
用于实现Java类型和JDBC类型之间的相互转换。当Mybatis从数据库中读取数据或将数据写入数据库时,它会使用类型处理器来完成这些转换。
step1:自定义类型处理器
实现org.apache.ibatis.type.TypeHandler
接口或者继承org.apache.ibatis.type.BaseTypeHandler
抽象类
以下是将Java的LocalDate类型与JDBC的DATE类型进行转换的示例:
package com.harley.utils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.*;
import java.time.LocalDate;
/**
* @author harley
* @since 2025-02-15 21:33:11
*/
// 标记Java类型
@MappedTypes(LocalDate.class)
// 标记JDBC类型
@MappedJdbcTypes(JdbcType.DATE)
public class LocalDateTypeHandler extends BaseTypeHandler<LocalDate> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, LocalDate parameter, JdbcType jdbcType) throws SQLException {
ps.setDate(i, Date.valueOf(parameter));
}
@Override
public LocalDate getNullableResult(ResultSet rs, String columnName) throws SQLException {
Date date = rs.getDate(columnName);
return date != null ? date.toLocalDate() : null;
}
@Override
public LocalDate getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Date date = rs.getDate(columnIndex);
return date != null ? date.toLocalDate() : null;
}
@Override
public LocalDate getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Date date = cs.getDate(columnIndex);
return date != null ? date.toLocalDate() : null;
}
}
step2:注册类型处理器
在mybatis-config.xml中,使用<typeHandlers>元素来注册自定义的类型处理器。可以通过指定类名的方式逐个注册,也可以指定包名让Mybatis自动扫描包下的所有类型处理器。
逐个注册
<typeHandlers>
<typeHandler handler="com.harley.typeHandlers.LocalDateTypeHandler"/>
</typeHandlers>
批量注册
<typeHandlers>
<package name="com.harley.typeHandlers"/>
</typeHandlers>
step3:使用类型处理器
注册完成后,mybatis会自动使用这些类型处理器进行Java类型和JDBC类型的转换。在SQL映射文件(xxxMapper.xml)中,无需额外配置即可使用。
<select id="selectUserByDate" resultType="com.harley.pojo.User">
select * from mybatis.user where create_date = #{date}
</select>
这里的#{date}
如果是LocalDate
类型,Mybatis会自动使用LocalDateTypeHandler
进行类型转换。
step4:显示指定类型处理器
在某些情况下,需要在SQL映射文件中显示指定使用的类型处理器。可以使用typeHandler属性来指定
<select id="selectUserByDate" resultType="com.harley.pojo.User">
select * from user where create_date = #{date,typeHandler=com.harley.typeHandlers.LocalDateTypeHandler}
</select>
005 || objectFactory(对象工厂)
主要负责创建Java对象实例,使用场景如下:
(1)自定义对象创建逻辑
当默认的对象创建方式无法满足需求时,例如需要在创建对象时进行额外的初始化操作、注入特定的依赖或者根据不同条件创建不同类型的对象,就可以通过自定义ObjectFactory来实现。
(2)集成第三方依赖注入框架
如果项目中使用了如Spring这样的依赖注入框架,需要将依赖注入的逻辑与Mybatis的对象创建过程集成,自定义ObjectFactory可以实现这一点,确保创建的对象能正确注入所需的依赖。
(3)处理特殊对象创建需求
对于一些特殊的Java对象,可能需要特殊的创建方式,例如创建具有复杂构造函数的对象,或者需要从特定的对象池中获取对象,此时自定义ObjectFactory能满足这些特殊需求。
step1:自定义ObjectFactory
package com.harley.utils;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import java.util.List;
import java.util.Properties;
/**
* @author harley
* @since 2025-02-15 21:50:00
*/
public class CustomObjectFactory extends DefaultObjectFactory {
@Override
public <T> T create(Class<T> type) {
// 可以在这里添加自定义的对象创建逻辑
System.out.println("Using custom object factory to create object of type:" + type.getName());
return super.create(type);
}
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
// 可以在这里添加自定义的对象创建逻辑
System.out.println("Using custom object factory to create object of type: " + type.getName() + " with constructor args");
return super.create(type, constructorArgTypes, constructorArgs);
}
@Override
public void setProperties(Properties properties) {
// 可以处理传入的属性配置
super.setProperties(properties);
}
}
step2:在mybatis-config.xml中配置自定义ObjectFactory
<objectFactory type="com.harley.utils.CustomObjectFactory">
<!--可以在这里配置属性-->
<property name="propertyName" value="propertyValue"/>
</objectFactory>
step3:使用自定义ObjectFactory
配置完成后,MyBatis在创建对象时会自动使用自定义的ObjectFactory。
当执行查询操作并将结果映射到Java对象时,Mybatis会调用自定义ObjectFactory的create方法来创建对象实例。
<select id="selectUser" resultType="com.harley.pojo.User">
select * from mybatis.user where id = #{id}
</select>
当执行上述查询时,Mybatis会使用自定义的ObjectFactory来创建com.harley.pojo.User对象实例,并且会执行自定义ObjectFactory中重写的create方法里的逻辑。
比如,有一个pojo类为User,包含id、name、age属性。可以在自定义对象工厂(CustomObjectFactory)进行如下配置
@Override
public void setProperties(Properties properties) {
// 从配置属性中获取默认名称和年龄
this.defaultName = properties.getProperty("defaultName", "DefaultUser");
this.defaultAge = Integer.parseInt(properties.getProperty("defaultAge", "20"));
super.setProperties(properties);
}
@Override
public <T> T create(Class<T> type) {
if (type == User.class) {
// 创建 User 对象并使用默认值初始化
User user = new User();
user.setName(defaultName);
user.setAge(defaultAge);
return (T) user;
}
return super.create(type);
}
然后在mybatis-config.xml配置相关属性
<!-- 配置自定义 ObjectFactory -->
<objectFactory type="com.example.CustomObjectFactory">
<property name="defaultName" value="John"/>
<property name="defaultAge" value="25"/>
</objectFactory>
根据Resources.getResourceAsStream("mybatis-config.xml")作为inputStream,然后通过SqlSessionFactoryBuilder().build()方法返回sqlSessionFactory对象,该对象开启会话,进行查询时。会查到如下内容
User{id=1, name='John', age=25}
即为,可为pojo对象的属性进行初始化赋值,类似于Spring的依赖注入功能。
006 || plugins(插件)
常见的使用场景如下:
(1)分页功能:处理大量数据查询时,需要对结果进行分页展示。通过插件可以在SQL执行前动态修改SQL语句,添加分页逻辑,而无需在每个查询方法中手动编写分页代码。
(2)性能监控:对SQL语句的执行时间进行监控,帮助开发者找出性能瓶颈。插件可以在SQL执行前后记录时间,统计执行时长,并将这些信息输出到日志或监控系统中。
(3)数据加密与解密:在数据持久化到数据库之前对敏感数据进行加密,在从数据库查询数据时对加密数据进行解密。插件可以在参数处理和结果处理阶段插入加密和解密逻辑。
(4)SQL日志增强:除了MyBatis自带的日志功能,插件可以进一步增强SQL日志的输出,例如将SQL语句和实际参数进行格式化输出,方便调试和分析。
step1:自定义插件类
package com.harley.plugins;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import java.util.Properties;
/**
* @author harley
* @since 2025-02-15 22:15:06
*/
@Intercepts({
@Signature(type = StatementHandler.class,method="prepare",args = {java.sql.Connection.class,Integer.class})
})
public class CustomPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 在目标方法执行前插入自定义逻辑
System.out.println("Before statement prepare");
Object result = invocation.proceed();
System.out.println("After statement prepare");
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target,this);
}
@Override
public void setProperties(Properties properties) {
// 可以处理插件配置的属性
Interceptor.super.setProperties(properties);
}
}
@Intercepts
和@Signature
注解用于指定要拦截的目标类和方法。这里拦截的是StatementHandler
类的prepare
方法。intercept
方法是插件的核心逻辑,在目标方法执行前后可以插入自定义代码plugin
方法用于将插件应用到目标对象上setProperties
方法用于处理插件配置的属性
step2:在mybatis-config.xml中配置插件
<plugins>
<plugin interceptor="com.harley.plugins.CustomPlugin">
<!--可以配置插件属性-->
<property name="propertyName" value="propertyValue"/>
</plugin>
</plugins>
007 || environments(环境配置)
可以配置多个环境,但是每个
SqlSessionFactory
实例只能选择一种环境。mybatis默认的事务管理器(
transactionManager
)就是JDBC,连接池(dataSource
)是POOLED注意
<environments>
的default需要配置一个<environment>
的id
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
011 || mappers(映射器)
(1)使用<mapper>标签指定单个映射文件
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
(2)使用<mapper>标签指定单个映射接口
<mappers>
<mapper class="com.example.mapper.UserMapper"/>
</mappers>
使用该方法,UserMapper映射接口和UserMapper.xml映射文件必须在同一个包下,且名称必须一致。
(3)使用<package>标签批量扫描包
<mappers>
<package name="com.example.mapper"/>
</mappers>
使用该方法,UserMapper映射接口和UserMapper.xml映射文件必须在同一个包下,且名称必须一致。
— 业精于勤荒于嬉,行成于思毁于随 —
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2023-06-05 curl - 详解
2023-06-05 SSM - 狂神的项目示例