mybatis 高级映射

高级结果映射

MyBatis的建立基于这样一个思想:数据库并非您想怎样就怎样的。虽然咱们但愿全部的数据库遵照第三范式或BCNF(修正的第三范式),但它们不是。若是有一个数据库可以完美映射到全部应用程序,也将是很是棒的,但也没有。结果集映射就是MyBatis为解决这些问题而提供的解决方案。例如,咱们如何映射下面这条语句?html

<select id="selectBlogDetails" parameterType="int" resultMap="detailedBlogResultMap">  
select  
B.id as blog_id,  
B.title as blog_title,  
B.author_id as blog_author_id,  
A.id as author_id,  
A.username as author_username,  
A.password as author_password,  
A.email as author_email,  
A.bio as author_bio,  
A.favourite_section as author_favourite_section,  
P.id as post_id,  
P.blog_id as post_blog_id,  
P.author_id as post_author_id,  
P.created_on as post_created_on,  
P.section as post_section,  
P.subject as post_subject,  
P.draft as draft,  
P.body as post_body,  
C.id as comment_id,  
C.post_id as comment_post_id,  
C.name as comment_name,  
C.comment as comment_text,  
T.id as tag_id,  
T.name as tag_name  
from Blog B  
left outer join Author A on B.author_id = A.id  
left outer join Post P on B.id = P.blog_id  
left outer join Comment C on P.id = C.post_id  
left outer join Post_Tag PT on PT.post_id = P.id  
left outer join Tag T on PT.tag_id = T.id  
where B.id = #{id}  
</select>


您可能想要把它映射到一个智能的对象模型,包括由一个做者写的一个博客,有许多文章(Post,帖子),每一个文章由0个或者多个评论和标签。下面是一个复杂ResultMap 的完整例子(假定做者、博客、文章、评论和标签都是别名)。仔细看看这个例子,可是不用太担忧,咱们会一步步地来分析,一眼看上去可能让人沮丧,可是实际上很是简单的java

<resultMap id="detailedBlogResultMap" type="Blog">  
<constructor>  
<idArg column="blog_id" javaType="int"/>  
</constructor>  
<result property="title" column="blog_title"/>  
<association property="author" column="blog_author_id" javaType=" Author">  
<id property="id" column="author_id"/>  
<result property="username" column="author_username"/>  
<result property="password" column="author_password"/>  
<result property="email" column="author_email"/>  
<result property="bio" column="author_bio"/>  
<result property="favouriteSection" column="author_favourite_section"/>  
</association>  
<collection property="posts" ofType="Post">  
<id property="id" column="post_id"/>  
<result property="subject" column="post_subject"/>  
<association property="author" column="post_author_id" javaType="Author"/>  
<collection property="comments" column="post_id" ofType=" Comment">  
<id property="id" column="comment_id"/>  
</collection>  
<collection property="tags" column="post_id" ofType=" Tag" >  
<id property="id" column="tag_id"/>  
</collection>  
<discriminator javaType="int" column="draft">  
<case value="1" resultType="DraftPost"/>  
</discriminator>  
</collection>  
</resultMap>

 

这个resultMap 的元素的子元素比较多,讨论起来比较宽泛。下面咱们从概念上概览一下这个resultMap的元素。算法

resultMapsql

·constructor–实例化的时候经过构造器将结果集注入到类中数据库

oidArg– ID 参数; 将结果集标记为ID,以方便全局调用缓存

oarg–注入构造器的结果集安全

·id–结果集ID,将结果集标记为ID,以方便全局调用mybatis

·result–注入一个字段或者javabean属性的结果app

·association–复杂类型联合;许多查询结果合成这个类型框架

o嵌套结果映射– associations能引用自身,或者从其它地方引用

·collection–复杂类型集合

o嵌套结果映射– collections能引用自身,或者从其它地方引用

·discriminator–使用一个结果值以决定使用哪一个resultMap

