前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >猿蜕变13——一文搞懂mybatis规范和标签

猿蜕变13——一文搞懂mybatis规范和标签

作者头像
山旮旯的胖子
发布2020-07-28 17:00:25
5110
发布2020-07-28 17:00:25
举报
文章被收录于专栏:猿人工厂猿人工厂

看过之前的蜕变系列文章,相信你对mybatis有了初步的认识。很多朋友编写mybatis比较随意,甚至工具生成的痕迹都经常见到,这个不是很好,sql是比较关键和核心的地方,不能骚整噢。我们今天进一步来了解下mybatis的一些规范写法和常用标签。

现在又要告诉大家一个不幸的消息:数据库的命名是有规范的,基本上不太会出现数据库字段名和类中的属性名一一对应的情况。不要问我为什么,因为大家都这么搞,大家是得罪不起的,如果你把数据库字段名和类中的属性名一致了,准备承受dba来自地狱的怒吼吧。我们之前为了解决这个问题,在sql语句中使用了as 的别名语法,这样写其实是很费力的。Mybatis提供了resultMap来解决这个问题,我们回到正途使用resultMap。

resultType实际上是将数据库表字段与JavaBean中的属性建立映射关系,在编写SQL的时候使用resultMap,mybatis会依据resultMap中的映射关系将数据库返回的记录映射到对应的字段上。

修改TravelRouteMapper.xml增加一个resultMap

代码语言:javascript
复制
 <resultMap type="TravelRoute" id="TravelRouteType" >

      <result column = "travel_route_id"property="travelRouteId"/>
      <result column = "travel_route_name"property="travelRouteName"/>
      <result column = "travel_route_price"property="travelRoutePrice"/>
      <result column = "travel_route_introduce"property="travelRouteIntroduce"/>
      <result column = "travel_route_flag"property="travelRouteFlag"/>
      <result column = "travel_route_date"property="travelRouteDate"/>
      <result column = "isThemeTour"property="isThemeTour"/>
      <result column = "travel_route_count"property="travelRouteCount"/>
      <result column = "travel_route_cid"property="travelRouteCid"/>
      <result column = "travel_route_image"property="travelRouteImage"/>
      <result column ="travel_route_seller_id"property="travelRouteSellerId"/>
</resultMap>

我们将之前使用as 语法的queryTravelByPage和queryTravelById的as xxx去掉,将resultType改为TravelRoute。留下一个queryTravelByName当作复习语法的例子就好,就不赶尽杀绝了。

代码语言:javascript
复制
  <select id="queryTravelByPage"resultMap="TravelRouteType" parameterType="java.util.Map">
   
     select
       travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count ,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id
    
      from   travel_route order by travel_route_id desc limit #{startRow},#{endRow}
     
    </select>
   
     <select id="queryTravelById"resultMap="TravelRouteType" parameterType="Long">
   
     select
       travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id 
    
      from   travel_route where travel_route_id =#{travelRouteId}
   
    </select>
   
   

运行测试程序,保证代码修改正确!

之前编写的例子中,我们都自己实现了dao接口,其实mybatis提供了动态代理的方式,无需由开发人员编写实现类。使用mapper的动态代理,可以简化冗余代码的编写,也是实际开发中推荐的写法。接下来,我们就一起来看下怎样使用动态代理。

1.在TravelRouteMapper.xml中的mapper标签中使用namespace属性:

代码语言:javascript
复制
<mapper namespace="com.pz.route.dao.TravelRouteDao">

这样编写mybatis mapper文件与具体的接口com.pz.route.dao.TravelRouteDao建立映射关系。

2.编写的Dao必须遵守一个命名规范——方法名和mapper文件的id值保持一一对应的关系。

3.使用sqlSession创建dao的代理对象执行数据库操作:

代码语言:javascript
复制
@Test
       public void testQueryTravelByIdProxy(){
              SqlSession sqlSession=null;
              try{
               sqlSession=MyBatisUtil.getSqlSession();
             
              TravelRouteDaotravelRouteDao=sqlSession.getMapper(TravelRouteDao.class);
             
              TravelRoute travelRoute=travelRouteDao.queryTravelById(515L);
              sqlSession.commit();
              System.out.println(travelRoute);
              }catch(Exception e){
                     e.printStackTrace();
              }finally{
                     if(null!=sqlSession){
                            sqlSession.close();
                     }
              }
             
       }

