mybatis基本操作之SQL映射

Mybatis之所以强大就是因为SQL映射语句。SQL映射文件的配置也很简单。来公司快两个月了,公司采用springboot +mybatis框架进行开发,将近期使用mybatis的心得做一个全面的总结:结构图如下:
在这里插入图片描述
今天的总结由四部分组成。介绍之前我们先介绍一下mapper文件的标签有哪些,分别都有什么作用;

  • mapper :映射文件的根元素,只有一个属性namespace(命名空间),主要作用有区分不同的mapper文件,全局唯一。绑定dao层接口,即面向接口编程。当namespace绑定某一接口后,可以不用写接口的实现类,mybatis会通过接口的完整限定名查找到与之对应的mapper配置文件来执行对应的SQL语句。因此,namespace命名必须与接口同名。
  • cache :配置给定命名空间的缓存。
  • cache-ref:从其他命名空间引用缓存。
  • resultMap:用来描述数据库结果集和实体类属性的对应关系。
  • sql:可以重用的sql块,也可以被其他语句引用。
  • insert :映射插入语句。
  • update:映射更新语句。
  • delete:映射删除语句。
  • select:映射查询语句。
    好,上干货的时间到了。接下来我们运用一下这些标签。看看这些标签分别都在什么位置。
    备注:本项目是采用springboot框架来搭建的。首先应该在springboot中配置与数据库连接的驱动文件。保证基本环境没有问题即可(也可以在mybatis核心配置文件中配置与数据库连接的驱动)。
  • 单条件查询
    条件查询首先我们搞清楚。通俗点说就是SQL语句的Where后面加条件,那单条件查询就是Where语句后面只能有一个条件。例如,我们查询今日新增的订单数量。
<!--  查询今日新增订单数量 -->
    <select id="getTodayAddOrderNum" resultMap="todayOrderNum">
        select count(*) as orderNum
        from client_business_info
        where date = curdate()
    </select>
    

可以看到where后面的条件是等于curdate(),这里解释一下,curdate()是Mysql提供的一个内置函数。返回结果是当天的日期。当然,这里我将他的返回结果做了一个resultMap封装。如下:

<resultMap id="todayOrderNum" type="com.em.bigdata.vo.BusinessEnd">
      <result property="toDayOrderNum" column="orderNum"></result>
</resultMap>

这里用到了前面介绍的关键字,resultMap和resultType。后面会直接将sql语句查询的结果自动与相对应的实体类进行映射。但前提条件是实体类中的属性名必须与数据库中的字段名一致才可以映射成功。要是不一致的话,需要用到resultMap来手动做映射。id就是唯一的,与查询结果中的resultMap的值绑定即可。type就是我们需要映射到那个实体类,result就是做映射结果处理。其中,property是代表实体类中的属性,column是数据库查询结果的字段名。

  • 多条件查询
    多条件查询顾名思义就是where后面有多个条件。
    例如,查询用户名以张开头并且性别为男的用户。很明显,分析这个要求,以张开头,肯定是一个模糊查询,这是第一个条件,性别为男,这是第二个条件。
    接口代码如下:
List<User> getUserList(String userName,String sex);

