mybatis动态sql使用以及增删改查的知识点

Posted xiaoqiang_0719

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis动态sql使用以及增删改查的知识点相关的知识,希望对你有一定的参考价值。

点击这里 查看Mybatis动态SQL官方文档
对于初学者来说查看文档内容有好多细节不理解这里我结合我自身学习动态SQL实际遇到的困惑以及细节标示做一个梳理
首先几个常用的关键字:

  • if 判断,当条件符合则进入条件语句(#id代表传入的值)

  <!--  如果条件都满足 则sql为   select * from test_table where id=? and last_name=?
        如果id==null则sql为  select * from test_table where  and last_name=?  sql就会报错
        两种处理方案 1.          
        我们使用 select * from test_table where 1=1 后面所有的if 前面都加 and
        select * from test_table where 1=1
         <if test="id!=null">
           and id=#id
        </if>
        <if test="lastName!=null">
            and last_name=#lastName,
        </if>
        2.使用where标签   <where></where> 后面单独讲
-->
 select * from test_table where
    <if test="id!=null">
     id=#id
    </if>
    <if test="lastName!=null">
      and last_name=#lastName,
    </if>



  • choose (when, otherwise):分支选择;类似于我们的swtich-case break语句,只会进入一个选择条件
    <!-- public List<TestBean> getInfo(TestBean testbean); -->
    <select id="getInfo" resultType="com.xiaoqiang.mybatis.bean.TestBean">
        select * from test_table
        <where>
            <!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
            <choose>
                <when test="id!=null">
                    id=#id
                </when>
                <when test="lastName!=null">
                    last_name like #lastName
                </when>
                <when test="email!=null">
                    email = #email
                </when>
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>
  • trim 字符串截取(where(封装查询条件), set(封装修改条件))
<!-- 使用where标签
     如果拼接第一个条件的时候第一个条件不成立则sql就会报错,
     例如下面代码的id==null则不会进入id=#id  sql就变成:select * from table where and email=? 明显sql报错
     使用where标签就会把前面的and去掉,保证sql正常。
     但是如果我们把and加到语句后面则where标签就无法实现了只能使用  trim  标签来处理,一般没这么写的
     <if test="id!=null">
      id=#id and
     </if>
 -->
       <where>    
            <if test="id!=null">
                id=#id
            </if>
         <if test="email!=null">
             and email=#email
            </if>
        </where>
        
 <!-- 使用set 是为了如果拼到最后的还有逗号,就会把最后的逗号去掉 我们仍然可以使用 trim 标签来替代set标签-->
   <update id="updateBean">
        <!-- Set标签的使用 -->
        update test_table 
        <set>
            <if test="lastName!=null">
                last_name=#lastName,
            </if>
            <if test="email!=null">
                email=#email,
            </if>
        </set>
        where id=#id
     </update>
     
     <!--我们使用trim标签替代where标签来定制where标签功能-->
      <select id="getBean" resultType="com.xiaoqiang.mybatis.bean.TestBean">
        select * from test_table 
        <!-- 后面多出的and或者or where标签不能解决的问题
        prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。
                prefix给拼串后的整个字符串加一个前缀
        prefixOverrides="":
                前缀覆盖: 去掉整个字符串前面多余的字符
        suffix="":后缀
                suffix给拼串后的整个字符串加一个后缀
        suffixOverrides=""
                后缀覆盖:去掉整个字符串后面多余的字符
        -->
        <!-- 自定义字符串的截取规则       suffixOverrides处理后缀and -->
        <trim prefix="where" suffixOverrides="and">
            <if test="id!=null">
                id=#id and
            </if>
            <if test="lastName!=null">
                last_name like #lastName and
            </if>
            <if test="email!=null">
                email=#email and
            </if>
        </trim>
    </select>
    
          <!--我们使用trim标签替代set标签  suffixOverrides处理后缀逗号-->
      update test_table 
             <trim prefix="set" suffixOverrides=",">
                 <if test="lastName!=null">
                      last_name=#lastName,
                 </if>
                 <if test="email!=null">
                      email=#email,
                 </if>
             </trim>
       where id=#id  
       
  • foreach 遍历集合
    <!--public List<TestBean> getBeans(List<Integer> ids);  -->
    <select id="getBeans" resultType="com.xiaoqiang.mybatis.bean.TestBean">
        select * from test_table where id in
        <!--
       sql :     select * from test_table where id in (1,2,3)
            collection:指定要遍历的集合
            item:将当前遍历出的元素赋值给指定的变量
            separator:每个元素之间的分隔符
            open:遍历出所有结果拼接一个开始的字符
            close:遍历出所有结果拼接一个结束的字符
            index:索引。遍历list的时候是index就是索引,item就是当前值
                          遍历map的时候index表示的就是map的key,item就是map的值

            使用#变量名就能取出变量的值也就是当前遍历出的元素
          -->
        <foreach collection="ids" item="item_id" separator=","
                 open="(" close=")">
            #item_id
        </foreach>
    </select>
    
  • 抽取重复片段使用:
  <!--
        抽取可重用的sql片段。方便后面引用
        1、sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
        2、include来引用已经抽取的sql
    -->
    <sql id="insertColumn">
       last_name,email
    </sql>
      <!-- 使用include 重用抽取出来的sql片段  -->
     insert into test_table (
        <include refid="insertColumn"></include>
          ) 
     values('name','xiaoqiang@163.com')

增删改查知识点记录:

获取自增主键只有设置useGeneratedKeys=“true” keyProperty="id"才能通过返回的bean拿到相应的id

	<!-- 
	获取自增主键的值:
		mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();
		useGeneratedKeys="true";使用自增主键获取主键值策略
		keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性
	-->
	<insert id="addEmp" useGeneratedKeys="true" keyProperty="id" >
		insert into test_table (last_name,email) 
		values(#lastName,#email)
	</insert>
	

如果我们传入多个参数 使用#参数名来取值是会报错:
org.apache.ibatis.binding.BindingException: Parameter ‘insert_type’ not found. Available parameters are [a, b, param1, param2]

	<!--
	单个参数:
	mybatis不会做特殊处理,
	#参数名/任意名:可以取出参数值。
    多个参数:
     mybatis会做特殊处理。多个参数会被封装成 一个map,
		key:param1...paramN,或者参数的索引也可以
		value:传入的参数值
	#就是从map中获取指定的key的值;
	  -->
	 <!--传入两个参数不能使用#insert_type #phoneNum这种形式酱紫会报上面错  需要使用param1...-->
    <select id="getTypeTwo" resultType="com.example.demomybatis.bean.myTypeBean">
        SELECT * FROM my_type
        WHERE insert_type=#insert_type and phone_num=#phone_num
    </select>
     <!--正确可使用形式-->
     <select id="getTypeTwo" resultType="com.example.demomybatis.bean.myTypeBean">
        SELECT * FROM my_type
        WHERE insert_type=#param1 and phone_num=#param2
    </select> 

     <!--Controller传入两个参数insertType,phoneNum调用Service的getTypeTwo最终映射到上面的Mapper的sql中使用param
     返回正确查询-->
    @GetMapping(value = "/getTypeTwo")
    public JSONObject getTypeTwo(@RequestParam("insertType") String insertType, @RequestParam("phoneNum") String phoneNum) 
        List<myTypeBean> typeTwo = service.getTypeTwo(insertType, phoneNum);
        JSONObject object = new JSONObject();
        object.put("data", typeTwo);
        object.put("code", "000");
        return object;
    
    
   或者使用第二种形式 -->命名参数(常用形式):在Mapper.java接口修改与xml相对应的的方法,给方法的参数加上@Param("insert_type")明确参数的key 使用#insert_type 就可以拿到相应的值
   
   <!--   import org.apache.ibatis.annotations.Param;-->
    List<myTypeBean> getTypeTwo(@Param("insert_type") String insert_type, @Param("phone_num") String phone_num);

mybatis一级、二级缓存描述

	/**
	 * 两级缓存:
	 * 一级缓存:(本地缓存):sqlSession级别的缓存。一级缓存是一直开启的;SqlSession级别的一个Map
	 * 		与数据库同一次会话期间查询到的数据会放在本地缓存中。
	 * 		以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;
	 * 
	 * 		一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询):
	 * 		1、sqlSession不同。
	 * 		2、sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)
	 * 		3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
	 * 		4、sqlSession相同,手动清除了一级缓存(缓存清空)
	 * 
	 * 二级缓存:(全局缓存):基于namespace级别的缓存:一个namespace对应一个二级缓存:
	 * 		工作机制:
	 * 		1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
	 * 		2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
	 * 		3、sqlSession===EmployeeMapper==>Employee
	 * 						DepartmentMapper===>Department
	 * 			不同namespace查出的数据会放在自己对应的缓存中(map)
	 * 			效果:数据会从二级缓存中获取
	 * 				查出的数据都会被默认先放在一级缓存中。
	 * 				只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
	 * 		使用:
	 * 			1)、开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>
	 * 			2)、去mapper.xml中配置使用二级缓存:
	 * 				<cache></cache>
	 *                      使用一个空cache标签就可以对这个Mapper开启二级缓存
	 *                      cache有很多参数这里一一列举一下:
	 * 
	 *       <cache eviction=""  blocking="" flushInterval="" readOnly="" size="" type="" ></cache>
	 * 
	 *          eviction:缓存的回收策略:
	 *                       • LRU – 最近最少使用的:移除最长时间不被使用的对象。
	 *                       • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
	 *             	        • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。       
	 *                       • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
	 *                       • 默认的是 LRU。    
	 *         flushInterval:缓存刷新间隔 
	 *                         缓存多长时间清空一次,默认不清空,设置一个毫秒值
	 *         readOnly:是否只读:
	 *                         true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
	 * 				                 mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
	 * 	               	      false:非只读:mybatis觉得获取的数据可能会被修改。
	 * 			                      mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢
	 *        size:缓存存放多少元素;
	 * 	      type="":指定自定义缓存的全类名;
	 * 	   	  实现Cache接口即可;
	 *                    	3)、我们的POJO(Bean)需要实现序列化接口 implements Serializable
	 * 
	 * 和缓存有关的设置/属性:
	 * 			1)、cacheEnabled=true:false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)
	 * 			2)、每个select标签都有useCache="true":
	 * 					false:不使用缓存(一级缓存依然使用,二级缓存不使用)
	 * 			3)、【每个增删改标签的:flushCache="true":(一级二级都会清除)】
	 * 					增删改执行完成后就会清楚缓存;
	 * 					测试:flushCache="true":一级缓存就清空了;二级也会被清除;
	 * 					查询标签:flushCache="false":
	 * 						如果flushCache=true;每次查询之后都会清空缓存;缓存是没有被使用的;
	 * 			4)、sqlSession.clearCache();只是清楚当前session的一级缓存;
	 * 			5)、localCacheScope:本地缓存作用域:(一级缓存SESSION);当前会话的所有数据保存在会话缓存中;
	 * 								STATEMENT:可以禁用一级缓存;		
	 * 				
	 *第三方缓存整合:
	 *		1)、导入第三方缓存包即可;
	 *		2)、导入与第三方缓存整合的适配包;官方有;
	 *		3)、mapper.xml中使用自定义缓存
	 *		<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
	 *
	 * 
	 */

以上是关于mybatis动态sql使用以及增删改查的知识点的主要内容,如果未能解决你的问题,请参考以下文章

mybatis 的 sql 映射文件增删改查的学习

Mybatis可以自动生成增删改查的sql.xml文件吗

SpringBoot整合Mybatis实现增删改查的功能

mybatis逆向工程之动态web项目

MyBatis:mybatis Java API编程实现增删改查的用法

mybatis生成的增删改查怎么用