Mybatis学习笔记

原文: https://blog.gmem.cc/mybatis-study-note

 

简介

Mybatis是一个持久化层的Java框架,但是它并不是完整的ORM方案,它是以SQL为中心的,更像JOOQ而不是Hibernate。这意味着,如果使用Mybatis,你在某种程度上需要抛弃OO的领域模型设计(以对象为中心),转而以数据库表为中心进行设计。

Mybatis的特色是可以定制SQL语句(甚至是存储过程),这让你有很好的机会执行SQL优化,但很容易丢失数据库方面的可移植性。能够定制SQL,也使Mybatis能够很好的支持遗留数据库。

HelloWorld

本章结合一个非常简单的例子,介绍Mybatis的基本组件和基础用法。

Maven依赖
SqlSessionFactory 

每个Mybatis应用都是以一个SqlSessionFactory实例为中心的,你可以基于XML或者Java的方式,提供SqlSessionFactory的初始化参数。

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。

基于XML初始化

Java代码:

对应主配置文件:

基于Java代码初始化
映射器

上面两种初始化SqlSessionFactory的方式中,分别引用了UserMapper.xml文件、USerMapper类,这两个文件就是所谓的映射器(Mapper)。

映射器指定了SQL语句和Java类型之间的映射关系。Mybatis支持XML文件、Java注解两种映射器配置方式。

XML映射器

对应映射器文件,被主配置文件引用:

注解映射器

尽管基于注解的配置在各大框架的用户中都越来越流行,但是由于注解自身的限制,对于很多Mybatis的高级映射,XML映射方式是必须的。

如果存在和UserMapper.class在类路径上一致的UserMapper.xml文件,Mybatis会自动将其加载进来作为映射补充。如果两者存在重复映射语句,Mybatis会报错。

SqlSession 

该类包含了面向数据库执行 SQL 命令所需的所有方法,日常工作主要通过它进行。

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,不能被共享。

基于XML映射器的用法
基于注解映射器的用法

可以看到,对于简单语句来说,注解使代码显得更加简洁。但是Java注解对于稍微复杂的语句就会力不从心并且会显得更加混乱,因此业务复杂的话,最好使用XML风格的映射器。

主配置文件

前面提到的mybatis-config.xml,就是Mybatis主配置文件,定制此文件可以在很大程度上改变Mybatis的行为。该配置文件的根元素是configuration。

properties

可以定义一系列属性,让配置文件其它地方基于 ${prop} 的语法引用。你可以引用外部的Java属性文件:

也可以使用子元素直接指定属性:

甚至两种方式混合使用。 属性优先级由高到低:

  1. SqlSessionFactoryBuilder.build()中传递的属性
  2. 通过resource指定的Java属性文件中的属性
  3. property子元素指定的属性
settings

该元素的setting子元素可以改变Mybatis的行为,在子元素setting中,可以指定以下项:

设置项 说明
cacheEnabled Boolean=true,所有映射器中配置的缓存的全局开关
lazyLoadingEnabled Boolean=false,如果true,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态
aggressiveLazyLoading Boolean=true,如果true,对任意延迟属性的调用会使带有延迟加载属性的对象(该属性引用的对象)完整(激进)加载;反之,每种属性将会按需加载
multipleResultSetsEnabled Boolean=true,是否允许单一语句返回多结果集(需要兼容驱动)
useColumnLabel Boolean=true,使用列标签代替列名。不同的驱动在这方面会有不同的表现
useGeneratedKeys Boolean=false,如果true,强制自动生成主键
defaultExecutorType

Enum(SIMPLE|REUSE|BATCH)=SIMPLE。设置默认的SQL执行器:

  1. SIMPLE,普通的执行器
  2. REUSE,重用预处理语句
  3. BATCH,重用预处理语句并执行批量更新
defaultStatementTimeout SQL执行超时的秒数
defaultFetchSize 给驱动提示,通知抓取数据的跳数,单个查询可以覆盖之
safeRowBoundsEnabled Boolean=false,是否允许在嵌套语句中使用分页(RowBounds),如果允许设置为fasle
safeResultHandlerEnabled Boolean=true,是否允许在嵌套语句中使用分页(ResultHandler),如果允许设置为fasle
mapUnderscoreToCamelCase

Boolean=false,是否把基于下划线的数据库列映射为驼峰式大小写

该设置项和自动映射机制有关,Mybatis的默认映射方式是:列名、属性名不区分大小写的想等,则匹配

localCacheScope