mapper文件对应的sql语句

 <select id="getUserList" resultType="com.em.demo.User" parameterType="java.lang.String">
        select 
        	* 
        from
        	 _user
        where 
        	username like concat('%',#{param1},'%')
        and
       		sex = #{param2}
    </select>

其实,一情况下,多参数都会封装成一个对象来进行传递。改造一下:
接口如下:

List<User> getUserList(User user);

mapper文件如下:

 <select id="getUserList" resultType="com.em.demo.User" parameterType="com.em.demo.User">
        select 
        	* 
        from
        	 _user
        where 
        	username like concat('%',#{userName},'%')
        and
       		sex = #{sex}
 </select>

可以看到,改动了好多处的地方,第一,接口的入参不在是简单的数据类型,而是一个User对象类型;第二,参数类型(parameterType,指定入参的数据类型,当有多个条件且数据类型不一致时可以忽略不写)也变成复杂数据类型user了;第三,查询条件后面的值不在时原来的#{param1}和#{param2}了,现在是#{userName}和#{sex}了。即#{属性名}(参数对象中的属性名)。
当然,一个sql语句的查询条件可能有十几个,我们不可能针对每一个sql语句的查询条件都封装成一个对象,所以,mybatis提供了一个更灵活的方式,就是封装成Map对象即可。
接口如下:

List<User> getUserList(Map<String,String> userMap);

mapper文件如下:

 <select id="getUserList" resultType="com.em.demo.User" parameterType="java.util.Map">
        select 
        	* 
        from
        	 _user
        where 
        	username like concat('%',#{uName},'%')
        and
       		sex = #{uSex}
 </select>

测试代码:
Map<String,String> map = new HashMap<String,String>();
map.put(“uName”,“张”);
map.put(“uSex”,“女”);
然后在调用这个接口,传入我们封装好的Map就ok了。

其实,通过Map传递参数,在sql语句中只需要按照map的key即可获取到对应的值。Mybatis传入参数类型可以是Java的基础数据类型,但是只适用于一个参数的情况,通过#{参数名}即可获取传入的值。惹是多参数入参,则需要复杂数据类型来支持,包括Java实体类,Map,通过#{属性名}或#{Map的Key}来获取传入的参数值。

  • 自定义查询结果
    这个一般是在多表查询过程中才能用到。例如,用户表中包含用户的基本信息之外还有选课表的id,但是我现在要知道用户具体选了哪一门课的课程名称,而不是课程id.这就需要用户表和课程表联合查询。但是在显示的时候应该显示选课名称而不是选课的id,应该如何解决?
    一般有两种解决方案:
    第一:修改实体类,增加课程名称这个属性,完成相应的sql语句,对用户表和选课表进行联合查询,使用resultType自动映射。
    第二:通过resultMap映射自定义结果,一般推荐使用这种方案。即使用resultMap做自定义结果映射,字段名可以不一致,并且可以指定要显示的列,比较灵活。

备注: 前面简单介绍过resultType和resultMap的区别,这里就详细的说一下:
resultType: 直接表示返回类型,包括基础数据类型和复杂数据类型
resultMap: 是对外部resultMap定义的引用,对应外部resultMap的id,表示返回结果映射到哪一个resultMap上,
两者的关联: 在mybatis进行查询的时候,查询出来的每个字段值都放在一个对应的Map里面,其中键是字段名,值则是对应的值。当select元素提供的返回类型属性是resultType的时候,Mybatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性(即调用对用的对象里面的setter方法进行复制)。正因为如此,当使用resultType的时候,直接在后台就能接收到其对象相应的属性值。由此可以看出,其实mybatis每个查询映射的返回值类型都是resultMap,只是当我们提供的返回值类型的属性是resultType的时候,mybatis会自动把对应的值赋给resultType所指定对象的属性,而当我们提供的返回数据类型属性是resultMap的时候,因为Map不能很好的表示领域模型,就需要通过进一步的定义把它转化为对应的实体类型。

mybatis的自动映射级别:
NONE: 禁止自动匹配
PARTIAL: 默认,自动匹配属性。
FULL: 自动匹配所有属性
在mybatis中,使用resultMap能够自动进行映射匹配的前提是字段名和属性名必须一致,在默认映射级别PARTIAL情况下,字段名和属性名一致,即使没有做属性名和字段名的匹配,也可以在后台获取到未匹配的属性值 。若字段名和属性名不一致,且在resultMap中没有做映射,那么就无法在后台获取到。

- 增加操作
增加操作使用insert标签。
mapper接口定义:

int addUser(User user);

sql语句如下:

<insert id="addUser" parameterType="com.em.bigdata.User" >
        insert into 
            _user(username,password,sex,age)
        values (
            #{userName},
            #{passWord},
            #{sex},
            #{age}
        )
    </insert>

删除和修改就不做演示了,跟插入都差不多,唯一不同的是就是修改使用update标签,删除使用delete标签。
需要注意的是,对于增删改这类操作的时候,哟啊注意两点:
第一:该类型的操作本身默认返回执行sql语句影响的行数,所以DAO层的接口方法的返回值一般设置为int型,最好不要返回成boolean型。
第二:insert,update,delete元素中均没有resultType属性,只有查询操作需要对返回结果的类型(resultType/resultMap)进行相应的设定。

  • 多参数入参
    之前我们说过,mybatis传入参数如果时Java的基础数据类型的话,只适用于一个 参数的情况,通过#{参数名}可以获取传入的值。但是有多个参数的情况下,就获取不到了。之前采用的方案就是封装参数,将参数封装成Map对象或者一个实体对象。可通过#{map的key}或者#{对象的属性}获取到传入的值。可问题来了,有时候我们为了提高的代码的可读性,可以清晰的看出这个接口方法所需要的参数是什么,我们就不能进行封装,那怎么办嘞?mybatis提供了一个注解,叫做@Param,使用他可以传入多个参数。具体代码如下:
List<User> getUserList(@Param("name")String userName,@Param("sex")String sex);

mapper文件

 <select id="getUserList" resultType="com.em.demo.User" parameterType="java.lang.String">
        select 
        	* 
        from
        	 _user
        where 
        	username like concat('%',#{name},'%')
        and
       		sex = #{sex}
    </select>

**总结:**了解过mybatis源码的都知道,mybatis的参数类型为Map,如果使用@Param注解参数,那么就会记录指定的参数名为key,如果参数前没有加@Param,那么就会使用"Param"+参数的序号作为Map的key,所以,在进行多参数入参时,既可以通过@Param注解来指定key,也可以使用默认的方法来获取,但是,一般建议采用注解的方式类获取。避免未知的错误发生。

  • 高级映射结果
    什么时候要用到高级映射结果那?就是Java的实体类中嵌套了另一个实体类,这个时候就需要高级映射了。如果嵌套的实体类是一个List的形式的,那就是对应的一对多关联。说直白点无非就是在resultMap处理sql语句返回的结果,这种结果一般分为两种情况,一对一的关系和一对多的关系。

  • 使用association处理一对一的关联关系
    接口代码如下:

/***
     * 品牌销售排行
     * @param count
     * @return
     */
    List<BusinessEnd> brandSaleOrder(Integer count);

mapper文件如下:

 <!--   品牌销售排行  -->
    <select id="brandSaleOrder" resultMap="businessResultMap" parameterType="java.lang.Integer">
        select agent,sum(sign_price) as sign_price
        from client_business_info
        where agent != ''
        and agent is not null
        group by agent
        having sign_price > 0
        ORDER BY sign_price DESC
        LIMIT #{0}
    </select>

高级映射文件如下:

<resultMap id="businessResultMap" type="com.em.bigdata.vo.BusinessEnd">
        <association property="platformBusiness" javaType="com.em.bigdata.pojo.Business">
            <id property="id" column="ID"></id>
            <result property="date" column="date"/>
            <result property="proNo" column="pro_no"/>
            <result property="companyName" column="company_name"/>
            <result property="goodsName" column="goods_name"/>
            <result property="goodsNum" column="goods_num"/>
            <result property="customerAddr" column="customer_addr"/>
            <result property="typeGoods" column="type_goods"/>
            <result property="productType" column="product_type"/>
            <result property="agent" column="agent"/>
            <result property="suppName" column="supp_name"/>
            <result property="signPrice" column="sign_price"/>
            <result property="signTotal" column="sign_total"/>
        </association>
    </resultMap>

实体类代码如下:

package com.em.bigdata.vo;

import com.em.bigdata.pojo.Business;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serializable;
import java.math.BigDecimal;

/**
 * 交易大屏端
 * @author fafatuo
 * @version 1.0
 * @date 2020/8/20 9:50
 */
@ApiModel
public class BusinessEnd implements Serializable {

    @ApiModelProperty(value = "平台交易数据")
    private Business platformBusiness;

    //今日新增订单数量
    @ApiModelProperty(value = "今日新增订单数量")
    private Integer toDayOrderNum;

    //今日新增订单金额
    @ApiModelProperty(value = "今日新增交易金额")
    private BigDecimal toDayOrderMoney;

    //累计交易额
    @ApiModelProperty(value = "累计交易额")
    private BigDecimal cumulativeTransactionAmount;

    public Business getPlatformBusiness() {
        return platformBusiness;
    }

    public void setPlatformBusiness(Business platformBusiness) {
        this.platformBusiness = platformBusiness;
    }

    public Integer getToDayOrderNum() {
        return toDayOrderNum;
    }

    public void setToDayOrderNum(Integer toDayOrderNum) {
        this.toDayOrderNum = toDayOrderNum;
    }

    public BigDecimal getToDayOrderMoney() {
        return toDayOrderMoney;
    }

    public void setToDayOrderMoney(BigDecimal toDayOrderMoney) {
        this.toDayOrderMoney = toDayOrderMoney;
    }

    public BigDecimal getCumulativeTransactionAmount() {
        return cumulativeTransactionAmount;
    }

    public void setCumulativeTransactionAmount(BigDecimal cumulativeTransactionAmount) {
        this.cumulativeTransactionAmount = cumulativeTransactionAmount;
    }
}

这里就不细说了,对照代码应该可以看懂。

测试结果:
在这里插入图片描述

  • 使用Collection处理一对多关联关系
    前面已经说过了,Collection用户处理一对多的关系。一般实体类中定义了如
    private List uList,这样的嵌套子类时,这个返回结果肯定就是一对多的关系。我们需要用到该关键字去做高级映射。其实跟一对一映射没多大区别。就是标签使用Collection,propety就是对应实体类中的属性,这里就是uList,一对一中采用javaType,而一对多中用ofType,后面跟我们要映射的完全限定类名(如果起了别名,就写别名)。基本就这些。由于我项目中没有用到这个,就先不演示了。

Mybatis的基础查询基本就总结这些。不懂的可V信我:tff1280298759

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值