Mybatis第二天

动态sql

if

满足if的判断条件,if中的语句会被拼接入sql中。

<select id="findActiveBlogLike"
     resultType="Blog">
 SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <if test="title != null">
   AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
   AND author_name like #{author.name}
  </if>
</select>

choose、when、otherwise

类似Java中的switch,传入了那个参数,就使用哪个参数作为查询条件。

<select id="findActiveBlogLike"
     resultType="Blog">
 SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
     AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
     AND author_name like #{author.name}
    </when>
    <otherwise>
     AND featured = 1
    </otherwise>
  </choose>
</select>

trim、where、set

<select id="findActiveBlogLike"
     resultType="Blog">
 SELECT * FROM BLOG
 WHERE
  <if test="state != null">
   state = #{state}
  </if>
  <if test="title != null">
   AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
   AND author_name like #{author.name}
  </if>
</select>

这个情况下,如果if都判断为false,那么sql语句就会多出一个where,可以使用< where >标签代替where

<select id="findActiveBlogLike"
     resultType="Blog">
 SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
       AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
       AND author_name like #{author.name}
    </if>
  </where>
</select>

where 元素只会在子元素返回任何内容的情况下才插入 WHERE 子句。而且,若子句的开头为 AND 或 OR , where 元素也会将它们去除。如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
 ...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

用于动态更新语句的类似解决方案叫做 set 。 set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

<update id="updateAuthorIfNecessary">
 update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
 where id=#{id}
</update>

这个例子中, set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
比如:

<select id="selectPostIn" resultType="domain.blog.Post">
 SELECT *
 FROM POST P
 WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
       #{item}
  </foreach>
</select>

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符。
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach 。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

Mybatis的特殊功能

处理枚举类型

默认情况下MyBatis使用EnumTypeHandler来处理enum类型的Java属性,并且将其存储为enum值的名称。我们不需要为此做任何额外的配置。可以像使用基本数据类型属性一样使用enum类型属性。
当执行insertStudent语句的时候MyBatis会取Gender枚举(FEMALE/MALE)的名称,存储到GENDER列中。如果你想存储FEMALE为0,MALE为1到gender列中,需要在mybatis-config.xml文件中配置专门的类型处理器,并指定它处理的枚举类型是哪个。

<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.briup.special.Gender"/>

注意:枚举类型的【顺序值】是根据enum中的声明顺序赋值的。如果改变了Gender里面对象的声明顺序,则数据库存储的数据和此顺序值就不匹配了。

sql语句需要传入多个参数

MyBatis中的映射语句有一个parameterType属性来制定输入参数的类型。如果我们想给映射语句传入多个参数的话,我们可以将所有的输入参数放到HashMap中,将HashMap传递给映射语句。其实就是把多个参数存到Map中,把Map当做一个参数再传给sql语句,mybaits收到后再解析Map集合拿到每一个参数。同时MyBatis还提供了另外一种传递多个输入参数给映射语句的方法。
例如我们想通过给定的name和email信息查找学生信息,定义查询接口如下:
对于映射器中的方法,MyBatis默认从左到右给方法的参数命名为param1、param2…,依次类推。

<update id="updateUserPicNameById1" parameterType="map">
 update user_pics set name = #{name} where id = #{id}
</update>
 
<update id="updateUserPicNameById2">
 update user_pics set name = #{param2} where id = #{param1}
</update>
void updateUserPicNameById1(Map<String,String> map);
void updateUserPicNameById2(Integer id,String name);

使用RowBounds对结果集进行分页

MyBatis可以使用RowBounds逐页加载表数据。RowBounds对象可以使用offset和limit参数来构建。参数offset表示开始位置,而limit表示要取的记录的数目。
但是其实Mybatis的分页是基于内存的分页(查出所有记录再按偏移量offset和limit取结果),在大数据量的情况下这样的分页效率会很低,后面我们会使用mybaits的分页辅助工具来完成分页。
oracle使用rownum也可以完成分页: rownum(伪列)是oracle中独有的,是在查询过程中动态生成的一个列,该列不会在数据库中真实添加,表示查询出的每行数据的行号,第一行的行号是1,以此类推。
rownum的操作要求:
rownum 可以等于1
rownum 可以大于0
rownum 可以小于任何数
但是可以给rownum其一个别名,并把sql语句查询结果当做一张表再查询,这样就可以对这个行号进行任意操作了。

缓存

默认情况下,mybatis会启用一级缓存。如果使用同一个session对象调用了相同的SELECT语句,则直接会从缓存中返回结果,而不是再查询一次数据库。

注意:session调用commit或close方法后,这个session中的一级缓存就会被清空

二级缓存: 在不同的session对象之间可以共享缓存的数据

  1. mybatis-config.xml 文件中保证 < setting name=“cacheEnabled” value=“true”/> 设置中是缓存功能是开启的,默认就是开启的true
  2. 在需要二级缓存的xml映射文件中,手动开启缓存功能,在根元素中加入一个标签即可: < cache/>
  3. 一个session查询完数据之后,需要调用commit或者close方法后,这个数据才会进入到二级缓存中,然后其他session就可以共享到这个缓存数据了。

