映射器配置文件和映射器接口
在 com.mybatis3.mappers 包中的 StudentMapper.xml 配置文件内,有个 id 为 ”findStudentById” 的 SQL 语句:
1 | <?xml version="1.0" encoding="utf-8"?> |
如果你注意到上述的 SELECT 映射定义,你可以看到,我们为所有的映射语句中的 stud_id 起了别名。
我们可以使用 ResultMap,来避免上述的到处重复别名,我们稍后会继续讨论。
除了 java.util.List
,你也可以是由其他类型的集合类,如 Set,Map,以及 SortedSet。MyBatis 根据集合的类型,会采用适当的集合实现,如下所示:
- 对于 List,Collection,Iterable 类型,MyBatis 将返回
java.util.ArrayList
- 对于 Map 类型,MyBatis 将返回
java.util.HashMap
- 对于 Set 类型,MyBatis 将返回
java.util.HashSet
- 对于 SortedSet 类型,MyBatis 将返回
java.util.TreeSet
结果集映射 ResultMap
ResultMap 被用来将 SQL SELECT 语句的结果集映射到 JavaBean 的属性中。我们可以定义结果集映射 ResultMap 并且在一些 SELECT 语句上引用 resultMap。MyBatis 的结果集映射 ResultMap 特性非常强大,你可以使用它将简单的 SELECT 语句映射到复杂的一对一和一对多关系的 SELECT 语句上。
简单 ResultMap
一个映射了查询结果和 Student JavaBean 的简单的 resultMap 定义如下:
1 | <resultMap id="StudentResult" type="com.mybatis3.domain.Student"> |
id 为 StudentWithAddressResult 的 resultMap 拓展了 id 为 StudentResult 的 resultMap。
如果你只想映射 Student 数据,你可以使用 id 为 StudentResult 的 resultMap,如下所示:
1 | <select id="findStudentById" parameterType="long" |
1 | <resultMap type="Student" id="StudentWithAddressResult"> |
set 条件
<set>
元素和 <where>
元素类似,如果其内部条件判断有任何内容返回时,他会插入 SET SQL 片段。
1 | <update id="updateStudent" parameterType="Student"> |
MyBatis 支持将多个输入参数传递给映射语句,并以 #{param}
的语法形式引用它们:
1 | <select id="findAllStudentsByNameEmail" resultMap="StudentResult"> |
这里 #{param1}
引用第一个参数 name,而 #{param2}
引用了第二个参数 email。
1 | StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); |
多行结果集映射成 Map
如果你有一个映射语句返回多行记录,并且你想以 HashMap 的形式存储记录的值,使用记录列名作为 key 值,而记录对应值或为 value 值。我们可以使用 sqlSession.selectMap(),如下所示:
<select id=" findAllStudents" resultMap="StudentResult">
select * from Students
</select>
查询:
Map<Long, Student> studentMap =
sqlSession.selectMap("com.mybatis3.mappers.StudentMapper.findAllStudents", "studId");
这里 studentMap 将会将 studId 作为 key 值,而 Student 对象作为 value 值。
使用 RowBounds 对结果集进行分页
有时候,我们会需要跟海量的数据打交道,比如一个有数百万条数据级别的表。由于计算机内存的现实我们不可能一次性加载这么多数据,我们可以获取到数据的一部分。特别是在 Web 应用程序中,分页机制被用来以一页一页的形式展示海量的数据。
MyBatis 可以使用 RowBounds 逐页加载表数据。RowBounds 对象可以使用 offset 和 limit 参数来构建。参数 offset 表示开始位置,而 limit 表示要取的记录的数目。
假设如果你想每页加载并显示 25 条学生的记录,你可以使用如下的代码:
<select id="findAllStudents" resultMap="StudentResult">
select * from Students
</select>
然后,你可以如下加载第一页数据(前25条):
int offset = 0 , limit = 25;
RowBounds rowBounds = new RowBounds(offset, limit);
List<Student> = studentMapper.getStudents(rowBounds);
若要展示第二页,使用 offset = 25,limit = 25; 第三页,则为 offset = 50,limit = 25。
使用 ResultSetHandler 自定义处理结果集 resultSet
MyBatis 在将查询结果集映射到 JavaBean 方面提供了很大的选择性。但是,有时候我们会遇到由于特定的目的,需要我们自己处理 SQL 查询结果的情况。MyBatis 提供了 ResultHandler 插件形式允许我们以任何自己喜欢的方式处理结果集 ResultSet。
假设我们想从学生的 stud_id 被用作 key,而 name 被用作 value 的 HashMap 中获取到 student 信息。
mybatis-3.2.2
并不支持使用 resultMap 配置将查询的结果集映射成一个属性为 key,而另外属性为 value 的 HashMap。
sqlSession.selectMap() 则可以返回以给定列为 key,记录对象为 value 的 map。
我们不能将其配置成其中一个属性作为 key,而另外的属性作为 value。
对于 sqlSession.select() 方法,我们可以传递给它一个 ResultHandler 的实现,它会被调用来处理 ResultSet 的每一条记录。
public interface ResultHandler {
void handleResult(ResultContext context);
}
现在我们来看一下怎么使用 ResultHandler 来处理结果集 ResultSet,并返回自定义化的结果。
public Map<Long, String> getStudentIdNameMap() {
final Map<Long, String> map = new HashMap<Long, String>();
SqlSession sqlSession = MyBatisUtil.openSession();
try {
sqlSession.select("com.mybatis3.mappers.StudentMapper.findAllStudents"
, new ResultHandler() {
@Override
public void handleResult(ResultContext context) {
Student student = (Student) context.getResultObject();
map.put(student.getStudId(), student.getName());
}
}
} finally {
sqlSession.close();
}
return map;
}
在上述的代码中,我们提供了匿名内部 ResultHandler 实现类,在 handleResult() 方法中,我们使用 context.getResultObject() 获取当前的 result 对象,即 Student 对象,因为我们定义了 findAllStudent 映射语句的 resultMap="studentResult"
。对查询返回的每一行都会调用 handleResult() 方法,并且我们从 Student 对象中取出 studId 和 name,将其放到 map 中。
缓存
将从数据库中加载的数据缓存到内存中,是很多应用程序为了提高性能而采取的一贯做法。MyBatis 对通过映射的 SELECT 语句加载的查询结果提供了内建的缓存支持。默认情况下,启用一级缓存,即,如果你使用同一个 SqlSession 接口对象调用了相同的 SELECT 语句,则直接会从缓存中返回结果,而不是再查询一次数据库。
我们可以在 SQL 映射器 XML 配置文件中使用 <cache />
元素添加全局二级缓存。
当你加入了 <cache />
元素,将会出现以下情况:
- 所有的在映射语句文件定义的
select
语句的查询结果都会被缓存 - 所有的在映射语句文件定义的
insert
,update
和delete
语句将会刷新缓存 - 缓存根据最近最少被使用(Least Recently Used,LRU)算法管理
- 缓存不会被任何形式的基于时间表的刷新(没有刷新时间间隔),即不支持定时刷新机制
- 缓存将存储 1024 个查询方法返回的列表或者对象的引用
- 缓存会被当作一个读/写缓存。这是指检索出的对象不会被共享,并且可以被调用者安全地修改,不会有其他潜在的调用者或者线程的潜在修改干扰,即,缓存是线程安全的。
你也可以通过复写默认属性来自定义缓存的行为,如下所示:
<cache eviction="FIFO" flushInterval="60000" size="512"
readOnly="true"/>
以下是对上述属性的描述:
- eviction:此处定义缓存的移除机制。默认值是 LRU,其可能的值有:LRU(least recently used,最近最少使用),FIFO(first in first out,先进先出),SOFT(soft reference,软引用),WEAK(weak reference,弱引用)。
- flushInterval:定义缓存刷新间隔,以毫秒计。默认情况下不设置。所以不使用刷新间隔时,缓存cache只有在调用语句的时候刷新。
- size:表示缓存cache中能容纳的最大元素数。默认值是1024,你也可以设置成任意的正整数。
- readOnly:一个只读的缓存 cache 会对所有的调用者返回被缓存对象的同一个实例(实际返回的是被返回对象的一份引用)。一个读/写缓存 cache 将会返回被返回对象的一分拷贝(通过序列化)。默认情况下设置为 false。可能的值有 false 和 true。
一个缓存的配置和缓存实例被绑定到映射器配置文件所在的名空间(namespace)上,所以在相同名空间内的所有语句被绑定到一个 cache 中。
默认的映射语句的 cache 配置如下:
<select... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>
你可以为任意特定的映射语句复写默认的 cache 行为;例如,对一个 select 语句不使用缓存,可以设置 useCache=”false”。
除了内建的缓存支持,MyBatis 也提供了与第三方缓存类库如 Ehcache
, OSCache
, Hazelcast
的集成支持。你可以在 MyBatis官方网站 上找到关于继承第三方缓存类库的更多信息。
如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理