通过SqlSession对象的getMapper方法,将要获取的dao接口的class属性传入,会返回MyBatis会使用动态代理的方式创建对象,该对象是有jdk的动态代理自动生成的。由于我们的Sqlsession默认的是手动提交的事务方式,所以我们还是需要在程序中commit。不过,将dao的实现类去除掉之后,代码更加简洁。

我们之前编写的updateById方法其实存在一个问题——如果传入的数据是null或者是空字符串,对应的字段也会被设置为null或者是空字符串,其实这样提供方法比较危险,在实际开发的过程中,往往希望只对传入的数据做更新。还有一个场景,我们上网的时候发现页面上有多个组合查询条件,输入某一个查询条件就匹配一项查询结果,输入多个查询条件,就要求查询结果匹配多个查询条件。针对这样的场景,mybatis提供了动态sql技术来减少开发人员的开发工作。

if标签

我们使用if标签来解决数据更新的控制问题——对于一些字段,必须有值传入才做更新:

代码语言:javascript
复制
<update id="updateById">
      update   
      travel_route
       set
       <if test="travelRouteName!= null and travelRouteName != ''"> 
       travel_route_name=#{travelRouteName},
       </if>
        <if test="travelRoutePrice!= null and travelRoutePrice >0 "> 
       travel_route_price=#{travelRoutePrice},
       </if>
        <if test="travelRouteIntroduce!= null and travelRouteIntroduce != ''"> 
      travel_route_introduce=#{travelRouteIntroduce},
       </if>
        <if test="travelRouteFlag!= null "> 
       travel_route_flag=#{travelRouteFlag},
       </if>
       <if test="travelRouteFlag!= null "> 
       travel_route_date=#{travelRouteDate},
       </if>
        <if test="travelRouteFlag!= null "> 
       isThemeTour=#{isThemeTour},
       </if>
        <if test="travelRouteCount!= null and travelRouteCount > 0 "> 
       travel_route_count=#{travelRouteCount},
       </if>
        <if test="travelRouteCid!= null and travelRouteCid > 0 "> 
       travel_route_cid=#{travelRouteCid},
       </if>
        <if test="travelRouteImage!= null and travelRouteImage != ''"> 
       travel_route_image=#{travelRouteImage},
       </if>
        <if test="travelRouteSellerId!= null and travelRouteSellerId >0 "> 
      travel_route_seller_id=#{travelRouteSellerId}
       </if>
      where travel_route_id =#{travelRouteId}
   
   
</update>

运行测试用例,确保代码没有问题!

where标签

我们来实现一个新的功能,实现复合查询:如果输入了线路名称,我们就按线路名称模糊查询,如果输入了价格我们就查询大于输入价格的线路。我们可以通过where标签来实现它。

在mapper中编写sql:

代码语言:javascript
复制
<select id="queryTravelByQuery"resultMap="TravelRouteType" parameterType="TravelRoute">
   
     select
       travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id 
    
      from travel_route
       <where>
          <if test="travelRouteName!= null and travelRouteName != ''"> 
          and travel_route_name like  '%' #{travelRouteName} '%'
         </if>
         <if test="travelRoutePrice!= null and travelRoutePrice>0 "> 
          andtravel_route_price>#{travelRoutePrice}
         </if>
        </where>
   
    </select>
代码语言:javascript
复制
编写方法接口:/**
     * 模糊查询TravelRoute列表
     * @param travelRoute
     * @return
     */
List<TravelRoute>queryTravelByQuery(TravelRoute travelRoute);

由于项目为了展示之前的例子,解决编译问题 实现类实现一个空方法就好,使用动态代理的方式是无需编写实现类的:

代码语言:javascript
复制
@Override
       public List<TravelRoute>queryTravelByQuery(TravelRoute travelRoute) {
              // TODO Auto-generated method stub
              returnnull;
       }