注意:默认情况下,被二级缓存保存的对象需要实现序列化接口。

二级缓存补充说明

  1. 映射语句文件中的所有select语句将会被缓存
  2. 映射语句文件中的所有insert,update和delete语句会刷新缓存
  3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。
  4. 缓存会根据指定的时间间隔来刷新。
  5. 缓存会存储1024个对象

cache标签常用属性:
eviction=“FIFO” flushInterval=“60000” size=“512” readOnly=“true”

Mybatis注解

@Insert

插入注解,标记这个接口对应的方法用于插入数据库。
自动生成主键可以使用 @Options注解的userGeneratedKeys和keyProperty属性让数据库产生 auto_increment(自增长)列的值,然后将生成的值设置到输入参数对象的属性中。

@Insert("insert into students(name,email,addr_id, phone)
 values(#{name},#{email},#{address.addr Id},#{phone})")
@Options(useGeneratedKeys = true, keyProperty = "studId")
int insertStudent(Student student);

有一些数据库如Oracle,并不支持AUTO_INCREMENT列属性,它使用序列(SEQUENCE)来产生主键的值。我们可以使用@SelectKey注解来为任意SQL语句来指定主键值,作为主键列的值。假设我们有一个名为STUD_ID_SEQ的序列来生成STUD_ID主键值。

@Insert("insert into students(stud_id,name,email,addr_id,phone) values(#{studId},#
{name},#{email},#{address.addrId},#{phone})")
 @SelectKey(statement="select my_seq.nextval from dual",  
 keyProperty="studId", resultType=int.class, before=true)
 int insertStudent(Student student);

@Update

定义一个update映射语句

@Delete

定义一个DELETE映射语句

@Select

定义一个Select映射语句,

结果集映射

可以将查询结果通过别名或者是@Results注解与实体类的属性映射起来。

@Select("select * from students")
@Results(
 {
 @Result(id = true, column = "stud_id", property = "studId"),
 @Result(column = "name", property = "name"),
 @Result(column = "email", property = "email"),
 @Result(column = "addr_id", property = "address.addrId")
})
List<Student> findAllStudents();

也可以在xml中定义结果集,然后在注解中引用。例如:

@Select("select * from students where stud_id=#{studId}")
 @Results(
 {
 @Result(id = true, column = "stud_id", property = "studId"),
 @Result(column = "name", property = "name"),
 @Result(column = "email", property = "email"),
 @Result(column = "addr_id", property = "address.addrId")
 })
 Student findStudentById(int studId);
 
 @Select("select * from students")
 @Results(
 {
 @Result(id = true, column = "stud_id", property = "studId"),
 @Result(column = "name", property = "name"),
 @Result(column = "email", property = "email"),
 @Result(column = "addr_id", property = "address.addrId")
 })
 List<Student> findAllStudents();

这里两个语句的 @Results配置完全相同,可以创建一个映射文件,文件中配置< resultMap>元素,然后使用@ResultMap注解引用此< resultMap>。 在StudentMapper.xml中定义一个ID为StudentResult的< resultMap>。

<mapper namespace="com.briup.mappers.StudentMapper">
  <resultMap type="Student" id="StudentResult">
 	<id property="studId" column="stud_id" />
 	<result property="name" column="name" />
 	<result property="email" column="email" />
 	<result property="phone" column="phone" />
  </resultMap>
</mapper>

在StudentMapper.java中,使用 @ResultMap引用名为StudentResult的resultMap:

public interface StudentMapper{
 @Select("select * from students where stud_id=#{studId}")
 @ResultMap("com.briup.mappers.StudentMapper.StudentResult")
 Student findStudentById(int studId);
 @Select("select * from students")
 @ResultMap("com.briup.mappers.StudentMapper.StudentResult")
 List<Student> findAllStudents();
 }

一对一映射

MyBatis提供了 @One注解来使用嵌套select语句(Nested-Select)加载一对一关联查询数据。
例如,使用@One注解获取学生及其地址信息 @Result注解中,有one这个属性,也有many这个属性。

public interface StudentMapper{
 @Select("select addr_id as addrId, street, city, state, zip, country from
addresses where addr_id=#{id}")
 Address findAddressById(int id);
 @Select("select * from students where stud_id=#{studId} ")
 @Results(
 {
 @Result(id = true, column = "stud_id", property = "studId"),
 @Result(column = "name", property = "name"),
 @Result(column = "email", property = "email"),
 @Result(property = "address", column = "addr_id",
 one = @One(select = "com.briup.mappers.Student Mapper.findAddressById"))
 })
 Student selectStudentWithAddress(int studId);
 }

这里使用了@One注解的select属性来指定一个方法,该方法会返回一个Address对象。使用column=“addr_id”,则 STUEDNTS表中列addr_id的值将会作为输入参数传递给findAddressById()方法。如果 @One SELECT查询返回了多行结果,则会抛出TooManyResultsException异常。之前可以通过基于XML的映射配置,使用嵌套结果ResultMap来加载一对一关联的查询。而MyBatis当前版本中,并没有对应的注解支持。但是可以在映射文件中把1对1的嵌套结果形式的映射信息配置好,然后在@ResultMap注解中去引用它。在StudentMapper.xml中配置< resultMap>,如下所示:

<mapper namespace="com.briup.mappers.StudentMapper">
  <resultMap type="Address" id="AddressResult">
 <id property="addrId" column="addr_id" />
 <result property="street" column="street" />
 <result property="city" column="city" />
 <result property="state" column="state" />
 <result property="zip" column="zip" />
 <result property="country" column="country" />
  </resultMap>
  <resultMap type="Student" id="StudentWithAddressResult">
 <id property="studId" column="stud_id" />
 <result property="name" column="name" />
 <result property="email" column="email" />
 <association property="address" resultMap="AddressResult" />
  </resultMap>
 </mapper>
public interface StudentMapper{
 @Select("select stud_id, name, email, a.addr_id, street, city, state, zip,
country" + " FROM students s left outer join addresses a on s.addr_id=a.addr_id" + "
where stud_id=#{studId} ")
 @ResultMap("com.briup.mappers.StudentMapper.StudentWithAddressResult")
 Student selectStudentWithAddress(int id);
}

一对多映射

MyBatis提供了@Many注解,用来使用嵌套Select语句加载一对多关联查询。
例如,使用@Many注解获取一个讲师及其教授课程列表信息:

public interface TutorMapper{
@Select("select addr_id as addrId, street, city, state, zip, country from addresses where addr_id=#{id}")
Address findAddressById(int id);
@Select("select * from courses where tutor_id=#{tutorId}") @Results({
 @Result(id = true, column = "course_id", property = "courseId"),
 @Result(column = "name", property = "name"),
 @Result(column = "description", property = "description"),
 @Result(column = "start_date" property = "startDate"),
 @Result(column = "end_date" property = "endDate")
})
List<Course> findCoursesByTutorId(int tutorId);
@Select("SELECT tutor_id, name as tutor_name, email, addr_id FROM tutors where tutor_id=#{tutorId}")
@Results({
 @Result(id = true, column = "tutor_id", property = "tutorId"),
 @Result(column = "tutor_name", property = "name"),
 @Result(column = "email", property = "email"),
 @Result(property = "address", column = "addr_id" one = @One(select = "com.briup.mappers.TutorMapper.findAddressById")),
 @Result(property = "courses", column = "tutor_id", many = @Many(select = "com.briup.mappers.TutorMapper.findCoursesByTutorId"))
 })
 Tutor findTutorById(int tutorId);
}

这里使用了@Many注解的select属性来指向一个方法,该方法将返回一个List< Course >对象。
使用column=”tutor_id”,TUTORS表中的tutor_id列值将会作为输入参数传递给findCoursesByTutorId()方法。
之前可以通过基于XML的映射配置,使用嵌套结果ResultMap来加载一对N关联的查询。而MyBatis当前版本,并没有对应的注解支持。
但是可以在映射文件中把1对N的嵌套结果形式的映射信息配置好,然后在@ResultMap注解中去引用它。
例如,在TutorMapper.xml中配置< resultMap >

<mapper namespace="com.briup.mappers.Tutor Mapper"> 
<resultMap type="Address" id="AddressResult"> 
<id property="addrId" column="addr_id" />
<result property="street" column="street" />
<result property="city" column="city" />
<result property="state" column="state" />
<result property="zip" column="zip" />
<result property="country" column="country" />
</resultMap>
<resultMap type="Course" id="CourseResult">
 <id column="course_id" property="course Id" />
 <result column="name" property="name" />
 <result column="description" property="description" />
 <result column="start_date" property="startDate" />
 <result column="end_date" property="endDate" />
</resultMap> 
<resultMap type="Tutor" id="TutorResult">
 <id column="tutor_id" property="tutorId" />
 <result column="tutor_name" property="name" />
 <result column="email" property="email" />
 <association property="address" result Map="AddressResult" />
 <collection property="courses" result Map="CourseResult" />
</resultMap>
</mapper>
public interface TutorMapper{
@Select("select t.tutor_id, t.name as tutor_name,email,a.addr_id, street, city, state, zip, country, course_id, c.name,description, start_date, end_date from tutors t left outer join addresses a on t.addr_id=a.addr_id left outer join courses c on t.tutor_id=c.tutor_id where t.tutor_id=#{tutorId}") 
@Result Map("com.briup.mappers.TutorMapper.TutorResult") 
Tutor selectTutorById(int tutorId);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值