Mybatis基础(下)

简介: Mybatis基础(下)

复杂查询


@Data
public class Teacher {
    int tid;
    String name;
    List<Student> studentList;
}


一个老师可以教授多个学生,那么能否一次性将老师的学生全部映射给此老师的对象呢

映射为Teacher对象时,同时将其教授的所有学生一并映射为List列表,显然这是一种一对多的查询,那么这时就需要进行复杂查询了。

现在需要使用resultMap来自定义映射规则:

<select id="getTeacherByTid" resultMap="asTeacher">
        select *, teacher.name as tname from student inner join teach on student.sid = teach.sid
                              inner join teacher on teach.tid = teacher.tid where teach.tid = #{tid}
</select>
<resultMap id="asTeacher" type="Teacher">
    <id column="tid" property="tid"/>
    <result column="tname" property="name"/>
    <collection property="studentList" ofType="Student">
        <id column="sid" property="sid"/>
        <result column="name" property="name"/>
        <result column="sex" property="sex"/>
    </collection>
</resultMap>


id标签用于在多条记录中辨别是否为同一个对象的数据

通过使用collection来表示将得到的所有结果合并为一个集合,比如上面的数据中每个学生都有单独的一条记录,因此tid相同的全部学生的记录就可以最后合并为一个List,得到最终的映射结果,当然,为了区分,最好也设置一个id,只不过这个例子中可以当做普通的result使用。

@Data
@Accessors(chain = true)
public class Student {
    private int sid;
    private String name;
    private String sex;
    private Teacher teacher;
}
@Data
public class Teacher {
    int tid;
    String name;
}


可以使用resultMap来实现:

<resultMap id="test2" type="Student">
    <id column="sid" property="sid"/>
    <result column="name" property="name"/>
    <result column="sex" property="sex"/>
    <association property="teacher" javaType="Teacher">
        <id column="tid" property="tid"/>
        <result column="tname" property="name"/>
    </association>
</resultMap>
<select id="selectStudent" resultMap="test2">
    select *, teacher.name as tname from student left join teach on student.sid = teach.sid
                                                 left join teacher on teach.tid = teacher.tid
</select>


事务操作


获取SqlSession关闭自动提交来开启事务模式:

public static void main(String[] args) {
    try (SqlSession sqlSession = MybatisUtil.getSession(false)){
        TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
        testMapper.addStudent(new Student().setSex("男").setName("小王"));
        testMapper.selectStudent().forEach(System.out::println);
    }
}


提交事务:

sqlSession.commit();


事务回滚:

sqlSession.rollback();


动态 SQL


动态 SQL 是 MyBatis 的强大特性之一。可以根据不同条件拼接 SQL 语句


if

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


如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果


choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 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>


缓存机制

Mybatis内置了一个缓存机制,我们查询时,如果缓存中存在数据,那么我们就可以直接从缓存中获取,而不是再去向数据库进行请求。

Mybatis存在一级缓存和二级缓存,默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存(一级缓存无法关闭,只能调整)

cf23898427535027178f9e95a5367fcb.png

一级缓存,在进行DML操作后,会使得缓存失效。

当前会话结束后,也会清理全部的缓存,因为已经不会再用到了。

一级缓存只针对于单个会话,多个会话之间不相通。

public static void main(String[] args) throws InterruptedException {
    try (SqlSession sqlSession = MybatisUtil.getSession(true)){
        TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
        Student student1 = testMapper.getStudentBySid(1);
        Student student2 = testMapper.getStudentBySid(1);
        System.out.println(student1 == student2);
    }
}


一级缓存给我们提供了很高速的访问效率,但是它的作用范围实在是有限,如果一个会话结束,那么之前的缓存就全部失效了

如果希望缓存能够扩展到所有会话都能使用,可以通过二级缓存来实现

二级缓存默认是关闭状态,要开启二级缓存,需要在映射器XML文件中添加:

<cache/>


<cache
  eviction="FIFO" //缓存淘汰策略
  flushInterval="60000"  //缓存刷新间隔
  size="512"   //缓存个数
  readOnly="true"/>  //只读缓存

如果我不希望某个方法开启缓存呢?我们可以添加useCache属性来关闭缓存:

<select id="getStudentBySid" resultType="Student" useCache="false">
    select * from student where sid = #{sid}
</select>


可以使用flushCache="false"在每次执行后都清空缓存,通过这这个我们还可以控制DML操作完成之后不清空缓存。

<select id="getStudentBySid" resultType="Student" flushCache="true">
    select * from student where sid = #{sid}
</select>


添加了二级缓存之后,会先从二级缓存中查找数据,当二级缓存中没有时,才会从一级缓存中获取,当一级缓存中都还没有数据时,才会请求数据库

如果存在多台服务器或者是多个程序都在使用Mybatis操作同一个数据库,并且都开启了缓存会存在缓存一致性问题,此时得关闭Mybatis的缓存来保证一致性:

<settings>
    <setting name="cacheEnabled" value="false"/>
</settings>


<select id="getStudentBySid" resultType="Student" useCache="false" flushCache="true">
    select * from student where sid = #{sid}
</select>


注解开发


直接使用注解来实现XML中定义映射规则和SQL语句并绑定到一个接口的方法定义上