Enum(SESSION | STATEMENT)=SESSION。Mybatis使用本地缓存机制(Local Cache)来防止循环引用、加速重复嵌套查询:

  1. SESSION,会话中所有语句共享缓存,类似于Hibernate一级缓存
  2. STATEMENT,仅单个语句内部使用缓存
lazyLoadTriggerMethods Enum(equals|clone|hashCode|toString),逗号分隔。哪些方法会触发对象的延迟加载
defaultScriptingLanguage 指定动态SQL生成使用的默认语言
callSettersOnNulls Boolean=false,当结果集中值为NULL时,是否调用实体的setter或者Map的Put
logImpl Enum(SLF4J | LOG4J|...)指定Mybatis使用的日志实现,默认自动查找
proxyFactory Enum(JAVASSIST|CGLIB)=JAVASSIS,创建延迟加载对象时使用的代理库
typeAliases

该参数仅用于XML配置风格,其子元素typeAlias为某个Java类设置别名:

或者指定Java类所在的包名,这样,包内所有Java类的Base name自动别设置为别名:

你可以在映射器配置中,使用别名来引用一个Java类,别名更加短小。

内置别名

Mybatis为常用的JDK内置类型已经建好了大小写无关的别名,例如:

别名 Java类型
_byte byte
byte Byte
decimal BigDecimal
object Object
collection Collection
map Map
hashmap HashMap
list List
arraylist ArrayList
iterator Iterator
typeHandlers

该元素的typeHandler子元素用于注册自定义的类型处理器。

类型处理器用于执行类型转换。无论在Mybatis在预处理语句中设置一个值时,还是在它从结果集中获取一个值时,都会调用类型处理器在JDBC类型和Java类型之间进行适当的转换。类型处理器的职责类似于Hibernate的类型系统。

Mybatis已经内置了常用的类型处理器,除非你需要定制自己的类型处理器,否则不需要配置该元素。

自定义类型处理器

若要定制自己的类型处理器,可以继承BaseTypeHandler类:

然后在此设置项中注册新的类型处理器:

你也可以指定包,Mybaits在包中查找多个类型处理器:

处理枚举类型

要让Mybatis支持枚举类型,可以注册EnumTypeHandler或者EnumOrdinalTypeHandler,后者默认已经注册。这两者的区别是:

  1. EnumTypeHandler,把枚举值对应的名字存入数据库
  2. EnumOrdinalTypeHandler,把枚举值对应的数字存入数据库

除了以全局方式来指定枚举处理方式以外,你还可以针对单个枚举设置:

甚至针对单个映射语句设置:

objectFactory

Mybatis在获取结果集后,需要依据映射器将结果集转换为Java对象,而它创建Java对象就是通过对象工厂来完成的。

默认的对象工厂仅仅是调用Java类的默认构造器,如果你需要修改此默认行为,可以实现自己的对象工厂,并注册:

plugins

用于注册Mybatis插件,每个plugin子元素对应一个插件。

Mybatis设计了一个很简单的插件扩展机制——允许你拦截映射语句执行过程的某个点,并加入扩展逻辑。可以拦截的点包括:

  1. Executor的update, query, flushStatements, commit, rollback, getTransaction, close, isClosed方法
  2. ParameterHandler的getParameterObject, setParameters方法
  3. ResultSetHandler的handleResultSets, handleOutputParameters方法
  4. StatementHandler的prepare, parameterize, batch, update, query方法 
实现拦截器

要拦截以上方法,你只需要实现拦截器接口,并添加必要的注解:

注册插件
environments

你可以在此元素下定义多个环境,并指定其中一个为默认环境。

所谓环境,是指一个数据源及操控它的事务管理器。通过定义多个环境,Mybatis可以快速的在不同类型的数据库、不同数据实例之间进行切换。

每个SqlSessionFactory只能使用一个环境,你可以使用如下签名的方法为SqlSessionFactory指定(非默认的)环境:

单个环境的配置,看起来大概是这个样子:

transactionManager

该元素定义某个环境使用的事务管理器,Mybatis支持两种类型的事务管理器:

  1. JDBC,直接使用JDBC API进行提交和回滚,依赖于从数据源得到的连接来管理事务
  2. MANAGED,该配置让容器来管理事务的整个生命周期。默认情况下,该事务管理器会负责连接的关闭,如果需要禁止此行为,可以:

当你整合Mybatis和Spring时,不需要配置事务管理器。

数据源