ocase–基于不一样值的结果映射

§嵌套结果映射–case也能引用它自身, 因此也能包含这些一样的元素。它也能够从外部引用resultMap

 

è最佳实践:逐步地生成resultMap,单元测试对此很是有帮助。若是您尝试一会儿就生成像上面这样巨大的resultMap,可能会出错,而且工做起来很是吃力。从简单地开始,再一步步地扩展,而且进行单元测试。使用框架开发有一个缺点,它们有时像是一个黑合。为了确保达到您所预想的行为,最好的方式就是进行单元测试。这对提交bugs 也很是有用。

 

下一节,咱们一步步地查看这些细节。

id, result元素

 

<id property="id" column="post_id"/>

<result property="subject" column="post_subject"/>

 

这是最基本的结果集映射。id 和result 将列映射到属性或简单的数据类型字段(String, int, double, Date等)。

这二者惟一不一样的是,在比较对象实例时id 做为结果集的标识属性。这有助于提升整体性能,特别是应用缓存和嵌套结果映射的时候。

 

Id、result属性以下:

 

Attribute

Description

property

映射数据库列的字段或属性。若是JavaBean 的属性与给定的名称匹配,就会使用匹配的名字。不然,MyBatis 将搜索给定名称的字段。两种状况下您均可以使用逗点的属性形式。好比,您能够映射到“username”,也能够映射到“address.street.number”。

column

数据库的列名或者列标签别名。与传递给resultSet.getString(columnName)的参数名称相同。

javaType

完整java类名或别名(参考上面的内置别名列表)。若是映射到一个JavaBean,那MyBatis 一般会自行检测到。然而,若是映射到一个HashMap,那您应该明确指定javaType 来确保所需行为。

jdbcType

这张表下面支持的JDBC类型列表列出的JDBC类型。这个属性只在insert,update或delete 的时候针对容许空的列有用。JDBC 须要这项,但MyBatis 不须要。若是您直接编写JDBC代码,在容许为空值的状况下须要指定这个类型。

typeHandler

咱们已经在文档中讨论过默认类型处理器。使用这个属性能够重写默认类型处理器。它的值能够是一个TypeHandler实现的完整类名,也能够是一个类型别名。

 

支持的JDBC类型

 

MyBatis支持以下的JDBC类型:

BIT

FLOAT

CHAR

TIMESTAMP

OTHER

UNDEFINED

TINYINT

REAL

VARCHAR

BINARY

BLOB

NVARCHAR

SMALLINT

DOUBLE

LONGVARCHAR

VARBINARY

CLOB

NCHAR

INTEGER

NUMERIC

DATE

LONGVARBINARY

BOOLEAN

NCLOB

BIGINT

DECIMAL

TIME

NULL

CURSOR

 

 

 

Constructor元素

 

<constructor>

<idArg column="id" javaType="int"/>

<arg column=”username” javaType=”String”/>

</constructor>

 

当属性与DTO,或者与您本身的域模型一块儿工做的时候,许多场合要用到不变类。一般,包含引用,或者查找的数据不多或者数据不会改变的的表,适合映射到不变类中。构造器注入容许您在类实例化后给类设值,这不须要经过public方法。MyBatis一样也支持private属性和JavaBeans的私有属性达到这一点,可是一些用户可能更喜欢使用构造器注入。构造器元素能够作到这点。

 

考虑下面的构造器:

 

public class User {

//…

public User(int id, String username) {

//…

}

//…

}

 

为了将结果注入构造器,MyBatis须要使用它的参数类型来标记构造器。Java没有办法经过参数名称来反射得到。所以当建立constructor 元素,确保参数是按顺序的而且指定了正确的类型。

 

<constructor>

<idArg column="id" javaType="int"/>

<arg column=”username” javaType=”String”/>

</constructor>

 

其它的属性与规则与id、result元素的同样。

 

Attribute

