mybatis.config 配置项介绍可参考官方文档:mybatis.config 官方入门手册
主要介绍和实践mybatis.config
文件中的配置参数具体是什么作用/效果。
将由易到难依次实践每个参数的效果,部分复杂的配置项可能需要结合spring框架进行实践(后续补充)。
常用设置(settings)
- logImpl: 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
- STDOUT_LOGGING 控制台日志
- NO_LOGGING 无日志
- SLF4J
- LOG4J
- LOG4J2
- DK_LOGGING
- COMMONS_LOGGING
这个比较好理解,配置日志输出方式,没有配置的话默认输出到控制台。下面是一个使用slf4j
当门面日志, log4j
当日志实现的配置 。(对了,log4j今天被扫描出来有漏洞,记得及时修复,官方补丁 )
<!--日志框架-->
<!--slf4j 门面日志框架包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<!--slf4j 绑定log4j的中间包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.32</version>
</dependency>
<!--log4j日志包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
复制代码
## log4j的形式就是 logger(日志输出源对象) - 绑定 appender(日志输出目的地)
# 配置根logger ,第一个为最低级别 [ level ] , appenderName1, appenderName2
log4j.rootLogger = debug , stdout , file
# 配置日志信息输出目的地
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
# 配置日志输出格式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} - %-4r %-5p [%t] %C:%L %x - %m%n
# 配置日志信息输出目的地
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
# 配置日志输出格式
log4j.appender.file.Encoding=UTF-8
# 输出文件位置此为项目根目录下的logs文件夹中
log4j.appender.file.File=D:/java/log/test.log
log4j.appender.file.DatePattern = '_'yyyy-MM-dd'.log'
# 配置file为自定义布局模式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
##日志输出目的地
#(1)org.apache.log4j.ConsoleAppender(控制台)
#(2)org.apache.log4j.FileAppender(文件)
#(3)org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
#(4)org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
#(5)org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
## 日志输出格式
#(1)org.apache.log4j.HTMLLayout(以HTML表格形式布局)
#(2)org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
#(3)org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
#(4)org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
复制代码
- mapUnderscoreToCamelCase : 是否开启驼峰命名自动映射
默认为关闭。开启后,比如数据库中的 own_phone
可以映射到实体对象的 ownPhone
上。
@Data
public class Student implements Serializable {
private static final long serialVersionUID = -1774428258743097453L;
private Integer id;
private String name;
private Integer age;
private String ownPhone;
}
复制代码
CREATE TABLE `student` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`age` int(11) DEFAULT '0',
`own_phone` varchar(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4
复制代码
- 未开启前,查询到的ownPhone都为null
INFO [main] com.test.MybatisApplicationRun:32 - Student(id=1, name=xiao, age=10, ownPhone=null)
INFO [main] com.test.MybatisApplicationRun:32 - Student(id=2, name=nana, age=11, ownPhone=null)
复制代码
- 开启后
INFO [main] com.test.MybatisApplicationRun:32 - Student(id=1, name=xiao, age=10, ownPhone=151123456)
INFO [main] com.test.MybatisApplicationRun:32 - Student(id=2, name=nana, age=11, ownPhone=151123435)
复制代码
-
useGeneratedKeys 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。 默认为 false
效果:当需要插入的对象中主键为空,打算由数据库来生成时,在执行完插入操作后,
是否将主键值回写到对象上
(也就是是否可以在java代码中直接在对象上获取到对象的主键列,而不是再执行一次查询)。示例:
private static void insertStudent(SqlSession sqlSession) { log.info("插入记录"); Student student = new Student(null, "mapper插入",10,"151213", "中国东边"); Long count = sqlSession.getMapper(StudentMapper.class).insertStudent(student); log.info("插入记录条数:{},student{}", count, student); } 复制代码
- 未开启时:可以看到 id 列为
null
DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - ==> Preparing: insert into student(id,name,age,own_phone,address) value(?, ?, ?, ?, ?) DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - ==> Parameters: null, mapper插入(String), 10(Integer), 151213(String), 中国东边(String) DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - <== Updates: 1 INFO [main] com.test.MybatisApplicationRun:45 - 插入记录条数:1,studentStudent(id=null, name=mapper插入, age=10, ownPhone=151213, address=中国东边) 复制代码
- 开启后: 可以看到此次自动生成的主键ID值为 1236
DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - ==> Preparing: insert into student(id,name,age,own_phone,address) value(?, ?, ?, ?, ?) DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - ==> Parameters: null, mapper插入(String), 10(Integer), 151213(String), 中国东边(String) DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - <== Updates: 1 INFO [main] com.test.MybatisApplicationRun:45 - 插入记录条数:1,studentStudent(id=1236, name=mapper插入, age=10, ownPhone=151213, address=中国东边) 复制代码
使用地方:
mybatis.config
中
<setting name="useGeneratedKeys" value="false"/> 复制代码
- xxxMapper.xml 中具体的语句
<insert id="insertStudentByXml" parameterType="student" useGeneratedKeys = true keyProperty="id"> <selectKey resultType="int" keyProperty="id" order="BEFORE" > SELECT FLOOR(RAND()*100) FROM DUAL </selectKey> insert into student(id,name,age,own_phone,address) value(#{id}, #{name}, #{age}, #{ownPhone}, #{address}) </insert> 复制代码
自动生成主键有两种方式,一种直接是数据库中自增 (比如mysql) ,第二种是使用
selectKey
标签生成主键。mysql 和 oracle 都支持第二种。- xxMapper.java 中具体的方法
/** * 插入学生 * @param student * @return */ @Insert("insert into student(id,name,age,own_phone,address) value(" + "#{id}, #{name}, #{age}, #{ownPhone}, #{address})") @Options(useGeneratedKeys = true, keyProperty = "id") Long insertStudent(Student student); 复制代码
- 影响范围 和优先级:
mybatis.config
<xxMapper.xml
,不影响xxMapper.java
一般建议,不配置mybatis.config, 在具体的语句上开启或者关闭即可。
- 未开启时:可以看到 id 列为
-
defaultExecutorType 配置默认的执行器。
SIMPLE 就是普通的执行器;
REUSE 执行器会重用预处理语句(PreparedStatement);
BATCH 执行器不仅重用语句还会执行批量更新。
如果需要使用批量更新,建议设置成 BATCH
。
示例:在一个sqlsession 中 ,插入 2万条记录,
- 使用xml 中的 foreach ,因为mysql每条sql 最大字节数为 1M,因此每次提交100条记录
(一般每次提交在100是比较合理的,java自带的orm框架JPA中批量提交默认也是50)
- simple 执行耗时:1310毫秒
- REUSE 执行耗时:1150毫秒
- BATCH 执行耗时:770毫秒
- 代码中使用fori
- simple 执行耗时:22411毫秒
- REUSE 执行耗时:21076毫秒
- BATCH 执行耗时:1524毫秒
复制代码
- multipleResultSetsEnabled 是否允许单个语句返回多结果集
建议参看:multipleResultSetsEnabled
我的理解是,执行存储过程,可以根据不同的参数返回不同的结果集,比如结果集1 对应实体A, 结果集2对应实体B
<resultMap id="studentMap" type="com.po.vo.Student">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="age" property="age" jdbcType="INTEGER"/>
<result column="address" property="address" jdbcType="VARCHAR"/>
<result column="own_phone" property="ownPhone" jdbcType="VARCHAR"/>
<result column="birthday" property="birthday" jdbcType="DATE"/>
</resultMap>
<resultMap id="teacherMap" type="com.po.vo.Teacher">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="age" property="age" jdbcType="INTEGER"/>
<result column="address" property="address" jdbcType="VARCHAR"/>
<result column="own_phone" property="ownPhone" jdbcType="VARCHAR"/>
<result column="birthday" property="birthday" jdbcType="DATE"/>
</resultMap>
<select id="selectStudent" resultMap="studentMap, teacherMap" >
select * from Student
</select>
复制代码
对于mysql数据库,如果上面这样配置,可以正常查询,但是返回的结果集只能是Student类型的集合。
//TODO 后面抽时间再拔下源码
建议默认设置
-
autoMappingBehavior : 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)
默认值:PARTIAL
- 开启
INFO [main] com.test.MybatisApplicationRun:38 - {"age":10,"id":1,"name":"xiao","ownPhone":"151123456"} INFO [main] com.test.MybatisApplicationRun:38 - {"age":11,"id":2,"name":"nana","ownPhone":"151123435"} 复制代码
- 关闭
INFO [main] com.test.MybatisApplicationRun:38 - null INFO [main] com.test.MybatisApplicationRun:38 - null 复制代码
-
autoMappingUnknownColumnBehavior 指定发现自动映射目标未知列(或未知属性类型)的行为。默认为 NONE
NONE
: 不做任何反应
未发现任何异常
WARNING
: 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior'
的日志等级必须设置为WARN
)
只设置 WARNING ,不配置日志logger,跟默认无区别;
配置logger 后#在log4j.properties中新增自定义logger的级别 org.apache.ibatis.session.AutoMappingUnknownColumnBehavior = WARN 日志输出: WARN [main] org.apache.ibatis.session.AutoMappingUnknownColumnBehavior$2:47 - Unknown column is detected on 'com.mybatis.mapper.StudentMapper.selectStudent' auto-mapping. Mapping parameters are [columnName=address,propertyName=address,propertyType=null] 复制代码
FAILING
: 映射失败 (抛出SqlSessionException
)
Cause: org.apache.ibatis.session.SqlSessionException: Unknown column is detected on 'com.mybatis.mapper.StudentMapper.selectStudent' auto-mapping. Mapping parameters are [columnName=address,propertyName=address,propertyType=null] at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:135) 复制代码
-
useColumnLabel : 使用列标签代替列名,默认开启
-
jdbcTypeForNull : 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
mysql 对于null值,即使没有设置 JdbcType也能正常入库;
oracle 对于null 值,如果没有设置 JdbcType ,将无法正常入库,会报错,建议使用oracle数据库的可以设置为 NULL ,或者给每个字段都设置jdbcType ,比如#{birthday,jdbcType=DATE}
-
shrinkWhitespacesInSql : 从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5) |
-
defaultScriptingLanguage 指定动态 SQL 生成使用的默认脚本语言。
-
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存 默认为 true
-
lazyLoadingEnabled 延迟加载的全局开关
-
aggressiveLazyLoading 开启时,任一方法的调用都会加载该对象的所有延迟加载属性
-
localCacheScope MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。
以上几个延迟和缓存相关的参数都是为了mybatis用来解决循环依赖的情况,具体可以查询下相关资料
无意义或无效设置
- defaultSqlProviderType: 给类似
@SelectProvider
指定默认的type
@SelectProvider 语法如下,其实就是生成一个sql
public interface StudentMapper {
/**
* 演示使用注解 @SelectProvider 执行sql操作
* @return
*/
@SelectProvider(type = StudentMapperProvider.class, method = "getSql")
List<Student> getStudentListByAnnation();
class StudentMapperProvider{
public String getSql() {
SQL sql = new SQL();
sql.FROM("student");
sql.SELECT("*")
.WHERE("1=1");
return sql.toString();
}
}
}
复制代码
@Slf4j
public class MybatisApplicationRun {
public static void main(String[] args) {
String mybatisConfig = "mybatisConfig.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(mybatisConfig);
} catch (IOException e) {
log.error("mybatis配置文件加载出错:" + e.getMessage(), e);
}
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Student> list = sqlSession.selectList("com.mybatis.mapper.StudentMapper." + "selectStudent");
list.forEach(i -> log.info(JSONObject.toJSONString(i, SerializerFeature.WriteNullStringAsEmpty)));
log.info("使用@selectProvider进行数据库查询");
List<Student> list2 = sqlSession.getMapper(StudentMapper.class).getStudentListByAnnation();
list2.forEach(i -> log.info(JSONObject.toJSONString(i, SerializerFeature.WriteNullStringAsEmpty)));
sqlSession.close();
}
}
复制代码
输出日志如下:
[frame] 2021-12-12 00:30:50,447 - 459 INFO [main] com.test.MybatisApplicationRun:35 - {"age":10,"id":1,"name":"xiao","ownPhone":"151123456"}
[frame] 2021-12-12 00:30:50,447 - 459 INFO [main] com.test.MybatisApplicationRun:35 - {"age":11,"id":2,"name":"nana","ownPhone":"151123435"}
[frame] 2021-12-12 00:30:50,447 - 459 INFO [main] com.test.MybatisApplicationRun:36 - 使用@selectProvider进行数据库查询
[frame] 2021-12-12 00:30:50,447 - 459 DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - ==> Preparing: SELECT * FROM student WHERE (1=1)
[frame] 2021-12-12 00:30:50,447 - 459 DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - ==> Parameters:
[frame] 2021-12-12 00:30:50,458 - 470 DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger:143 - <== Total: 2
[frame] 2021-12-12 00:30:50,458 - 470 INFO [main] com.test.MybatisApplicationRun:38 - {"age":10,"id":1,"name":"xiao","ownPhone":"151123456"}
[frame] 2021-12-12 00:30:50,458 - 470 INFO [main] com.test.MybatisApplicationRun:38 - {"age":11,"id":2,"name":"nana","ownPhone":"151123435"}
复制代码
- defaultStatementTimeout : 设置超时时间,它决定数据库驱动等待数据库响应的秒数。
经过测试发现,没有设置该值时,mysql的默认超时在4秒
左右,设置该值为1秒
或者 10秒
等没有太大的影响。用的是mysql5.7.24
, oracle 没有试验
[frame] 2021-12-12 01:20:22,110 - 181 DEBUG [main] org.apache.ibatis.transaction.jdbc.JdbcTransaction:136 - Opening JDBC Connection
[frame] 2021-12-12 01:20:26,240 - 4311 ERROR [main] com.test.MybatisApplicationRun:38 -
### Error querying database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
复制代码
-
vfsImpl : 指定 VFS 的实现 (无意义)
-
configurationFactory : 指定一个提供
Configuration
实例的类
一般不这么写,直接生成一个configuration Bean即可
-
useActualParamName : 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上
-parameters
选项。(新增于 3.4.1)默认 true (无意义) -
logPrefix : 指定 MyBatis 增加到日志名称的前缀。 (无效)
-
defaultEnumTypeHandler : 指定 Enum 使用的默认
TypeHandler
(无意义,一般都不允许数据库中使用枚举值类型) -
defaultScriptingLanguage : 指定动态 SQL 生成使用的默认脚本语言。 (使用默认即可)
近期评论