Mybatis支持三种数据源:

  1. UNPOOLED,不启用连接池的简单数据源。配置项:
    配置项 说明
    driver JDBC 驱动的 Java 类的完全限定名
    url JDBC URL 地址
    username 登录数据库的用户名
    password 登录数据库的密码
    defaultTransactionIsolationLevel 默认的连接事务隔离级别
    driver.*** 将***属性传递给JDBC驱动
  2. POOLED,使用连接池实现连接复用。除了UNPOOLED提供的配置项外,还支持:
    配置项 说明
    poolMaximumActiveConnections 任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10
    poolMaximumIdleConnections 任意时间可能存在的空闲连接数
    poolMaximumCheckoutTime 在被强制返回之前,池中连接被拿出来使用的最大时间,默认20000ms
  3. JNDI,使用JavaEE容器提供的JNDI上下文来查找数据源
databaseIdProvider

Mybatis可以依据数据库产品的不同,来执行不同的SQL语句。一般你可以使用默认值:

来支持尽可能多的主流数据库。

mappers

指定映射器的引用,即SQL映射语句所在的XML文件或者Java类的引用:

映射器配置

在使用Mybatis进行开发的过程中,映射器配置是一项主要的工作。合理使用映射器,可以减少90%以上的SQL代码。

OGNL

原样字符串(${})、动态SQL元素中,可以使用OGNL表达式。OGNL的基础知识和语法,请参考Struts2学习笔记

在映射器配置中,OGNL上下文对象 #this 是一个类似于Apache Struts值栈的对象。你可以直接访问查询参数的任何属性,以及以下特殊属性:

特殊属性 说明
_parameter 查询参数对象本身 
_databaseId 当前数据库类型,用于多数据库支持 
select

这是映射器配置最常用的一个元素,用于定义一个将结果集映射到Java对象的查询语句。下面是一个简单的例子:

这个配置的含义是,定义一个标识符为selectUser的映射语句,该语句:

  1.  接受一个int型的参数
  2. 查询结果映射为java.util.HashMap。该Map的键是数据库列的别名,值则是结果行中的对应的值
  3. #{id} 告知Mybatis,创建一个预编译SQL语句,并在此处设置一个位置参数,就像这样:
属性列表
属性 说明
id String,在当前命名空间中唯一的标识符,可以被用来引用这条语句
parameterType

Type/TypeAlias,传入这条语句的参数类型,可选,因为Mybatis可以基于类型处理器推断参数类型

如果该语句有多个参数,你可以指定参数类型为一个复合的对象类型,并在SQL语句中使用#{propName}引用对象的属性作为参数

resultType

Type/TypeAlias,从该语句结果集构造的Java对象的类型。对于期望返回集合类型的,这里指定的是集合元素的类型

不能和resultMap一起使用

resultMap String,引用外部定义的结果映射规则
flushCache Boolean,如果设置为true,那么该语句一旦被执行,本地缓存、二级缓存皆被清空
useCache Boolean,对于SELECT语句默认为true,如果为true则该语句的结果被二级缓存
timeout Number,语句执行超时的秒数
fetchSize Number,提示JDBC,每次抓取数据的行数
statementType

Enum(TATEMENT | PREPARED | CALLABLE) = PREPARED

指示Mybatis创建何种类型的JDBC语句

resultSetType

Enum(FORWARD_ONLY|SCROLL_SENSITIVE|SCROLL_INSENSITIVE)

提示Mybatis创建何种类型的结果集,默认取决于驱动

resultOrdered

Boolean=false,仅仅针对嵌套结果SELECT语句使用

resultSets

仅对多结果集的情况,逗号分隔的结果集名称

insert|update|delete

这三类元素分别表示插入、更新、删除语句,它们的实现方式很接近:

属性列表
属性 说明
id 参见select元素的属性说明
parameterType
flushCache
timeout
statementType
useGeneratedKeys Boolean=false,仅针对INSERT/UPDATE语句。如果设置为true,则Mybatis会利用JDBC的getGeneratedKeys方法来取回数据库内部自动生成的列值,MySQL、MS SQL Server等数据库支持自增长方式的列值自动生成
keyProperty

设置为一个属性名,Mybatis将通过getGeneratedKeys的返回值,或者insert语句的selectKey子元素来设置该属性的值

如果你想得到多个自动生成的列,可以设置逗号分隔的多个属性

回填主键

插入单个对象时,你可以把数据库自动生成的主键回填给Java对象的某个属性:

对应Java代码:

selectKey