Description

column

数据库的列名或者列标签别名。与传递给resultSet.getString(columnName)的参数名称相同。

javaType

完整java类名或别名(参考上面的内置别名列表)。若是映射到一个JavaBean,那MyBatis 一般会自行检测到。然而,若是映射到一个HashMap,那您应该明确指定javaType 来确保所需行为。

jdbcType

支持的JDBC类型列表中列出的JDBC类型。这个属性只在insert,update 或delete 的时候针对容许空的列有用。JDBC 须要这项,但MyBatis 不须要。若是您直接编写JDBC代码,在容许为空值的状况下须要指定这个类型。

typeHandler

咱们已经在文档中讨论过默认类型处理器。使用这个属性能够重写默认类型处理器。它的值能够是一个TypeHandler实现的完整类名,也能够是一个类型别名。

 

 

Association元素

 

<association property="author" column="blog_author_id" javaType=" Author">

<id property="id" column="author_id"/>

<result property="username" column="author_username"/>

</association>

Association元素处理“has-one”(一对一)这种类型关系。好比在咱们的例子中,一个Blog有一个Author。联合映射与其它的结果集映射工做方式差很少,指定property、column、javaType(一般MyBatis会自动识别)、jdbcType(若是须要)、typeHandler。

不一样的地方是您须要告诉MyBatis 如何加载一个联合查询。MyBatis使用两种方式来加载:

·Nested Select:经过执行另外一个返回预期复杂类型的映射SQL语句(即引用外部定义好的SQL语句块)。

·Nested Results:经过嵌套结果映射(nested result mappings)来处理联接结果集(joined results)的重复子集。

首先,让咱们检查一下元素属性。正如您看到的,它不一样于普通只有select和resultMap属性的结果映射。

Attribute

Description

property

映射数据库列的字段或属性。若是JavaBean 的属性与给定的名称匹配,就会使用匹配的名字。不然,MyBatis 将搜索给定名称的字段。两种状况下您均可以使用逗点的属性形式。好比,您能够映射到”username”,也能够映射到更复杂点的”address.street.number”。

column

数据库的列名或者列标签别名。与传递给resultSet.getString(columnName)的参数名称相同。

注意: 在处理组合键时,您可使用column= “{prop1=col1,prop2=col2}”这样的语法,设置多个列名传入到嵌套查询语句。这就会把prop1和prop2设置到目标嵌套选择语句的参数对象中。

javaType

完整java类名或别名(参考上面的内置别名列表)。若是映射到一个JavaBean,那MyBatis 一般会自行检测到。然而,若是映射到一个HashMap,那您应该明确指定javaType 来确保所需行为。

jdbcType

支持的JDBC类型列表中列出的JDBC类型。这个属性只在insert,update 或delete 的时候针对容许空的列有用。JDBC 须要这项,但MyBatis 不须要。若是您直接编写JDBC代码,在容许为空值的状况下须要指定这个类型。

typeHandler

咱们已经在文档中讨论过默认类型处理器。使用这个属性能够重写默认类型处理器。它的值能够是一个TypeHandler实现的完整类名,也能够是一个类型别名。

联合嵌套选择(Nested Select for Association)

select

经过这个属性,经过ID引用另外一个加载复杂类型的映射语句。从指定列属性中返回的值,将做为参数设置给目标select 语句。表格下方将有一个例子。注意:在处理组合键时,您可使用column=”{prop1=col1,prop2=col2}”这样的语法,设置多个列名传入到嵌套语句。这就会把prop1和prop2设置到目标嵌套语句的参数对象中。

 例如:  

<resultMap id=”blogResult” type=”Blog”>  
<association property="author" column="blog_author_id" javaType="Author"  
select=”selectAuthor”/>  
</resultMap>  
   
<select id=”selectBlog” parameterType=”int” resultMap=”blogResult”>  
SELECT * FROM BLOG WHERE ID = #{id}  
</select>  
   
