前言
这是课设制作总结的第四篇,目前仍旧奋战在持久层。前面三节分析了项目需求、编写了持久层mapper接口、实现了部分mapper接口的配置文件及测试。
这一节就来继续将剩下的mapper文件配置并测试完。
有关项目背景和model类设计可以查看第一节:【从零开始JavaEE课设】《影院系统》(一) 需求分析 数据库设计 后端model类
model层类涉及到的不多,仅有七个类且类间关系比较简单明确:
知识点简结
resultMap配置
resultMap真的是一大神器,可以在其中清晰的表达类之间的对应包含关系,非常的方便。
对于这个项目来说,目前主要用到它来解决一对一和一对多关系。
一对一 和 一对多
在resultMap中使用association标签可以映射一对一的包含关系
例如,在放映计划中,一个放映计划关联了一个电影和一个房间,是两个一对一关系。
放映计划对应的resultMap:
<resultMap type="screeningPlan" id="planMap">
<id column="spId" property="id"/>
<result column="price" property="price"/>
<result column="planTime" property="time"/>
<result column="planDate" property="date"/>
<!--关联房间-->
<association property="room" javaType="room">
<id column="rId" property="id"/>
<result column="seat" property="seat"/>
<result column="roomName" property="name"/>
<result column="type" property="type"/>
</association>
<!--关联电影-->
<association property="film" javaType="film" resultMap="com.none.mapper.FilmMapper.filmMap"></association>
</resultMap>
这个例子同时展示了如何使用已经映射好的map。对于关联关系一层一层传递的关系编写非常的友好。
映射在FilmMapper中的film:
<resultMap type="film" id="filmMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="director" property="director"/>
<result column="country" property="country"/>
<result column="length" property="length"/>
<result column="release_time" property="releaseTime"/>
<result column="offline_time" property="offlineTime"/>
<result column="language" property="language"/>
<result column="introduction" property="introduction"/>
<collection property="post" javaType="list" ofType="filmPost">
<id column="pid" property="id"/>
<result column="film_Id" property="filmId"/>
<result column="dir" property="dir"/>
</collection>
</resultMap>
这里面又提到了如何进行一对多映射,电影和电影海报的关系就是一对多。这需要用到集合(collection)这个标签进行配置。
其中有三个常用属性:
- property,表示这个集合映射到哪个成员
- javaType,表示这个集合的类型
- ofType,集合中元素的类型
另外,查询一对多关系时映射记得使用外联结,左右联结皆可,使用内联结可能会丢失一部分数据,mybatis会帮助我们自动将同一个主表内容映射成为一个同对象。
例如,查询所有的电影及其对应的海报对象,联结时的语句:
film LEFT OUTER JOIN film_post ON film.id = film_post.film_id
传递参数为集合,foreach标签
当WHERE
条件需要使用到IN
判断时,往往需要传递一个集合作为参数。
这时需要使用到foreach
标签进行处理
例如,查询一些电影对应的记录
mapper方法:
/*查询影片记录*/
public List<Record> selectByFilms(@Param("films") List<Film> films);
mapper文件:
<select id="selectByFilms" resultMap="recordMap">
<include refid="select"></include>
WHERE film.id IN
<foreach collection="films" index="index" item="film" open="(" separator="," close=")">
#{film.id}
</foreach>
;
</select>
这里需要这几个参数:
- collection,表示集合的类型,如果方法处使用了
@Param
注解则这里应该写注解中的映射名 - index,代表迭代的次数或者映射中的键值
- item,代表遍历到的元素
- open,语句开始时的内容
- close,语句结束时的内容
- separator,参数见的分隔符
使用sql、include简化SQL语句
可以使用sql
标签封装常用的sql片段,并在sql语句中使用include
标签引用这些片段;
例如,需要查出的字段及其别名可以使用sql
封装,并可以在具有嵌套结构时调用已经封装好的sql片段
例如,将相互联结的表的联结封装在一个sql片段中,编写select语句时就不需要表述千篇一律地表述表间的联结关系
如一个上映计划需要聚合一个电影和一个影厅,所以查询时需要将计划表联结电影表及影厅表:
<sql id="allContent">
plan.id spId,plan.price price,plan.time planTime,plan.date planDate,
room.id rId,room.seat seat,room.name roomName,room.type type,
film.id fId,film.name filmName,film.director director,film.country country,film.length length,film.release_time release_time,film.offline_time offline_time,film.language language,film.introduction introduction,
film_post.id pid,film_post.dir dir,film_post.film_id film_id
</sql>
<sql id="join">
screening_plan plan JOIN film ON plan.film_id = film.id
JOIN room ON room.id = plan.room_id
LEFT JOIN film_post ON film_post.film_id = film.id
</sql>
又如,一个购票记录需要组合一个放映计划:
<sql id="allContent">
record.id reId,record.money reMoney,record.time reTime,record.code code,record.phone phone,record.seat_id seatId,
<include refid="com.none.mapper.ScreeningPlanMapper.allContent"></include>
</sql>
<sql id="join">
record JOIN
<include refid="com.none.mapper.ScreeningPlanMapper.join"></include>
ON record.plan_id = plan.id
</sql>
mapper文件
Record
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.none.mapper.RecordMapper">
<sql id="allContent">
record.id reId,record.money reMoney,record.time reTime,record.code code,record.phone phone,record.seat_id seatId,
<include refid="com.none.mapper.ScreeningPlanMapper.allContent">