MyBatis快速入门(13)XML映射文件-其它标签

前面介绍了mybatis的insert,delete,update,select四个主要的参数,也是映射文件中四个主要的标签。除了这四个我们还使用了selectKey标签生成了主键id,下面我们来讨论除了增删改查这四个标签之外的其它标签。从这些当中也能看出mybatis的强大之处。




selectKey标签 

先来回顾一下selectKey标签,有时候新增一条数据,知道新增成功即可。但是有时候,需要这条新增数据的主键,以便逻辑使用,再将其查询出来明显不符合要求,效率也变低了。这时候,通过一些设置,mybatis可以将insert的数据的主键返回,直接拿到新增数据的主键,以便后续使用。这里主要说的是selectKey标签。设计表的时候有两种主键,一种自增主键,一般为int类型,一种为非自增的主键,例如用uuid等。

关于自增主键获取id,我们直接指定insert标签的useGeneratedKeys属性和keyProperty属性即可,并不用写selectKey标签:

下面说一下非自增主键,在代码中生成的不用说,代码中直接就能获取。非自增主键也可以在数据库中直接生成,比如oracle的序列,数据库中的uuid,数据库的随机数等等。例如:

这种方式就得通过selectKey获取。这种方式需要参数类型里面有id这个属性,在执行insert之前会先吧获取的id赋值到user里面的id属性中,然后再正常执行下面的insert语句。不过selectKey这种方式还是建议能不用最好不要用!







foreach标签

很多时候我们传入的参数可能不是一个数量确定的基础类型或者对象类型,而是一个集合或者数组类型,里面包含了数量不确定的参数个数,这时候可以在语句中使用foreach标签处理参数。下面是foreach标签的各个属性:

collection:表示迭代集合的参数名称

item:表示本次迭代获取的元素名称,若collection为List、Set或者数组,则表示其中的元素;若collection为map,则代表key-value的value,该参数为必选

open:表示该迭代以什么开始,最常用的是左括弧’(’,注意:mybatis会将该字符拼接到迭代sql语句之前,该参数为可选项

close:表示该语句以什么结束,最常用的是右括弧’)’,注意:mybatis会将该字符拼接到整体的sql语句之后,该参数为可选项

separator:mybatis会在每次迭代后智能判断要不要给sql语句后面加上separator属性指定的字符,该参数为可选项

index:在list、Set和数组中,index表示当前迭代的位置,在map中,index代指是元素的key,该参数是可选项。

前面有个例子是根据id查询名称,下面看一个根据多个id查询名称的例子:

接口定义:

注意SQL语句中collection的命名,这种写法的话,SQL语句中只能写collection="collection"或者collection="list",如果想给集合参数专门起个别名,可以在接口中定义:

这样SQL语句中就可以使用别名了:

再来看SQL语句,前面写一个1=2是为了后面拼接SQL方便,可以想象如果传入的参数是1和2两个,那么最终SQL就是:

select name from t_user where 1=2 or id=1 or id=2

这种写法虽然符合逻辑,但是看上去让SQL有点丑,后面介绍动态SQL的时候会看到更好的写法。

上面介绍了一个批量查询的例子,使用了foreach标签的两个参数,下面介绍一个批量插入的例子:

这里要注意,虽然设置了每个foreach的内容用逗号间隔,但是其实最后一条后面是不用写逗号的,这时候mybatis会自己智能判断,来看接口定义:

注意上面的批量插入语句只是适用于部分数据库,这里只是参考,大家可以根据实际情况使用foreach。

还有一个问题也需要注意,open和close属性并不是设置到每行迭代语句的开头和结尾,而是整体迭代的最前面和最后面,因此这里的批量插入的括号要在每行里自己写。









sql标签

这个元素可以被用来定义可重用的 SQL 代码段,这些 SQL 代码可以被包含在其他语句中。它可以(在加载的时候)被静态地设置参数。 在不同的包含语句中可以设置不同的值到参数占位符上。比如:

这个 SQL 片段可以被包含在其他语句中,例如:

添加SQL片段要是用include标签,其中refid属性指向的就是sql标签的id,也可以给SQL片段中的字段使用别名:

这样语句也要随之改变:

我们一整个映射文件当中,同一个表每次使用的别名不一定是一样了,可以在SQL片段中使用动态别名:

这样在使用SQL片段的时候声明一下即可:

include标签中间可以添加属性标签,属性标签的name指向的是SQL片段里面的变量,value表示替换变量的值。大家可以想象,有了sql标签,动态的属性,表名和动态的条件都可以根据自己的需要设定。不过为了简单,大部分sql标签都建议用在数据库字段上。









参数

之前讨论的所有语句中,使用的都是简单参数。实际上参数是 MyBatis 非常强大的元素。对于简单的使用场景,大约 90% 的情况下你都不需要使用复杂的参数,比如:

id=#{id}

id是一个基础类型的字段(int),是个简单类型,没有内部属性,所以直接传递值,如果是对象类型,例如:

就像上面,如果 User 类型的参数对象传递到了语句中,id、name 属性将会被查找,然后将它们的值传入预处理语句的参数中。User是自定义的对象,我们还可以使用map:

入参类型相应的改变即可,SQL的写法基本不变:

对于向语句中传递参数来说,这真是既简单又有效。不过参数映射的功能远不止于此。首先,像 MyBatis 的其他部分一样,参数也可以指定一个特殊的数据类型。比如id参数:

#{id,javaType=int,jdbcType=NUMERIC}

因此我们的SQL可以写成:

像 MyBatis 的其它部分一样,javaType 几乎总是可以根据参数对象的类型确定下来,除非该对象是一个 HashMap。这个时候,你需要显式指定 javaType 来确保正确的类型处理器(TypeHandler)被使用。

提示: JDBC 要求,如果一个列允许 null 值,并且会传递值 null 的参数,就必须要指定 JDBC Type。

对于数值类型,还有一个小数保留位数的设置,来指定小数点后保留的位数。例如:

#{money,javaType=double,jdbcType=NUMERIC,numericScale=2}

最后,来看mode 属性,我们在调用存储过程的时候,存储过程有三种类型的参数,分别为 IN(输入参数),OUT(输出参数),INOUT(输入输出参数)。一个存储过程,可以有多个 IN 参数,至多有一个 OUT 或 INOUT 参数。mode允许你指定 IN,OUT 或 INOUT 参数。如果参数的 mode 为 OUT 或 INOUT,就像你在指定输出参数时所期望的行为那样,参数对象的属性实际值将会被改变。 如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 引用来将结果集 ResultMap 映射到参数的类型上。要注意这里的 javaType 属性是可选的,如果留空并且 jdbcType 是 CURSOR,它会被自动地被设为 ResultMap(关于ResultMap后面会详细介绍)。例如:

#{company, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

尽管mybatis的参数的所有这些选项很强大,但大多时候你只须简单地指定属性名,其他的事情 MyBatis 会自己去推断,顶多要为可能为空的列指定 jdbcType。例如:










参数的字符串替换

默认情况下,mybatis使用#{}接收参数,使用 #{} 格式的语法会导致 MyBatis 创建 PreparedStatement 参数占位符并安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法。不过有时你就是想直接在 SQL 语句中插入一个不转义的字符串。 比如在很多情况下要插入一段SQL语句来作为参数,比如一段order by,或者在开发权限功能的时候一段代表动态权限的SQL语句,那这个时候,我们需要的不是自动处理参数,而是把参数像字符串一样只做拼接即可。这时候可以使用:

 ${} 

比如拼接一段order by:

select name 

from t_user 

where id=#{id} 

${orderBy}

这里 MyBatis 不会修改或转义字符串。再举一个例子,比如查询功能的条件不固定时,不一定会使用哪个字段,那也可以这样写:

select name

from t_user

where ${colName} = #{colVal}

不止字段名,甚至如果表名也不固定,也可以使用字符串替换的参数方法,这里不再举例。不过有一点要注意,在正常的参数中如果也使用${},要注意它是字符串拼接,也就是说如果是字符串,要这样写:

name = '${name}'

引号要自己加上。不过通常绝大部分的业务不建议使用${}。

提示: 用这种方式接受用户的输入,并将其用于语句中的参数是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。









结果映射

我们执行select语句的时候,要在标签中指定回参类型 resultType,表示使用哪个类来接收返回的参数。除了resultType还有一种接收返回参数的属性是resultMap,使用这个参数需要引用一个resultMap标签所定义的内容,所以需要了解resultMap标签。

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份resultMap 能够代替实现同等功能的长达数千行的代码。ResultMap 的设计思想是,对于简单的语句根本不需要配置resultMap ,而对于复杂一点的语句只需要描述它们的关系就行了。简单的语句前面介绍了很多,比如,对于简单的没有直接Java类接收的结果,我们直接只用hashmap接收:

上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 不是一个很好的领域模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为领域模型。例如:

上面我们接收参数使用的是User类的别名user,前面已经讨论过。使用别名时,MyBatis 会在幕后自动创建一个 ResultMap,再基于每个属性名来映射列到 JavaBean 的属性上。如果列名和属性名没有精确匹配,可以在 SELECT 语句中对列使用别名(这是一个基本的 SQL 特性)来匹配标签。也就是说,我们给类定义别名,其实真正使用的是ResultMap,但是这个过程是透明的。自动创建的resultMap就像下面这样:

这面的种种用法,都是简单的结果映射,都没有明显的自定义resultMap标签。











高级结果映射

MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们不总都是这样。 如果能有一种完美的数据库映射模式,所有应用程序都可以使用它,那就太好了,但可惜也没有。 而 ResultMap 就是 MyBatis 对这个问题的答案。

比如对于一个非常非常复杂的查询,关联了五六张表,查询的结果字段是好几张表的部分字段整合在一起的结果,这时候肯定没有一个和表对应的实体类能够接收这个结果。我们如果使用resultType,那么有两种解决方法,一个是直接使用map接收,虽然写上去简单了,但是对于业务的清晰和维护无疑是成本很大的。而且map并不是一个好的模型。另一个办法是专门为了这个SQL创建一个实体类,用来接收这个结果,在很多项目中都能看到这种做法。

但是最好的方法是自定义一个resultMap,自定义一个结果映射,要比写很多代码,或者直接使用map好的多。比如我们来看下面这个SQL语句:

算是一个比较复杂的了,你可能想把它映射到一个智能的对象模型,这个对象表示了一篇博客,它由某位作者所写,有很多的博文,每篇博文有零或多条的评论和标签。 我们来看看下面这个完整的resulteMap例子,它是一个非常复杂的结果映射(假设作者,博客,博文,评论和标签都是类型别名)。 下面我们会一步一步来说明。虽然它看起来复杂,但其实非常简单。

可以看到一个resultMap标签,里面还包含了各种子标签。resultMap 元素有很多子元素和一个值得深入探讨的结构。 下面是resultMap 元素的概念视图。

错落有致的属性说明,也表示了标签的使用位置和用法。注意这些都是resultMap得子元素,并不是标签内部的属性,关于属性的说明如下:

其中id好理解,就是一个唯一标识,引用的时候指向的就是id,type指向的是整个结果映射到的具体类,与resultType的一样。

最佳实践: 最好一步步地建立结果映射。单元测试可以在这个过程中起到很大帮助。 如果你尝试一次创建一个像上面示例那样的巨大的结果映射,那么很可能会出现错误而且很难去使用它来完成工作。 从最简单的形态开始,逐步迭代。而且别忘了单元测试! 使用框架的缺点是有时候它们看上去像黑盒子(无论源代码是否可见)。 为了确保你实现的行为和想要的一致,最好的选择是编写单元测试。提交 bug 的时候它也能起到很大的作用。

下面一步一步细说每一部分。先来看id和result:

这些是结果映射最基本的内容。id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。这两者之间的唯一不同是,id 元素表示的结果将是对象的标识属性,例如主键,这会在比较对象实例时用到。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。下面看一下两个元素都有的一些属性:

为了以后可能的使用场景,MyBatis 通过内置的 jdbcType 枚举类型支持下面的 JDBC 类型。

通过id和result元素可以满足大多数的数据传输对象(Data Transfer Object, DTO)以及绝大部分领域模型的要求。但有些情况下你想使用不可变类。 一般来说,很少改变或基本不变的包含引用或数据的表,很适合使用不可变类。 构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。MyBatis 也支持私有属性和私有 JavaBean 属性来完成注入,但有一些人更青睐于通过构造方法进行注入。 constructor 元素就是为此而生的。来看一个简单的构造方法:

public User(Integer id, String username, int age) { }

为了将结果注入构造方法,MyBatis 需要通过某种方式定位相应的构造方法。 在下面的例子中,MyBatis 搜索一个声明了三个形参的的构造方法,参数类型以 java.lang.Integer, java.lang.String 和 int 的顺序给出。