@Insert("insert into student(name, sex) values(#{name}, #{sex})")
int addStudent(Student student);


修改一下配置文件中的映射器注册:

<mappers>
    <mapper class="com.test.mapper.MyMapper"/>
    <!--  也可以直接注册整个包下的 <package name="com.test.mapper"/>  -->
</mappers>


进行自定义映射规则:

@Results({
        @Result(id = true, column = "sid", property = "sid"),
        @Result(column = "sex", property = "name"),
        @Result(column = "name", property = "sex")
})
@Select("select * from student")
List<Student> getAllStudent();


@Result注解数组,每个@Result注解都都一个单独的字段配置

复杂查询:

@Results({
        @Result(id = true, column = "tid", property = "tid"),
        @Result(column = "name", property = "name"),
        @Result(column = "tid", property = "studentList", many =
            @Many(select = "getStudentByTid")
        )
})
@Select("select * from teacher where tid = #{tid}")
Teacher getTeacherBySid(int tid);
@Select("select * from student inner join teach on student.sid = teach.sid where tid = #{tid}")
List<Student> getStudentByTid(int tid);


多出了一个子查询,而这个子查询是单独查询该老师所属学生的信息,而子查询结果作为@Result注解的一个many结果,代表子查询的所有结果都归入此集合中(也就是之前的collection标签)

@Result也提供了@One子注解来实现一对一的关系表示,类似于之前的assocation标签:

@Results({
        @Result(id = true, column = "sid", property = "sid"),
        @Result(column = "sex", property = "name"),
        @Result(column = "name", property = "sex"),
        @Result(column = "sid", property = "teacher", one =
            @One(select = "getTeacherBySid")
        )
})
@Select("select * from student")
List<Student> getAllStudent();


直接使用注解编写SQL语句但是我希望映射规则依然使用XML来实现,提供了@ResultMap注解,直接指定ID即可:

@ResultMap("test")
@Select("select * from student")
List<Student> getAllStudent();


通过@ConstructorArgs注解来指定构造方法:

@ConstructorArgs({
        @Arg(column = "sid", javaType = int.class),
        @Arg(column = "name", javaType = String.class)
})
@Select("select * from student where sid = #{sid} and sex = #{sex}")
Student getStudentBySidAndSex(@Param("sid") int sid, @Param("sex") String sex);


当参数列表中出现两个以上的参数时,添加@Param来指定参数名称:

@Select("select * from student where sid = #{sid} and sex = #{sex}")
Student getStudentBySidAndSex(@Param("sid") int sid, @Param("sex") String sex);


通过参数名称.属性的方式去让Mybatis知道我们要用的是哪个属性:

@Insert("insert into student(sid, name, sex) values(#{sid}, #{student.name}, #{student.sex})")
int addStudent(@Param("sid") int sid, @Param("student")  Student student);


注解控制缓存机制:

@CacheNamespace(readWrite = false)
public interface MyMapper {
    @Select("select * from student")
    @Options(useCache = false)
    List<Student> getAllStudent();


Sex(@Param(“sid”) int sid, @Param(“sex”) String sex);

当参数列表中出现两个以上的参数时,添加`@Param`来指定参数名称:
~~~java
@Select("select * from student where sid = #{sid} and sex = #{sex}")
Student getStudentBySidAndSex(@Param("sid") int sid, @Param("sex") String sex);


通过参数名称.属性的方式去让Mybatis知道我们要用的是哪个属性:

@Insert("insert into student(sid, name, sex) values(#{sid}, #{student.name}, #{student.sex})")
int addStudent(@Param("sid") int sid, @Param("student")  Student student);


注解控制缓存机制:

@CacheNamespace(readWrite = false)
public interface MyMapper {
    @Select("select * from student")
    @Options(useCache = false)
    List<Student> getAllStudent();


使用@CacheNamespace注解直接定义在接口上即可,然后我们可以通过使用@Options来控制单个操作的缓存启用。

相关文章
|
6月前
|
SQL Java 数据库连接
【MyBatis】搭建MyBatis
【MyBatis】搭建MyBatis
46 0
|
6月前
|
Java 数据库连接 mybatis
mybatis技术总篇
mybatis技术总篇
|
11月前
|
XML Java 数据库连接
Mybatis基础(上)
Mybatis基础(上)
|
SQL Java 数据库连接
Mybatis/Mybatis-Plus基础(二)
Mybatis/Mybatis-Plus基础
95 0
|
SQL Java 数据库连接
Mybatis/Mybatis-Plus基础(一)
Mybatis/Mybatis-Plus基础
84 0
|
SQL Java 数据库连接
Mybatis/Mybatis-Plus基础(四)
Mybatis/Mybatis-Plus基础
135 0
|
SQL XML 算法
Mybatis/Mybatis-Plus基础(三)
Mybatis/Mybatis-Plus基础
237 0
|
SQL 存储 Java
MyBatis 学习笔记(二)MyBatis常用特性运用
接上一篇MyBatis 学习笔记(一)MyBatis的简介与使用以及与其他ORM框架的比较,今天我们接着来学习MyBatis的一些常用特性,包括别名,类型处理器,动态SQL
103 0
MyBatis 学习笔记(二)MyBatis常用特性运用
|
XML Java 数据库连接
下一篇
无影云桌面