Mybatis应用场景详解——学会在开发中真正应用

在看完mybatis简单入门之后,了解了mybatis程序的环境搭建和完整流程,紧接着就是功能的应用,本篇文章主要讲解了mybatis的常见应用场景

mybatis入门文章链接:mybatis入门

1、主键返回

通常我们会将数据库表的主键id设为自增。在插入一条记录时,我们不设置其主键id,而让数据库自动生成该条记录的主键id,那么在插入一条记录后,如何得到数据库自动生成的这条记录的主键id呢?有两种方式

  1. 使用 useGenerateKeyskeyProperty 属性 ==》基于mysql这种支持自增长的数据库
<mapper namespace="chen.mapper.StudentMapper">
    <insert id="addStudent" parameterType="chen.pojo.Student" useGeneratedKeys="true" keyProperty="id">
        insert into Student(name,age) values(#{name},#{age})
    </insert>
</mapper>
  1. 使用 < selectKey > 子标签 ==> 基于oracle这种不支持自增长的数据库

其实< selectKey就是一条sql语句,我们把它放在主sql语句执行之后,将其执行得到的结果封装到java对象的指定属性上,只能用在insert和update中,下面代码中的LAST_INSERT_ID()实际上是MySQL提供的一个函数,用来获得最近插入或更新的主键id

    <insert id="addStudent2" parameterType="chen.pojo.Student">
        insert into Student(name,age) values(#{name},#{age})
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            select LAST_INSERT_ID();
        </selectKey>
    </insert>

测试代码

    @Test
    public void addStudent(){
    
    
        SqlSession sqlSession = MybatisUtils.getSqlSession(); //已经封装好的mybatis工具类的调用

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        Student student = new Student(-1, "huang", 18);
        studentMapper.addStudent(student);

        sqlSession.commit();
        sqlSession.close();
    }

结果
在这里插入图片描述

2、批量查询

主要是动态SQL标签的使用,如果parameterType是List的话,则在标签体内用List;如果parameterType是数组的话,那么只能用变量名array

    <select id="findStudent" resultType="chen.pojo.Student" parameterType="java.util.List">
        select * from Student
        <where>
            <if test="list != null and list.size() > 0">
                and id in
                <foreach collection="list" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
    </select>
    @Test
    public void findStudent(){
    
    
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        List<Student> students = studentMapper.findStudent(Arrays.asList(1,2));

        students.forEach(System.out::println);

        sqlSession.commit();
        sqlSession.close();
    }

结果
在这里插入图片描述

3、动态SQL

3.1、if

只有当满足条件的时候,才会执行if标签里的语句,该例子实现模糊查询,模糊查询用&{}

    <select id="find" resultType="chen.pojo.Student">
        select * from Student where age >= 18
        <if test="name!=null and name!=''">
            and name like '%${name}%'
        </if>
    </select>

3.2、choose

choose和wen,otherwise 是配套标签,类似于java中的switch,只会选择满足条件的一个

    <select id="find2" resultType="chen.pojo.Student" parameterType="int">
        select * from Student where age > #{age}
        <choose>
            <when test="age>=20">
                and name = "chen"
            </when>
            <otherwise>
                and name = "lin"
            </otherwise>
        </choose>
    </select>

3.3、foreach

使用来做迭代连接的,通常会与sql语句中的in做连接查询条件结合使用,其中foreach标签的属性,collection是看你是数组害死List,item指明哪一列,open即开头,close即结尾,separartor是以什么分隔

    <select id="findStudent" resultType="chen.pojo.Student" parameterType="java.util.List">
        select * from Student
        <where>
            <if test="list != null and list.size() > 0">
                and id in
                <foreach collection="list" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
    </select>

3.4、sql

可以将重复的sql片段提取出来,然后在需要的地方,使用< include >标签进行引用

    <select id="find3" parameterType="chen.pojo.Student" resultType="chen.pojo.Student">
        select * from Student
        <include refid="whereName"/>
    </select>

    <sql id="whereName">
        <where>
            name like '%${name}%'
        </where>
    </sql>

4、缓存

  • 一级缓存
    默认开启,同一个SqlSession级别共享的缓存,在一个SqlSession的生命周期内,执行两次相同的SQL查询,则第二次查询会直接取缓存的数据,而不走数据库。当然,若第一次和第二次相同的SQL查询之间,执行了DML(增删改),则第一缓存会被清空,第二次查询仍然会走数据库
    一级缓存在下面清空下会被清空:
    (1)在同一个SqlSession中执行增删改操作(不必提交)会清除一级缓存
    (2)SqlSession在关闭时,会清除一级缓存
    (3)在mapper.xml中某个crud标签,设置属性flushCache=true,这样一级和二级缓存都会失效
    (4)在全局配置文件中设置< setting name=“localCacheScope” value=“STATEMENT”>,这样一级魂村会失效,二级缓存不受影响
  • 二级缓存
    默认关闭,可以通过全局配置文件中的< setting name=“cacheEnabled” value=“true”>开启二级缓存总开关,然后在某个mapper.xml中增加< cache />,即开启了二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个sqlSession中可以共享一个二级缓存,开启二级缓存后, 需要提交sqlSession,查询的数据才会被刷新到二级缓存中

5、关联查询

使用< resultMap > 标签(一对多)以及 < assocaition> (一对一)和 < collection>子标签(多对多),进行关联查询

文章链接:关联查询详解

6、延时加载

延时加载和关联查询是结合进行应用的,也就是说,只在< assocaition> 和 < collection> 标签上起作用:对于延时加载的作用可以这么理解,如果我们不采用延时加载的话,比如用户和订单的信息是一对多的关系,在查询用户信息时设置了关联查询订单,若不采用延时加载策略,我们查这一百个用户的信息只需要一个sql查询;若开启了关联查询且不是延时加载,则对于这一百个用户,我们会发出100条sql语句去查询订单信息,而我们可能只关心id=3的订单信息,所以很多关联信息是没有用的

开启:< setting name=“lazyLoadingEnabled” value=“true”/>

<!-- StudentMapper.xml -->
<resultMap id="studentExt" type="com.yogurt.po.StudentExt">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="score" column="score"/>
        <result property="age" column="age"/>
        <result property="gender" column="gender"/>
		<!-- 当延迟加载总开关开启时,resultMap下的association和collection标签中,若通过select属性指定嵌套查询的SQL,则其fetchType默认是lazy的,当在延迟加载总开关开启时,需要对个别的关联查询禁用延迟加载时,才有必要配置fetchType = eager -->
    	<!--
 		column用于指定用于关联查询的列
		property用于指定要封装到StudentExt中的哪个属性
		javaType用于指定关联查询得到的对象
		select用于指定关联查询时,调用的是哪一个DQL
		-->
        <association property="clazz" javaType="com.yogurt.po.Clazz" column="class_id"
                     select="com.yogurt.mapper.ClassMapper.findById" fetchType="lazy"/>

    </resultMap>

    <select id="findLazy" parameterType="string" resultMap="studentExt">
        SELECT * FROM student WHERE name like '%${value}%';
    </select>

<!-- com.yogurt.mapper.ClassMapper -->
<select id="findById" parameterType="int" resultType="com.yogurt.po.Clazz">
        SELECT * FROM class WHERE id = #{id}
</select>

/** 用于封装关联查询的对象 **/
public class StudentExt{

	private Integer id;

	private String name;

	private Integer score;

	private Integer age;

	private Integer gender;

    /** 关联对象 **/
	private Clazz clazz;
    
   	//getter/setter
}

猜你喜欢

转载自blog.csdn.net/qq_45151059/article/details/113815148