当你在处理一个带有多个形参的构造方法时,很容易搞乱 arg 元素的顺序。 从版本 3.4.3 开始,可以在指定参数名称的前提下,以任意顺序编写 arg 元素。 为了通过名称来引用构造方法参数,你可以添加 @Param 注解,或者使用 '-parameters' 编译选项并启用 useActualParamName 选项(默认开启)来编译项目。下面是一个等价的例子,尽管函数签名中第二和第三个形参的顺序与 constructor 元素中参数声明的顺序不匹配。

如果名称和类型的属性相同,那么可以省略 javaType 。其它元素标签的属性和id以及result的是差不多的:


上面直接配置属性和配置构造器其实就是创建对象实例的两种不同方法而已,Java中基本也都是使用set方法赋值或者创建对象时直接使用有参数的构造器创建。原理上都差不多。












多对一关联

再来看一下关联,数据库中的关联关系大致上分为一对多、多对一和多对多三种情况。下面看一个多对一的例子:

上面的关联使用了association标签,关联(association)元素处理“有一个”类型的关系。说简单些就是在多对一的关系中,查询多方的其中一个,顺便把所对应的一方查出来。 比如,在我们的示例中,一个博客对应一个用户(作者)。关联结果映射和其它类型的映射工作方式差不多。 你需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来,所以不用写),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。

关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:

嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。

嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。

首先,先让我们来看看这个元素的属性。你将会发现,和普通的结果映射相比,它只在 select 和 resultMap 属性上有所不同。

先来看一个关联的嵌套 Select 查询的例子,先来看用到的属性:

再看具体映射文件中SQL的写法:

就是这么简单。我们有两个 select 查询语句:一个用来加载博客(Blog),另外一个用来加载作者(Author),而且博客的结果映射描述了应该使用 selectAuthor 语句加载它的 author 属性。其它所有的属性将会被自动加载,只要它们的列名和属性名相匹配。

这种方式虽然很简单,但在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题”。 概括地讲,N+1 查询问题是这样子的:

你执行了一个单独的 SQL 语句来获取结果的一个列表(就是“+1”)。

对列表返回的每条记录,你执行一个 select 查询语句来为每条记录加载详细信息(就是“N”)。

这个问题会导致成百上千的 SQL 语句被执行。有时候,我们不希望产生这样的后果。好消息是,MyBatis 能够对这样的查询进行延迟加载,因此可以将大量语句同时运行的开销分散开来。 然而,如果你加载记录列表之后立刻就遍历列表以获取嵌套的数据,就会触发所有的延迟加载查询,性能可能会变得很糟糕。所以还有另外一种方法。就是关联的嵌套结果映射。


我们来看关联的嵌套结果映射的例子,先来看用到的属性:

之前,你已经看到了一个非常复杂的嵌套关联的例子。 下面的例子则是一个非常简单的例子,用于演示嵌套结果映射如何工作。 现在我们将博客表和作者表连接在一起,而不是执行一个独立的查询语句,就像这样:

注意查询中的连接,以及为确保结果能够拥有唯一且清晰的名字,我们设置的别名。 这使得进行映射非常简单。现在我们可以映射这个结果:

在上面的例子中,你可以看到,博客(Blog)作者(author)的关联元素委托名为 “authorResult” 的结果映射来加载作者对象的实例。

非常重要: id 元素在嵌套结果映射中扮演着非常重要的角色。你应该总是指定一个或多个可以唯一标识结果的属性。 虽然,即使不指定这个属性,MyBatis 仍然可以工作,但是会产生严重的性能问题。 只需要指定可以唯一标识结果的最少属性。显然,你可以选择主键(复合主键也可以)。

现在,上面的示例使用了外部的结果映射元素来映射关联。这使得 Author 的结果映射可以被重用。 然而,如果你不打算重用它,或者你更喜欢将你所有的结果映射放在一个具有描述性的结果映射元素中。 你可以直接将结果映射作为子元素嵌套在内。这里给出使用这种方式的等效例子:

那如果博客(blog)有一个共同作者(co-author)该怎么办?select 语句看起来会是这样的:

回忆一下,Author 的结果映射定义如下:

由于结果中的列名与结果映射中的列名不同。你需要指定 columnPrefix 以便重复使用该结果映射来映射 co-author 的结果。


下面来看一下关联的多结果集(ResultSet)的情况,先看属性:

从版本 3.2.3 开始,MyBatis 提供了另一种解决 N+1 查询问题的方法。某些数据库允许存储过程返回多个结果集,或一次性执行多个语句,每个语句返回一个结果集。 我们可以利用这个特性,在不使用连接的情况下,只访问数据库一次就能获得相关数据。在例子中,存储过程执行下面的查询并返回两个结果集。第一个结果集会返回博客(Blog)的结果,第二个则返回作者(Author)的结果。