<select id=”selectAuthor” parameterType=”int” resultType="Author">  
SELECT * FROM AUTHOR WHERE ID = #{id}  
</select>  
<wbr>

咱们使用两个select语句:一个用来加载Blog,另外一个用来加载Author。Blog的resultMap 描述了使用“selectAuthor”语句来加载author的属性。

若是列名和属性名称相匹配的话,全部匹配的属性都会自动加载。

 

译者注:

上面的例子,首先执行<select id=“selectBlog”>,执行结果存放到<resultMap id=“blogResult”>结果映射中。“blogResult”是一个Blog类型,从<select id=“selectBlog”>查出的数据都会自动赋值给”blogResult”的与列名匹配的属性,这时blog_id,title等就被赋值了。同时“blogResult”还有一个关联属性"Author",执行嵌套查询select=”selectAuthor”后,Author对象的属性id,username,password,email,bio也被赋于数据库匹配的值。

 

Blog

{

blog_id;

title;

Author author

{

id;

username;

password;

email;

bio;

 

}

 

}

 

 

虽然这个方法简单,可是对于大数据集或列表查询,就不尽如人意了。这个问题被称为“N+1 选择问题”(N+1 Selects Problem)。归纳地说,N+1选择问题是这样产生的:

·您执行单条SQL语句去获取一个列表的记录( “+1”)。

·对列表中的每一条记录,再执行一个联合select 语句来加载每条记录更加详细的信息(“N”)。

这个问题会致使成千上万的SQL语句的执行,所以并不是老是可取的。

上面的例子,MyBatis可使用延迟加载这些查询,所以这些查询立马可节省开销。然而,若是您加载一个列表后当即迭代访问嵌套的数据,这将会调用全部的延迟加载,所以性能会变得很是糟糕。

鉴于此,这有另一种方式。

联合嵌套结果集(Nested Results for Association) 

resultMap

一个能够映射联合嵌套结果集到一个适合的对象视图上的ResultMap 。这是一个替代的方式去调用另外一个select 语句。它容许您去联合多个表到一个结果集里。这样的结果集可能包括冗余的、重复的须要分解和正确映射到一个嵌套对象视图的数据组。简言之,MyBatis 让您把结果映射‘连接’到一块儿,用来处理嵌套结果。举个例子会更好理解,例子在表格下方。

您已经在上面看到了一个很是复杂的嵌套联合的例子,接下的演示的例子会更简单一些。咱们把Blog和Author表联接起来查询,而不是执行分开的查询语句:

<select id="selectBlog" parameterType="int" resultMap="blogResult">  
select  
B.id as blog_id,  
B.title as blog_title,  
B.author_id as blog_author_id,  
A.id as author_id,  
A.username as author_username,  
A.password as author_password,  
A.email as author_email,  
A.bio as author_bio  
from Blog B left outer join Author A on B.author_id = A.id  
where B.id = #{id}  
</select>


注意到这个链接(join),要确保全部的别名都是惟一且无歧义的。这使映射容易多了,如今咱们来映射结果集:

 

<resultMap id="blogResult" type="Blog">  
<id property=”blog_id” column="id" />  
<result property="title" column="blog_title"/>  
<association property="author" column="blog_author_id" javaType="Author"  
resultMap=”authorResult”/>  
</resultMap>  
   
<resultMap id="authorResult" type="Author">  
<id property="id" column="author_id"/>  
<result property="username" column="author_username"/>  
<result property="password" column="author_password"/>  
<result property="email" column="author_email"/>  
<result property="bio" column="author_bio"/>  
</resultMap>

 

在上面的例子中,您会看到Blog的做者(“author”)联合一个“authorResult”结果映射来加载Author实例。