如果数据库不支持自动生成主键,你可以让Mybatis生成,并插入到数据库:

selectKey属性说明如下:

statementTypeÈ

属性 说明
keyProperty 与参数的什么属性匹配,支持逗号分隔多个值
keyColumn 匹配属性对应的列名称,支持逗号分隔多个值
resultType 属性值的类型
order

Enum(BEFORE|AFTER):

  1. 如果设置为BEFORE,先执行此selectKey语句,得到ID,然后执行插入语句
  2. 如果设置为AFTER,则先执行插入语句
statementType

Enum(TATEMENT | PREPARED | CALLABLE)

多行插入

如果数据库支持多行插入,你可以传递一系列对象:

对应Java代码:

注意:Mybatis无法在批量插入时获得数据库自动生成的列。 

sql

该元素用来定义可重复使用的SQL片断,它可以被包含在其它语句中。sql支持参数化:

在其它语句中,你可以引用sql元素:

sql也可以引用sql元素,甚至引用者的refid都可以参数化:

参数

前面很多地方已经用到了参数,你可以为语句明确的指定参数类型(parameterType) ,例如:

这样,当调用此语句时,你传入了一个User类型的对象,则它的name、age、dob属性都会通过反射机制找到,然后传入到预编译语句之中。

属性占位符

对于语句中的占位符,不仅可以指定一个名字,还可以指定:

  1. javaType,该属性的Java类型,除非该属性的容器对象是一个Map,一般不需要设置
  2. jdbcType,该属性对应的JDBC类型,如果null被当作值传递,那么对于所有可能为空的列,该属性都是需要的
  3. numericScale,对于数值类型,你可以用此字段指定小数位数
  4. typeHandler,你可以为属性指定一个类型处理器
  5. mode,可以设置为IN|OUT|INOUT,如果设置为OUT|INOUT,则参数对象的属性值可能会被改变

例如: #{property,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}  

参数转换

通过SqlSession的API调用映射语句时,如果:

  1. 传入的是一个数组或者列表,则Mybatis会自动将其转换为Map,此Map的键分别为array、list
  2. 传入的是一个简单类型,那么属性占位符的名称可以随意取
原样字符串

如果你想往SQL里插入一个字面值(而不是预编译语句的位置参数),可以使用${},例如: ORDER BY${columnName} 。columnName具体是何种,取决于上下文参数。

结果映射

当我们指定resultType为Map或者实体类时,已经在间接的使用resultMap,只不过映射方式是Mybatis自动推导出来的:

  1. 如果结果类型是Map,则把列名映射为Map的键
  2. 如果结果类型是实体类,则把列名映射为实体类的属性

假设实体类属性和列名不是完全匹配的,你就必须使用SQL的列别名来提示Mybatis进行映射:、

resultMap简介

你可以为语句指定resultMap而不是resultType属性, 前者引用一个resultMap元素。

resultMap元素定义一个数据库列——Java属性的映射规则,例如:

自动映射

在简单的场景下,我们可以让Mybatis自动完成属性——列映射,在复杂的场景下,我们可以使用resultMap。

Mybatis默认映射规则是:如果列名和Java属性名在不区分大小写的情况下相等,那么它们匹配成功。但是有些时候,我们数据库列名采用全大写、下划线风格,而Java属性一般都是驼峰式大小写。使用默认的自动映射规则无法满足需求,这时候,我们可以打开设置项mapUnderscoreToCamelCase,改变自动映射的规则。

即使在resultMap中,自动映射也起作用,因此你不必手工编写所有字段的映射规则。

缓存

Mybatis3的缓存实现改进了很多。默认情况下,只有局部缓存被启用。要启用SqlSessionFactory级别的二级缓存(跨Session),需要在映射文件中添加一行:

注意,缓存配置是绑定到映射文件的名字空间的。

属性列表
属性 说明
eviction

缓存满了以后,如何进行清理。默认LRU,可选值:

  1. LRU,最近最少使用,移除最长时间不被使用的对象
  2. FIFO,先进先出,按照对象进入缓存的顺序来移除
  3. SOFT ,软引用,移除基于垃圾回收器状态和软引用规则的对象
  4. WEAK,弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象
flushInterval 缓存刷新间隔,毫秒数。默认不设置,即仅仅在调用语句时才刷新
size 缓存对象的最大数量,默认1024
readOnly 是否只读方式使用缓存,如果true可以提高性能。默认false
type 可以指定自定义缓存实现
自定义缓存