在映射语句中,必须通过 resultSets 属性为每个结果集指定一个名字,多个名字使用逗号隔开。

现在我们可以指定使用 “authors” 结果集的数据来填充 “author” 关联:









一对多关联

我们已经在上面看到了如何处理多对一类型的关联。但是该怎么处理一对多类型的关联呢?这就是我们接下来要介绍的。一对多的关联使用集合(collection )标签,例如:

集合元素和关联元素几乎是一样的,它们相似的程度之高,以致于没有必要再介绍集合元素的相似部分。 所以让我们来关注它们的不同之处吧。我们来继续上面的示例,一个博客(Blog)只有一个作者(Author)。但一个博客有很多文章(Post)。 在博客类中,这可以用下面的写法来表示,也就是一方包含多方的通俗做法:

private List<Post> posts;

要像上面这样,映射嵌套结果集合到一个 List 中,可以使用集合元素。 和关联元素一样,我们可以使用嵌套 Select 查询,或基于连接的嵌套结果映射集合。

首先来看集合的嵌套 Select 查询,让我们看看如何使用嵌套 Select 查询来为博客加载文章。

你可能会立刻注意到几个不同,但大部分都和我们上面学习过的关联元素非常相似。 首先,你会注意到我们使用的是集合元素。 接下来你会注意到有一个新的 “ofType” 属性。这个属性非常重要,它用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。 在一般情况下,MyBatis 可以推断 javaType 属性,因此并不需要填写。所以很多时候你可以简略成:

下面来看集合的嵌套结果映射,现在你可能已经猜到了集合的嵌套结果映射是怎样工作的——除了新增的 “ofType” 属性,它和关联的完全相同。首先, 让我们看看对应的 SQL 语句:

我们再次连接了博客表和文章表,并且为每一列都赋予了一个有意义的别名,以便映射保持简单。 要映射博客里面的文章集合,就这么简单:

再提醒一次,要记得上面 id 元素的重要性,如果你不记得了,请阅读关联部分的相关部分。如果你喜欢更详略的、可重用的结果映射,你可以使用下面的等价形式:

再看集合的多结果集(ResultSet),像关联元素那样,我们可以通过执行存储过程实现,它会执行两个查询并返回两个结果集,一个是博客的结果集,另一个是文章的结果集:

在映射语句中,必须通过 resultSets 属性为每个结果集指定一个名字,多个名字使用逗号隔开。

我们指定 “posts” 集合将会使用存储在 “posts” 结果集中的数据进行填充:

注意: 对关联或集合的映射,并没有深度、广度或组合上的要求。但在映射时要留意性能问题。 在探索最佳实践的过程中,应用的单元测试和性能测试会是你的好帮手。 而 MyBatis 的好处在于,可以在不对你的代码引入重大变更(如果有)的情况下,允许你之后改变你的想法。

高级关联和集合映射是一个深度话题。就介绍到这里,配合少许的实践,你会很快了解全部的用法。












鉴别器

下面介绍一下鉴别器,先来看标签:

有时候,一个数据库查询可能会返回多个不同的结果集(但总体上还是有一定的联系的)。 鉴别器(discriminator)元素就是被设计来应对这种情况的,另外也能处理其它情况,例如类的继承层次结构。 鉴别器的概念很好理解——它很像 Java 语言中的 switch 语句。

一个鉴别器的定义需要指定 column 和 javaType 属性。column 指定了 MyBatis 查询被比较值的地方。 而 javaType 用来确保使用正确的相等测试(虽然很多情况下字符串的相等测试都可以工作)。例如:

在这个示例中,MyBatis 会从结果集中得到每条记录,然后比较它的 vehicle type 值。 如果它匹配任意一个鉴别器的 case,就会使用这个 case 指定的结果映射。 这个过程是互斥的,也就是说,剩余的结果映射将被忽略(除非它是扩展的,我们将在稍后讨论它)。 如果不能匹配任何一个 case,MyBatis 就只会使用鉴别器块外定义的结果映射。 所以,如果 carResult 的声明如下:

那么只有 doorCount 属性会被加载。这是为了即使鉴别器的 case 之间都能分为完全独立的一组,尽管和父结果映射可能没有什么关系。在上面的例子中,我们当然知道 cars 和 vehicles 之间有关系,也就是 Car 是一个 Vehicle。因此,我们希望剩余的属性也能被加载。而这只需要一个小修改。