重点提示:id元素在嵌套结果映射中扮演了很是重要的角色,您应该老是指定一个或多个属性来惟一标识这个结果集。事实上,若是您没有那样作,MyBatis也会工做,可是会致使严重性能开销。选择尽可能少的属性来惟一标识结果,而使用主键是最明显的选择(即便是复合主键)。

上面的例子使用一个扩展的resultMap 元素来联合映射。这可以使Author结果映射可重复使用。而后,若是您不须要重用它,您能够直接嵌套这个联合结果映射。下面例子就是使用这样的方式: 

<resultMap id="blogResult" type="Blog">  
<id property=”blog_id” column="id" />  
<result property="title" column="blog_title"/>  
<association property="author" column="blog_author_id" javaType="Author">  
<id property="id" column="author_id"/>  
<result property="username" column="author_username"/>  
<result property="password" column="author_password"/>  
<result property="email" column="author_email"/>  
<result property="bio" column="author_bio"/>  
</association>  
</resultMap>


在上面的例子中您已经看到若是处理“一对一”(“has one”)类型的联合查询。可是对于“一对多”(“has many”)的状况若是处理呢?这个问题在下一节讨论。

Collection元素 

<collection property="posts" ofType="domain.blog.Post">  
<id property="id" column="post_id"/>  
<result property="subject" column="post_subject"/>  
<result property="body" column="post_body"/>  
</collection>

 

collection元素的做用差很少和association元素的做用同样。事实上,它们很是类似,以致于再对类似点进行描述会显得冗余,所以咱们只关注它们的不一样点。

继续咱们上面的例子,一个Blog只有一个Author。但一个Blog有许多帖子(文章)。在Blog类中,会像下面这样定义相应属性: 

private List<Post> posts;

映射一个嵌套结果集到一个列表,咱们使用collection元素。就像association 元素那样,咱们使用嵌套查询,或者从链接中嵌套结果集。 

集合嵌套选择(Nested Select for Collection)

首先咱们使用嵌套选择来加载Blog的文章。 

<resultMap id=”blogResult” type=”Blog”>  
<collection property="posts" javaType=”ArrayList” column="blog_id"  
ofType="Post" select=”selectPostsForBlog”/>  
</resultMap>  
   
<select id=”selectBlog” parameterType=”int” resultMap=”blogResult”>  
SELECT * FROM BLOG WHERE ID = #{id}  
</select>  
   
<select id=”selectPostsForBlog” parameterType=”int” resultType="Author">  
SELECT * FROM POST WHERE BLOG_ID = #{id}  
</select>

一看上去这有许多东西须要注意,但大部分看起与咱们在association元素中学过的类似。首先,您会注意到咱们使用了collection元素,而后会注意到一个新的属性“ofType”。这个元素是用来区别JavaBean属性(或者字段)类型和集合所包括的类型。所以您会读到下面这段代码。

 

<collection property="posts" javaType=”ArrayList” column="blog_id"

ofType="Post" select=”selectPostsForBlog”/>
 

è理解为:“一个名为posts,类型为Post的ArrayList集合(A collection of posts in an ArrayList of type Post)” 。

javaType属性不是必须的,一般MyBatis 会自动识别,因此您一般能够简略地写成:

<collection property="posts" column="blog_id" ofType="Post"

select=”selectPostsForBlog”/>


 

集合的嵌套结果集(Nested Results for Collection)

这时候,您可能已经猜出嵌套结果集是怎样工做的了,由于它与association很是类似,只不过多了一个属性“ofType”

让咱们看下这个SQL: 

<select id="selectBlog" parameterType="int" resultMap="blogResult">  
select  
B.id as blog_id,  
B.title as blog_title,  
B.author_id as blog_author_id,  
P.id as post_id,  
P.subject as post_subject,  
P.body as post_body,  
from Blog B  
left outer join Post P on B.id = P.blog_id  
where B.id = #{id}  
</select>


一样,咱们把Blog和Post两张表链接在一块儿,而且也保证列标签名在映射的时候是惟一且无歧义的。如今将Blog和Post的集合映射在一块儿是多么简单:

<resultMap id="blogResult" type="Blog">  
<id property=”id” column="blog_id" />  
<result property="title" column="blog_title"/>  
<collection property="posts" ofType="Post">  
<id property="id" column="post_id"/>  
<result property="subject" column="post_subject"/>  
<result property="body" column="post_body"/>  
</collection>  
</resultMap>

 

再次强调一下,id 元素是很是重要的。若是您忘了或者不知道id 元素的做用,请先读一下上面association一节。

若是但愿结果映射有更好的可重用性,您可使用下面的方式:

<resultMap id="blogResult" type="Blog">  
<id property=”id” column="blog_id" />  
<result property="title" column="blog_title"/>  
<collection property="posts" ofType="Post" resultMap=”blogPostResult”/>  
</resultMap>  
   
<resultMap id="blogPostResult" type="Post">  
<id property="id" column="post_id"/>  
<result property="subject" column="post_subject"/>  
<result property="body" column="post_body"/>  
</resultMap>

在您的映射中没有深度、宽度、联合和集合数目的限制。但应该谨记,在进行映射的时候也要考虑性能的因素。应用程序的单元测试和性能测试帮助您发现最好的方式可能要花很长时间。但幸运的是,MyBatis容许您之后能够修改您的想法,这时只须要修改少许代码就好了。

关于高级联合和集合映射是一个比较深刻的课题,文档只能帮您了解到这里,多作一些实践,一切将很快变得容易理解。

 

Discriminator元素

 

<discriminator javaType="int" column="draft">

<case value="1" resultType="DraftPost"/>

</discriminator>

 

有时候一条数据库查询可能会返回包括各类不一样的数据类型的结果集。Discriminator(识别器)元素被设计来处理这种状况,以及其它像类继承层次状况。识别器很是好理解,它就像java里的switch语句。

 

Discriminator定义要指定columnjavaType属性。列是MyBatis将要取出进行比较的值,javaType用来肯定适当的测试是否正确运行(虽然String在大部分状况下均可以工做),例:  

<resultMap id="vehicleResult" type="Vehicle">  
<id property=”id” column="id" />  
<result property="vin" column="vin"/>  
<result property="year" column="year"/>  
<result property="make" column="make"/>  
<result property="model" column="model"/>  
<result property="color" column="color"/>  
<discriminator javaType="int" column="vehicle_type">  
<case value="1" resultMap="carResult"/>  
<case value="2" resultMap="truckResult"/>  
<case value="3" resultMap="vanResult"/>  
<case value="4" resultMap="suvResult"/>  
</discriminator>  
</resultMap>

在这个例子中,MyBatis将会从结果集中取出每条记录,而后比较它的vehicle type的值。若是匹配任何discriminator中的case,它将使用由case指定的resultMap。这是排它性的,换句话说,其它的case的resultMap将会被忽略(除非使用咱们下面说到的extended)。若是没有匹配到任何case,MyBatis只是简单的使用定义在discriminator块外面的resultMap。因此,若是carResult像下面这样定义:

 

<resultMap id="carResult" type="Car">

<result property=”doorCount” column="door_count" />

</resultMap>

 

那么,只有doorCount属性会被加载。这样作是为了与识别器cases群组彻底独立开来,哪怕它与上一层的resultMap一点关系都没有。在刚才的例子里咱们固然知道cars和vehicles的关系,a Car is-a Vehicle。所以,咱们也要把其它属性加载进来。咱们要稍稍改动一下resultMap:

 

<resultMap id="carResult" type="Car"extends=”vehicleResult”>

<result property=”doorCount” column="door_count" />

</resultMap>

 

如今,vehicleResult和carResult的全部属性都会被加载。

可能有人会认为这样扩展映射定义有一点单调了,因此还有一种可选的更加简单明了的映射风格语法。例如:

​
<resultMap id="vehicleResult" type="Vehicle">  
<id property=”id” column="id" />  
<result property="vin" column="vin"/>  
<result property="year" column="year"/>  
<result property="make" column="make"/>  
<result property="model" column="model"/>  
<result property="color" column="color"/>  
<discriminator javaType="int" column="vehicle_type">  
<case value="1" resultType="carResult">  
<result property=”doorCount” column="door_count" />  
</case>  
<case value="2" resultType="truckResult">  
<result property=”boxSize” column="box_size" />  
<result property=”extendedCab” column="extended_cab" />  
</case>  
<case value="3" resultType="vanResult">  
<result property=”powerSlidingDoor” column="power_sliding_door" />  
</case>  
<case value="4" resultType="suvResult">  
<result property=”allWheelDrive” column="all_wheel_drive" />  
</case>  
</discriminator>  
</resultMap>  

​


记住:对于这么多的结果映射,若是您不指定任何的结果集,那么MyBatis 会自动地将列名与属性相匹配。因此上面所举的例子比实际中须要的要详细。尽管如此,大部分数据库有点复杂,而且它并非全部状况都是彻底能够适用的。

Cache元素

 

MyBatis包含一个强大的、可配置、可定制的查询缓存机制。MyBatis 3 的缓存实现有了许多改进,使它更强大更容易配置。默认的状况,缓存是没有开启,除了会话缓存之外,它能够提升性能,且能解决循环依赖。开启二级缓存,您只须要在SQL映射文件中加入简单的一行:

 

<cache/>

 

这句简单的语句做用以下:

·全部映射文件里的select语句的结果都会被缓存。

·全部映射文件里的insert、updatedelete语句执行都会清空缓存。

·缓存使用最近最少使用算法(LRU)来回收

·缓存不会被设定的时间所清空。

·每一个缓存能够存储1024 个列表或对象的引用(无论查询方法返回的是什么)。

·缓存将做为“读/写”缓存,意味着检索的对象不是共享的且能够被调用者安全地修改,而不会被其它调用者或者线程干扰。

全部这些特性均可以经过cache元素进行修改。例如:

<cache

eviction="FIFO"

flushInterval="60000"

size="512"

readOnly="true"/>

 

这种高级的配置建立一个每60秒刷新一次的FIFO 缓存,存储512个结果对象或列表的引用,而且返回的对象是只读的。所以在不用的线程里的调用者修改它们可能会引用冲突。

 

可用的回收算法以下:

·LRU–最近最少使用:移出最近最长时间内都没有被使用的对象。

·FIFO–先进先出:移除最早进入缓存的对象。

·SOFT–软引用: 基于垃圾回收机制和软引用规则来移除对象(空间内存不足时才进行回收)。

·WEAK–弱引用:基于垃圾回收机制和弱引用规则(垃圾回收器扫描到时即进行回收)。

默认使用LRU。

flushInterval:设置任何正整数,表明一个以毫秒为单位的合理时间。默认是没有设置,所以没有刷新间隔时间被使用,在语句每次调用时才进行刷新。

Size:属性能够设置为一个正整数,您须要留意您要缓存对象的大小和环境中可用的内存空间。默认是1024。

readOnly:属性能够被设置为true 或false。只读缓存将对全部调用者返回同一个实例。所以这些对象都不能被修改,这能够极大的提升性能。可写的缓存将经过序列化来返回一个缓存对象的拷贝。这会比较慢,可是比较安全。因此默认值是false。

 

使用自定义缓存

除了上面已经定义好的缓存方式,您可以经过您本身的缓存实现来彻底重写缓存行为,或者经过建立第三方缓存解决方案的适配器。

<cache type=”com.domain.something.MyCustomCache”/>

这个例子演示了若是自定义缓存实现。由type指定的类必须实现org.mybatis.cache.Cache接口。这个接口是MyBatis框架比较复杂的接口之一,先给个示例:

public interface Cache {  
String getId();  
int getSize();  
void putObject(Object key, Object value);  
Object getObject(Object key);  
boolean hasKey(Object key);  
Object removeObject(Object key);  
void clear();  
ReadWriteLock getReadWriteLock();  
}

 

要配置您的缓存,简单地添加一个公共的JavaBeans 属性到您的缓存实现中,而后经过cache 元素设置属性进行传递,下面示例,将在您的缓存实现上调用一个setCacheFile(String file)方法。

 

<cache type=”com.domain.something.MyCustomCache”>

<property name=”cacheFile” value=”/tmp/my-custom-cache.tmp”/>

</cache>

 

您可使用全部简单的JavaBeans属性,MyBatis会自动进行转换。

须要牢记的是一个缓存配置和缓存实例都绑定到一个SQL Map 文件命名空间。所以,全部的这个相同命名空间的语句也都和这个缓存绑定。语句能够修改如何与这个缓存相匹配,或者使用两个简单的属性来彻底排除它们本身。默认状况下,语句像下面这样来配置:

<select ... flushCache=”false” useCache=”true”/>

<insert ... flushCache=”true”/>

<update ... flushCache=”true”/>

<delete ... flushCache=”true”/> 

由于有默认值,因此您不须要使用这种方式明确地配置这些语句。若是您想改变默认的动做,只须要设置flushCache和useCache 属性便可。举个例子来讲,在许多的场合下您可能排除缓存中某些特定的select语句。或者您想用select语句清空缓存。一样的,您也可能有一些update 语句在执行的时候不须要清空缓存。

 

cache-ref元素

 

回想上一节,咱们仅仅只是讨论在某一个命名空间里使用或者刷新缓存。但有可能您想要在不一样的命名空间里共享同一个缓存配置或者实例。在这种状况下,您就可使用cache-ref 元素来引用另一个缓存。

<cache-ref namespace=”com.someone.application.data.SomeMapper”/>

 

例子:

接下来看下一个完整的sqlmap能够运行的ibatis文件:


java类:

public class Item implements Serializable {  
  
    /** 
     *  
     */  
    private static final long serialVersionUID = 3969923837162162882L;  
  
    /** 
     *  
     */  
    private Long id;  
      
    /** 
     * 商品编码 
     */  
    private Long numIid;  
      
    /** 
     * 商品标题 
     */  
    private String title;  
      
    /** 
     * 副标题 
     */  
    private String subTitle;  
      
    /** 
     * 商品类目, 
     */  
    private Integer cat;  
      
    /** 
     * 商品主图地址 
     */  
    private String picUrl;  
      
    /** 
     * 商品缩略图 
     */  
    private String picThumUrl;  
      
    /** 
     * 商家编码, 
     */  
    private String outerId;  
      
    /** 
     * 商品属性 
     */  
    private String props;  
      
    /** 
     * 销售价格 
     */  
    private Double price;  
      
    /** 
     * 商品的市场价格 
     */  
    private Double marketPrice;  
      
    /** 
     * 商品数量 
     */  
    private Integer num;  
      
    /** 
     * 商品上架时间 
     */  
    private Date listTime;  
      
    /** 
     * 商品下架时间 
     */  
    private Date delistTime;  
      
    /** 
     * 商品销量 
     */  
    private Integer sales;    
  
    private Date created;  
      
    private Date modified;  
      
    /** 
     * 数据可用状态,0表示不可用,1表示可用 
     */  
    private Integer enableStatus;  
      
    /** 
     * 商品的url,不存储数据库 
     */  
    private String itemTaobaoUrl;  
      
    /** 
     * 商品所关联的活动 
     */  
    private Active active;  
      
    /** 
     * 该商品的搭配套餐 
     */  
    private List<Item> withPackages;  
  
    //省略了set get方法  
}
相关文章
相关标签/搜索