你可以实现自己的缓存,只需要实现org.mybatis.cache.Cache接口。要使用自定义缓存机制。

语句级设置

你可以设置每个映射语句的缓存规则,默认规则是这样的:

resultMap元素

映射器中的resultMap元素非常强大和重要,因此我们在此详细讨论它。

上面我们尝试了使用resultMap解决数据库字段名、实体类名不对应的问题。实际上resultMap能做的远远不止这点,它可以很好的解决关联映射问题——把结果集映射到一个对象图中。

resultMap属性 
属性 说明
id resultMap在名字空间中的唯一标识
type 此resultMap将结果集映射为何种对象
autoMapping 覆盖全局的自动映射设置
resultMap子元素概要 

下面依次介绍这些子元素的功能

id|result

这两个子元素都是把单个列的值映射到简单数据类型(数字、字符串、日期、布尔等),只是id提示Mybatis该字段是实体类的标识符,Mybatis会用此信息提升缓存、嵌入结果映射(联合映射)的性能。示例:

属性列表 
属性 说明
property Java端属性名,你可以使用点号导航,映射到对象图的深处
column 数据库列名,或者重命名后的列标签
javaType 该字段的Java类型,仅在映射到Map的时候需要
jdbcType 该字段的JDBC类型,仅仅对INSERT/UPDATE/DELETE语句处理可能为空的列时需要
typeHandler 使用的类型处理器
constructor

该子元素用于指定构造实体对象时,使用的构造器。constructor的两个子元素和id、result元素类似。

association

该子元素用于处理Has-A关系,例如一个用户有一个部门。Mybatis提供了两种方式来处理这种关联关系:

  1. 嵌套查询:执行另外一个SQL映射语句,来返回关联对象
  2. 嵌套结果:使用嵌套结果映射(nested result mappings)来处理重复的JOIN结果的子(多个用户具有同一部门,那么JOIN的结果中必然有重复的部门数据)集,这要求你手工编写一个JOIN查询,JOIN到关联对象的表
属性列表
属性 说明
property 参考id|result子元素
javaType
jdbcType
typeHandler
嵌套查询相关属性
column

当前对象表中,引用关联对象的外键列

如果使用复合主键,需要以 {prop1=col1,prop2=col2} 这样的方式来指定该属性,prop*为关联对象的属性,而col*为当前表的列名

select

指定另外一个映射语句的ID,该映射语句的结果类型必须和关联对象的类型兼容

如果使用复合主键,column配置中的prop*将作为参数传递给该映射语句

fetchType 抓取类型,可选值lazy、eager。用于覆盖全局设置
嵌套结果相关属性
resultMap 指定一个结果映射,该结果映射用于把当前结果集中某些列映射到关联对象
columnPrefix 用于关联对象的列的统一前缀
notNullColumn

默认情况下,当前结果集中映射到关联对象属性的那些列,只要有一个为非空值,则关联对象就会被创建

设置此属性,指定逗号分隔的若干列,只有这些列中至少一个不为空才创建关联对象

autoMapping 是否启用自动映射,覆盖全局值
嵌套查询示例

实体类和测试代码:

这种方式获得关联对象,想对简单,但是会导致所谓N + 1问题:

  1. 执行一个映射语句,获得User的列表,此所谓1
  2. 对于每个User,都需要执行一个语句来获得Dept,N个用户需要执行N此SQL

如果N数量很大,会导致大量零散的SQL,引起性能问题。延迟加载能够在某些场景下缓解此问题,但是如果你需要对User列表进行迭代,此问题就无法避免。

嵌套结果示例

这里仍然以User-Dept为例,最基本的形式:

我们可以把association内部的映射规则独立为resultMap,便于重用:

最好把DEPT_前缀给移除,这样deptResult被单独使用时可以不必编写列别名,设置association的columnPrefix即可(前提你给那些属于关联对象的列予以规范化的别名):

columnPrefix还可以用于多次连接到同一类关联对象时,使用同一resultMap时区分各自的列。

collection

上面我们学习了如何通过association子元素处理Has-A关系(many-to-one),如果遇到Has-Many情况怎么办呢,比如一个用户具有多个通信地址的情况?

这时可以使用collection子元素。我们以User-Address为例学习collection的用法,首先扩展一下实体类:

collection和association的属性很类似,我们直接以示例说明它们的差异。

嵌套查询示例
嵌套结果示例

嵌套结果总是基于JOIN来实现的: 

可以看到和association版的非常类似,只是多了一个ofType属性指定集合元素的类型。