现在 vehicleResult 和 carResult 的属性都会被加载了。可能有人又会觉得映射的外部定义有点太冗长了。 因此,对于那些更喜欢简洁的映射风格的人来说,还有另一种语法可以选择。例如:

提示: 请注意,这些都是结果映射,如果你完全不设置任何的 result 元素,MyBatis 将为你自动匹配列和属性。所以上面的例子大多都要比实际的更复杂。 这也表明,大多数数据库的复杂度都比较高,我们不太可能一直依赖于这种机制。












自动映射

正如上面所说,在简单的场景下,MyBatis 可以为你自动映射查询结果。但如果遇到复杂的场景,你需要构建一个结果映射。 但是在下面,你将看到,你可以混合使用这两种策略。让我们深入了解一下自动映射是怎样工作的。

当自动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。 这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性。

通常数据库列使用大写字母组成的单词命名,单词间用下划线分隔;而 Java 属性一般遵循驼峰命名法约定。为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase 设置为 true。设置位置在mybatis的全局配置文件中,需要在settings标签下面设置,具体设置如下:

甚至在提供了结果映射后,自动映射也能工作。在这种情况下,对于每一个结果映射,在 ResultSet 出现的列,如果没有设置手动映射,将被自动映射。在自动映射处理完毕后,再处理手动映射。 在下面的例子中,id 和 userName 列将被自动映射,hashed_password 列将根据配置进行映射。

有三种自动映射等级:

NONE - 禁用自动映射。仅对手动映射的属性进行映射。

PARTIAL - 对除在内部定义了嵌套结果映射(也就是连接的属性)以外的属性进行映射

FULL - 自动映射所有属性。

默认值是 PARTIAL,这是有原因的。当对连接查询的结果使用 FULL 时,连接查询会在同一行中获取多个不同实体的数据,因此可能导致非预期的映射。 下面的例子将展示这种风险:


在该结果映射中,Blog 和 Author 均将被自动映射。但是注意 Author 有一个 id 属性,在 ResultSet 中也有一个名为 id 的列,所以 Author 的 id 将填入 Blog 的 id,这可不是你期望的行为。 所以,要谨慎使用 FULL。

无论设置的自动映射等级是哪种,你都可以通过在结果映射上设置 autoMapping 属性来为指定的结果映射设置启用/禁用自动映射。









多参数传参

现在传参时都是在标签内设置参数的类型的,这是因为我们在接口定义的时候,大部分情况只传入了一个参数:

Integer  insert(User user);

如果传入的参数是多个怎么处理呢?比如:

我们可以把多个参数合并成一个,比如放到map里面,或者专门新建一个实体类存储这些参数,但是mybatis还提供了一种更简单的方法,就是在接口这里声明每个参数:

我们在形参的定义类型前面加了一个注解,表示声明参数,注解中传入了一个字符串,表示参数的名字,这个名字可以在SQL语句中使用。下面看一下SQL语句,我们既然在接口这里声明了参数,那么在SQL标签里,就不用了再写parameterType了:

通过这种方式可以传递多个参数,前面讲的foreach标签里面给集合定义别名也使用了这个注解,大家可以对比看下,充分了解这个注解的作用。



代码地址:https://gitee.com/blueses/mybatis-demo  06

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

  • XML映射文件 MyBatis 的真正强大在于它的映射语句,这是它的魔力所在。由于它的异常强大,映射器的 XML ...
    郭艺宾阅读 828评论 0 0
  • 数据库修改语句包括 insert,update 和 delete三种,它们的实现非常接近,看一下insert标签有...
    郭艺宾阅读 343评论 0 0
  • 跑步、男女、真话分别是书中六、七、八章节的讨论话题,时间紧促,当做快餐一般通读。 第六章《跑步》。顾名思义,一开始...
    Michael_Lau阅读 174评论 0 0
  • 1.向外划水 手肘伸直,手掌由向下转为向外,边转手掌边将全臂向外伸出。整个划水动作双手必须用阴力向前伸,双手前伸时...
    阿甘1972阅读 113评论 0 0
  • “我一路看过千山和万水,我的脚踏遍天南和地北,日晒或是风吹, 我都无所谓 ……”,这首歌火遍了大江南北,过去已经两...
    沧海明月光阅读 662评论 0 2