编写测试方法:
@Test
       publicvoid testQueryTravelRouteByQuerydProxy(){
              SqlSession sqlSession=null;
              try{
               sqlSession=MyBatisUtil.getSqlSession();
              TravelRouteDaotravelRouteDao=(TravelRouteDao) sqlSession.getMapper(TravelRouteDao.class);
              TravelRoute travelRoute = new TravelRoute();
              travelRoute.setTravelRouteName("春节");
              travelRoute.setTravelRoutePrice(100d);
              travelRoute.setTravelRouteDate("2019-10-26");
              List<TravelRoute> list=travelRouteDao.queryTravelByQuery(travelRoute);
              System.out.println(list);
              }catch(Exception e){
                     e.printStackTrace();
              }finally{
                     if(null!=sqlSession){
                            sqlSession.close();
                     }
              }
             
       }

运行测试用例,看看效果!

choose标签

我们再提一个小要求,如果用户没有传入travelRouteName也没有传入travelRoutePrice,程序就不返回数据。当然我们可以在程序中做出判断,不过mybatis提供了choose标签也可以实现上述要求。在mapper中编写sql:

代码语言:javascript
复制
  <select id="queryTravelByChooseQuery"resultMap="TravelRouteType" parameterType="TravelRoute">
   
     select
       travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id 
    
      from travel_route
       <where>
         <choose>
          <when test="travelRouteName!= null and travelRouteName != ''"> 
          and travel_route_name like  '%' #{travelRouteName} '%'
         </when>
         <when test="travelRoutePrice!= null and travelRoutePrice >0 "> 
          andtravel_route_price>#{travelRoutePrice}
         </when>
         <otherwise>
              1 >2
          </otherwise>
        </choose>
        
        </where>
   
    </select>

编写dao接口和实现类

代码语言:javascript
复制
/**
     * 模糊查询TravelRoute列表
     * @param travelRoute
     * @return
     */
   List<TravelRoute> queryTravelByChooseQuery(TravelRoutetravelRoute);
编写测试方法
@Test
       publicvoid testQueryTravelRouteByChooseQuerydProxy(){
              SqlSession sqlSession=null;
              try{
               sqlSession=MyBatisUtil.getSqlSession();
              TravelRouteDao travelRouteDao=(TravelRouteDao)sqlSession.getMapper(TravelRouteDao.class);
              TravelRoute travelRoute = new TravelRoute();
              List<TravelRoute> list=travelRouteDao.queryTravelByChooseQuery(travelRoute);
              System.out.println(list);
              }catch(Exception e){
                     e.printStackTrace();
              }finally{
                     if(null!=sqlSession){
                            sqlSession.close();
                     }
              }
             
       }

运行程序,我们发现返回了一个空的list.

choose标签有多个when子标签,但是只能有一个otherwise子标签,有点类似java中的switch语句,我们在子标签中使用了1>2这种错误条件,在sql层面就屏蔽了数据返回的可能性。

foreach标签遍历数组

我们再来完成一个小功能,传入一组id号,批量放回线路数据。我们需要使用到sql语句中的in语句,当然,也可以用拼接字符串的方式实现它,但是mybatis提供了foreach标签,实现了循环拼接的功能。

foreach标签的属性

§ collection 表示要遍历的集合类型,可以传入List和数组。

§ open、close、separator 用于 SQL 拼接,open表示由什么字符开始,colse表示由什么字符结束,separator表示拼接字符串的分隔符。

我们来编写一个例子使用下foreach标签,在mapper文件中编写下面内容:

代码语言:javascript
复制
<select id="queryTravelByForEach"resultMap="TravelRouteType" >
   
     select
       travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id 
    
      from travel_route
       <where>
         <choose>
       <when test="list != nulland list.size>0">
        travel_route_id IN
        <foreach collection="list"open="(" close=")"item="id" separator=",">
            #{id}
        </foreach>
        </when>
          <otherwise>
              1 >2
          </otherwise>
        </choose>
       </where>
       
    </select>
   

编写dao接口方法和接口实现:

代码语言:javascript
复制
 /**
     * 根据travelRouteIdList返回列表
     * @param travelRouteIdList
     * @return
     */
   List<TravelRoute> queryTravelByForEach(List<Long>travelRouteIdList);
编写测试方法:
@Test
       publicvoid testQueryTravelRouteByForEachProxy(){
              List<Long> idList= Arrays.asList(1L,2L,3L);
              SqlSession sqlSession=null;
              try{
               sqlSession=MyBatisUtil.getSqlSession();
              TravelRouteDaotravelRouteDao=(TravelRouteDao) sqlSession.getMapper(TravelRouteDao.class);
              TravelRoute travelRoute = new TravelRoute();
              List<TravelRoute> list=travelRouteDao.queryTravelByForEach(idList);
              System.out.println(list);
              }catch(Exception e){
                     e.printStackTrace();
              }finally{
                     if(null!=sqlSession){
                            sqlSession.close();
                     }
              }
             
       }
 

sql标签

我们发现编写select语句时需要每次都写很多字段名,每写一条语句就需要写一次,这样很累,当然你要是不怕dba地狱的怒吼和你的Leader的天堂的神罚的话,可以写select * 来解决。Mybatis提供sql标签来解决sql的复用问题,使用sql标签可以把公共的sql语句片段提取出来,在需要使用的时候写上include标签就可以引入公用的sql语句片段了。我们将公共的查询字段使用sql标签提取出来:

代码语言:javascript
复制
  <sql id = "commonselect">
   
     travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id 
   
   </sql>

为了验证一下,我们修改下之前的queryTravelByForEach语句

代码语言:javascript
复制
<select id="queryTravelByForEach"resultMap="TravelRouteType" >
   
     select
        <include refid="commonselect"/>
    
      from travel_route
       <where>
         <choose>
       <when test="list != nulland list.size>0">
        travel_route_id IN
        <foreach collection="list"open="(" close=")"item="id" separator=",">
            #{id}
        </foreach>
        </when>
          <otherwise>
              1 >2
          </otherwise>
        </choose>
       </where>
       
</select>

运行下测试用例,看看效果

注意噢,由于mybatis使用的时xml,在xml中有些符号,是不能直接使用的,遇到这种情况,我们可以使用实体符号代替。下面就是一些数学符号和实体符号之间的关系。

原符号 实体符号

< &lt;

<= &lt;=

> &gt;

>= &gt;=

& &amp;

" &quot;

' &apos;

这里要强调一下<,>=,<=,&,一定不能直接在xml中出现。

我们修改下queryTravelByQuery的程序要求,要求返回大于等于输入价格的线路,示例:

代码语言:javascript
复制
<select id="queryTravelByQuery"resultMap="TravelRouteType" parameterType="TravelRoute">
   
     select
       travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id 
    
      from travel_route
       <where>
          <if test="travelRouteName!= null and travelRouteName != ''"> 
          and travel_route_name like  '%' #{travelRouteName} '%'
         </if>
         <if test="travelRoutePrice!= null and travelRoutePrice >0 "> 
          and travel_route_price&gt;=#{travelRoutePrice}
         </if>
        </where>
   
    </select>

除了使用特殊符号之外,我们还可以将特殊符号放到<![CDATA[ ]]>里面,这里面的内容xml是不会转义的。

代码语言:javascript
复制
<select id="queryTravelByQuery"resultMap="TravelRouteType" parameterType="TravelRoute">
   
     select
       travel_route_id ,
       travel_route_name ,
       travel_route_price ,
       travel_route_introduce ,
       travel_route_flag ,
       travel_route_date ,
       isThemeTour ,
       travel_route_count,
       travel_route_cid ,
       travel_route_image ,
       travel_route_seller_id 
    
      from travel_route
       <where>
          <if test="travelRouteName!= null and travelRouteName != ''"> 
          and travel_route_name like  '%' #{travelRouteName} '%'
         </if>
         <if test="travelRoutePrice!= null and travelRoutePrice >0 "> 
          and <![CDATA[travel_route_price >= #{travelRoutePrice}]]>
         </if>
        </where>
    
    </select>
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 猿人工厂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档