discriminator

某些情况下,一个查询语句可能返回多行不同类型的数据,这些数据需要采用不同方式来映射。此时需要用到discriminator。

这里举一个通行工具(Vehicle)的例子,通行工具包括小汽车(Car)、卡车(Truck)、货车(Van)、SUV等类别,在这个例子里面Vehicle与后面的几个是父子类关系,但是存放在一张表里,通过一个鉴别字段区分。

我们看看Vehicle的结果映射:

再看看Car的结果映射:

 首先,当前行会映射为Car类型,另外由于指定了extends自vehicleResult,所以后者定义的映射规则自动被合并进来。 

动态SQL

Mybatis的动态SQL功能类似于Struts2的标签库,它利用一些特殊的XML元素,实现流程控制。

if

该元素主要用于实现有条件的WHERE子句包含:

choose - when - otherwise

类似于Java的switch语句:

where

该元素保证:只有一个以上if条件匹配的情况下,才往SQL中插入WHERE子句,若WHERE子句以OR、AND结尾,该元素也会把它们删除:

trim

该元素可以为其内部SQL设置前缀、后缀;也可以当内部SQL出现指定前缀、后缀的情况下,将其消除。与上面where等价的trim版本是:

set

与where类似,添加必要的SET前缀,而且仅仅添加需要更新的列,处理结尾的逗号:

与之等价的trim版本是: <trim prefix="SET" suffixOverrides=","></trim>  

foreach

当需要对集合进行遍历,例如IN查询、批量插入时,可以使用该元素:

bind

可以估算一个OGNL表达式,将结果绑定到上下文对象(参数对象)的一个属性:

多数据库支持

利用Mybatis动态SQL特性,我们可以很容易实现多数据库支持。我们可以随时访问变量_databaseId,来获得数据库厂商类型:

Java API
SqlSessionFactoryBuilder 

该类提供了多种构件SqlSessionFactory的方法:

Environment 
Configuration 

基于XML的主配置的Java编程式等价物:

SqlSessionFactory

主要用来获取SqlSession,有很多方法变体:

SqlSession

包含日常工作需要使用的大部分方法: 

SQL语句构建器

有时候你不得不在Java代码中编写SQL语句,为了减轻拼写SQL的痛苦,你可以使用MyBatis提供的SQL语句构建器:

与Spring集成
Maven依赖
基本配置
SqlSessionTemplate

与Mybatis默认的SqlSession实现DefaultSqlSession不同,SqlSessionTemplate是线程安全的,你可以放心的传递它。

管理映射器接口

你可以把映射器接口配置为Bean,Spring会自动生成其代理:

逐个配置映射器接口太麻烦,你可以配置自动扫描:

你可以在自己的DAO或者Service中注入这些映射器接口,并直接调用其中的SQL方法。

常见问题
重复映射导致异常

启动报错:java.lang.IllegalArgumentException: Mapped Statements collection already contains value for ...

原因:可能是因为你在XML映射器和注解映射器中指定了重复的映射语句,即XML的id与Java方法名相同。

找不到映射语句导致异常

执行语句时报错:Mapped Statements collection does not contain value for <statementName> 

可能原因:

  1. Java API中写错了语句ID
  2. 映射器没有被扫描到,注意mappers/package仅仅能识别基于注解的映射器
association不指定javaType导致异常

报错信息:

at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:122)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:73)

Caused by: java.lang.NullPointerException

at org.apache.ibatis.reflection.DefaultReflectorFactory.findForClass(DefaultReflectorFactory.java:42)
at org.apache.ibatis.reflection.MetaClass.<init>(MetaClass.java:39)
at org.apache.ibatis.reflection.MetaClass.forClass(MetaClass.java:43)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:524) 

原因:使用嵌套结果映射时association上没有标注关联对象的类型时,出现此错误。

collection不指定必要的id子元素导致异常

报错信息:Expected one result (or null) to be returned by selectOne(), but found: N

原因:User与Address是1:N关系,通过User左连接到Address,当userResult、addressResult两个结果映射都不设置id子元素时,会出现此异常

总结:id子元素最好都写上

无法显示Mybatis日志

首先配置好Log4j的logger: org.apache.ibatis 。

然后,对于3.2以前的版本,调用下面的方法之一:

对于3.2以后的版本,添加类似下面的配置项即可:

如何编写模糊查询

可以有不同的写法:

posted on 2017-08-15 21:51  杭州糊涂虫  阅读(281)  评论(0)    收藏  举报

导航