mybatis简单了解

一、什么是mybatis?为什么要使用mybatis?

mybatis是一个orm(Object Relational Mapping)框架。相对Hibernate和ApacheOJB等“一站式”ORM解决方案而言,Mybatis是一种“半自动化”的ORM实现。具有轻量、灵活、学习型强等优点。
点击了解更多内容

二、mybatis在项目中的存在

  1. dao层文件夹中分别存放了mapper.java和mapper.xml
  2. mapper.xml是对mapper.java接口的实现。他们之间是通过<mapper>标签的nameSpace属性实现绑定的。
    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.sjl.station.dao.ITicketDao">
    
  3. 检验是否绑定成功:如果按住ctrl键点击namespace中的值,可以直接跳转到对应的接口,则表示绑定成功。
  4. mybatis框架独立运行时,需要手动控制事物,进行打开、提交、回滚、关闭操作。若集成了Spring框架,则可以将其托管到Spring中自动管理。
    SqlSession session= MyBatisSessionFactory.getSession(); //获取数据库连接  
    session.commit(); //提交  
    session.rollback(); //回滚  
    session.close(); //关闭连接 
    

三、mybaits接口方法和接口方法的实现

  1. mapper.xml 是 mapper.java 的实现,两者通过 <statementSql></statementSql> 的 id属性来关联 【statementSql 泛指xml文件中的sql执行语句片段】

    mapper.java

    package com.sjl.station.dao;
    import com.sjl.station.model.Ticket;
    import com.sjl.station.query.QueryTicketObj;
    
    public interface ITicketDao {
    void updateTicket(Ticket ticket);
    }
    

    mapper.xml

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.sjl.station.dao.ITicketDao">
    <update id="updateTicket" parameterType="com.sjl.station.model.Ticket">
        UPDATE ticket SET surplus_vote=#{surplusVote} WHERE id=#{id}
    </update>
    

    可以看到\<update id = "update"> 中 id 的值 就是 mapper.java 中的方法名

四、接口方法和接口实现中 出入参 类型的定义

  1. 接口实现中可用的类型:java中的普通类型 和 自定义的pojo类型

  2. 定义入参的的属性:在 parameterType = " " 属性中定义
    【注意:入参是可选属性,根据需求设定】

    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >    
    select   
    <include refid="Base_Column_List" />  
    from product  
    where product_id = #{productId,jdbcType=VARCHAR}  
    </select>  
    
  3. 定义出参的属性:出参定义的是mapper.xml中的重点
    对于增删改语句,返回值是可选参数,如果要求有返回值,则他们的返回值默认为 int 型,这是由mybatis的底层定义的
    如:mapper.xml

    <delete id="deleteByPrimaryKey" parameterType="java.lang.String" >  
    delete from product  
    where product_id = #{productId,jdbcType=VARCHAR}  
    </delete>  
    
    <insert id="insert" parameterType="pojo.Product" >  
    insert into product (product_id, product_factroy, product_store,   
      product_descript)  
    values (#{productId,jdbcType=VARCHAR}, #{productFactroy,jdbcType=VARCHAR}, #{productStore,jdbcType=INTEGER},   
      #{productDescript,jdbcType=VARCHAR})  
    </insert>  
    
    <update id="updateByPrimaryKey" parameterType="pojo.Product" >  
    update product  
    set product_factroy = #{productFactroy,jdbcType=VARCHAR},  
      product_store = #{productStore,jdbcType=INTEGER},  
      product_descript = #{productDescript,jdbcType=VARCHAR}  
    where product_id = #{productId,jdbcType=VARCHAR}  
    </update>  
    

    mapper.java

    int deleteByPrimaryKey(String productId);  
    int insert(Product product);  
    int updateByPrimaryKey(Product product);  
    

    而对于查询语句<select> 而言,返回值是查询语句得到每一条结果的映射。
    查询结果的数据类型,决定了出参的类型,查询结果的条目数,决定了是否采用集合或者数组。换言之:如果返回单个值,外部用单值的方式接收;如果是多个值,就需要用List<?> 来接收。

    mapper.java

    //通过主键查询结果,只可能是一个对象,所以直接用自定义对象接收  
    Product selectByPrimaryKey(String productId);     
    
    //通过条件进行查询的结果,可能是返回多个对象,因此需要用List<Product> 来接收  
    List<Product> selectProByConditions(Product product);  
    

    mapper.xml 【在xml中的返回值类型为pojo.Product ,返回值的条目数决定了外部接收的单个值类型还是多个值类型】

    <select id="selectByPrimaryKey" resultMap="pojo.Product" parameterType="java.lang.String" >    
        select   
        <include refid="Base_Column_List" />  
        from product  
        where product_id = #{productId,jdbcType=VARCHAR}  
    </select>  
    
    <select id="selectProByConditions" parameterType="java.lang.String" resultMap="pojo.Product">  
        select product_name productName,sale_price as salePrice from product  
        <where>  
            <if test="productId!=null and productId!=''">  
                and product_id = #{productId}  
            </if>  
            <if test="productFactroy!=null and productFactroy!='' ">  
                and product_factroy = #{productFactroy}  
            </if>  
            <if test="productStore!=null">  
                and product_store = #{productStore}  
            </if>  
            <if test="productDescript!=null">  
                and product_descript = #{productDescript}  
            </if>  
        </where>   
    </select> 
    

    管理结果映射的标签有两种,分别是resultType和 resultMap 。通过这两个标签建立数据库查询结果的列和程序中实体类或java类型的映射关系

    resultType 和 resultMap 之间的关系和区别,一直是mybatis开发者关心的问题。但其实通过几个小的练习,就可以将两者的关系和使用场景搞明白了。

    resultType:是属性,可以管理普通返回值类型,也可以返回自定义的pojo包装类。
    如:

    <sql id="cusAndOrder">  
            c.*,  
            o.order_id as orderId,  
            o.create_date as createDate  
        </sql>  
        
        <select id="findCusAndOrderByCid"  resultType="pojo.CustomerAndOrder">  
            select  
            <include refid="cusAndOrder"/>  
            from  
            customer c,ordertable o  
            WHERE  
            c.cid = o.cid  
        </select>  
    

    其中pojo.CustomerAndOrder是笔者自定义的类型,继承Customer 类,并加入了几条Order的属性【注意:在声明自定义类时,一定要生成getter、setter、还有两构造方法 】

    有了构造方法,对象才能被初始化,查询结果才能被映射到对应字段

    package pojo;  
    
    import java.math.BigDecimal;  
    import java.util.Date;  
    
    public class CustomerAndOrder extends Customer {  
        
        private String orderId;  
        
        private Date createDate;  
    
        public String getOrderId() {  
            return orderId;  
        }  
    
        public void setOrderId(String orderId) {  
            this.orderId = orderId;  
        }  
    
        public Date getCreateDate() {  
            return createDate;  
        }  
    
        public void setCreateDate(Date createDate) {  
            this.createDate = createDate;  
        }  
    
        public CustomerAndOrder(String cid, String cname, String address,  
                String clevel, String email, BigDecimal balance, String orderId,  
                Date createDate) {  
            super(cid, cname, address, clevel, email, balance);  
            this.orderId = orderId;  
            this.createDate = createDate;  
        }  
    
        public CustomerAndOrder() {  
            super();  
            // TODO Auto-generated constructor stub  
        }  
    
        public CustomerAndOrder(String cid, String cname, String address,  
                String clevel, String email, BigDecimal balance) {  
            super(cid, cname, address, clevel, email, balance);  
            // TODO Auto-generated constructor stub  
        }  
    
    }  
    

    操作技巧:通过resultType定义返回值的时候,一定要注意查询结果的列名和属性名要一致才能被映射到。如果列名和字段名不一致,可以通过对字段名起别名(空格或者as),将值映射到自定义的属性中

    从上方的两段代码中可以发现<sql>片段中将order_id 起别名为 orderId 的目的就是为了映射关联

    resultMap:是属性,也是标签;它可以定义返回值类型,也可以作为映射管理器标签独立存在

    <resultMap id="BaseResultMap" type="pojo.OrderTable" >  
    <id column="order_id" property="orderId" jdbcType="VARCHAR" />  
    <result column="cid" property="cid" jdbcType="VARCHAR" />  
    <result column="address" property="address" jdbcType="VARCHAR" />  
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />  
    <result column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />  
        <!--维护一对多的关系  -->  
        <collection property="orderitemList" ofType="pojo.Orderitem">  
            <id column="orderitem_id" property="orderitemId"/>  
            <result column="product_id" property="productId"/>  
            <result column="count" property="count"/>  
        </collection>   
    </resultMap>  
    
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >  
    <!--  
        WARNING - @mbggenerated  
        This element is automatically generated by MyBatis Generator, do not modify.  
        This element was generated on Fri May 06 15:49:42 CST 2016.  
    -->  
    select   
    <include refid="Base_Column_List" />  
    from ordertable  
    where ordertable.order_id = #{orderId,jdbcType=VARCHAR}  
    </select>  
    

    从上面的代码块中可以发现:resultMap 作为映射管理器标签独立使用 ,其中id属性的值作为映射管理器的标识码,可以被statementSql引用
    而映射管理器的作用在于可以用来维护实体类之间的关系,如代码片段中所示:resultMap中通过<collection>标签维护了一个一对多的关系,在pojo.OrderTable中有一个以List存在的Orderitem 类,和OrderTable是一对多的关系。

五、SQL语句标签

<!--查询语句-->  
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >  
    select   
  </select>  
  
<!--插入语句-->  
<insert id="insert" parameterType="pojo.OrderTable" useGeneratedKeys="true" keyProperty="id">  
 insert into ordertable (order_id, cid, address, create_date, orderitem_id)  
    values (#{orderId,jdbcType=VARCHAR}, #{cid,jdbcType=VARCHAR}, #{address,jdbcType=VARCHAR},   
      #{createDate,jdbcType=TIMESTAMP}, #{orderitemId,jdbcType=VARCHAR})  
</insert>  
  
<!--删除语句-->  
<delete id="deleteByPrimaryKey" parameterType="java.lang.String" >  
delete from ordertable  
    where order_id = #{orderId,jdbcType=VARCHAR}  
</delete>  
  
<!--修改语句-->  
 <update id="updateByPrimaryKey" parameterType="pojo.OrderTable" >  
  update ordertable  
    set cid = #{cid,jdbcType=VARCHAR},  
      address = #{address,jdbcType=VARCHAR},  
      create_date = #{createDate,jdbcType=TIMESTAMP},  
      orderitem_id = #{orderitemId,jdbcType=VARCHAR}  
    where order_id = #{orderId,jdbcType=VARCHAR}  
  </update>  

需要配置的属性:
id="xxxx" >>> 表示此段sql执行语句的唯一标识,也是接口的方法名称【必须一致才能找到】
parameterType="" >>>表示该sql语句中需要传入的参数, 类型要与对应的接口方法的类型一致【可选】
resultMap=“ ”>>> 定义出参,调用已定义的<resultMap>映射管理器的id值
resultType=“ ”>>>定义出参,匹配普通java类型或自定义的pojo【出参类型若不指定,将为语句类型默认类型,如<insert>语句返回值为int】

useGeneratedKeys(仅对insert和update有用)这会令MyBatis使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(比如:像MySQL和SQL Server这样的关系数据库管理系统的自动递增字段),默认值:false。

keyProperty (仅对insert和update有用)唯一标记一个属性,MyBatis会通过getGeneratedKeys的返回值或者通过insert语句的selectKey子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。【keyProperty是Java对象的属性名,而不是表格的字段名】

至于为何<insert><delete><update> 语句的返回值类型为什么是int,有过JDBC操作经验的朋友可能会有印象,增删改操作实际上返回的是操作的条数。而Mybatis框架本身是基于JDBC的,所以此处也沿袭这种返回值类型。

传参和取值:mapper.xml 的灵活性还体现在SQL执行语句可以传参,参数类型通过parameterType= “” 定义

取值方式1:#{value jdbcType = valuetype}:jdbcType 表示该属性的数据类型在数据库中对应的类型,如 #{user jdbcType=varchar} 等价于 String username;

取值方式2:\$ {value } : 这种方式不建议大量使用,可能会发送sql注入而导致安全性问题。一般该取值方式可用在非经常变化的值上,如orderby \$ {columnName};

六、SQL片段标签

<sql>通过该标签可定义能复用的sql语句片段,在执行sql语句标签中直接引用即可。这样既可以提高编码效率,还能有效简化代码,提高可读性

需要配置的属性:id="" >>>表示需要改sql语句片段的唯一标识

引用:通过<include refid="" />标签引用,refid="" 中的值指向需要引用的<sql>中的id=“”属性

<!--定义sql片段-->  
<sql id="orderAndItem">  
    o.order_id,o.cid,o.address,o.create_date,o.orderitem_id,i.orderitem_id,i.product_id,i.count  
  </sql>  
  
 <select id="findOrderAndItemsByOid" parameterType="java.lang.String" resultMap="BaseResultMap">  
    select  
<!--引用sql片段-->  
    <include refid="orderAndItem" />  
    from ordertable o  
    join orderitem i on o.orderitem_id = i.orderitem_id  
    where o.order_id = #{orderId}  
  </select>  

七、映射管理器resultMap

映射管理器,是Mybatis中最强大的工具,使用其可以进行实体类之间的关系,并管理结果和实体类间的映射关系
需要配置的属性:<resultMap id=" " type=" ">
</resutlMap> id=" ">>>表示这个映射管理器的唯一标识,外部通过该值引用; type = " ">>> 表示需要映射的实体类;

需要配置的参数:
<id column = " " property= " " />
<id>标签指的是:结果集中结果唯一的列【column】 和 实体属性【property】的映射关系,注意:<id>标签管理的列未必是主键列,需要根据具体需求指定;

<result column= " " property=" " />
<result>标签指的是:结果集中普通列【column】 和 实体属性【property】的映射关系;

需要维护的关系:所谓关系维护是值在主表查询时将其关联子表的结果也查询出来

  1. 一对一关系<assocation property = " " javaType=" "> property = “ ” 被维护实体在宿主实体中的属性名,javaType = " " 被维护实体的类型

    Orderitem.java

    package pojo;  
    
    public class Orderitem {  
        
        private String orderitemId;  
    
        private String productId;  
    
        private Integer count;  
        
        private Product product;     
    

    从上方代码段可以看出:Product 对象在 Orderitem 实体中以 product 属性存在

    Orderitemmapper.xml

    <resultMap id="BaseResultMap" type="pojo.Orderitem" >  
    <id column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />  
    <result column="product_id" property="productId" jdbcType="VARCHAR" />  
    <result column="count" property="count" jdbcType="INTEGER" />  
    <!-- 通过association 维护 一对一关系 -->  
    <association property="product" javaType="pojo.Product">  
        <id column="product_id" property="productId"/>  
        <result column="product_factroy" property="productFactroy"/>  
        <result column="product_store" property="productStore"/>  
        <result column="product_descript" property="productDescript"/>  
    </association>  
    </resultMap>  
    

    通过xml的配置可以看出,在resultMap映射管理器中,通过<association> 进行了维护,也就是在查询Orderitem对象时,可以把关联的Product对象的信息也查询出来

  2. 一对多关系的维护<collection property=" " ofType=" "> property = “ ” 被维护实体在宿主实体中的属性名 ,ofType=“ ”是被维护方在宿主类中集合泛型限定类型

    【由于在一对多关系中,多的一放是以List形式存在,因此ofType的值取用Lsit<?> 的泛型对象类型】

    OrderTable.java

    public class OrderTable {  
    
        private String orderId;  
    
        private String cid;  
    
        private String address;  
    
        private Date createDate;  
    
        private String orderitemId;  
        
        private List<Orderitem> orderitemList ;
    }
    

    OrderTableMapper.xml

    <resultMap id="BaseResultMap" type="pojo.OrderTable" >  
    <!--  
        WARNING - @mbggenerated  
        This element is automatically generated by MyBatis Generator, do not modify.  
        This element was generated on Fri May 06 15:49:42 CST 2016.  
    -->  
    <id column="order_id" property="orderId" jdbcType="VARCHAR" />  
    <result column="cid" property="cid" jdbcType="VARCHAR" />  
    <result column="address" property="address" jdbcType="VARCHAR" />  
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />  
    <result column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />  
        <!--维护一对多的关系  -->  
        <collection property="orderitemList" ofType="pojo.Orderitem">  
            <id column="orderitem_id" property="orderitemId"/>  
            <result column="product_id" property="productId"/>  
            <result column="count" property="count"/>  
        </collection>   
    </resultMap>  
    
  3. 在resultMap 中需要注意两点:

    • 关联关系的维护可以根据实体类之间的实际情况进行嵌套维护
    <resultMap id="BaseResultMap" type="pojo.OrderTable" >  
    <id column="order_id" property="orderId" jdbcType="VARCHAR" />  
    <result column="cid" property="cid" jdbcType="VARCHAR" />  
    <result column="address" property="address" jdbcType="VARCHAR" />  
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />  
    <result column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />  
         <!--维护一对多的关系  -->  
        <collection property="orderitemList" ofType="pojo.Orderitem">  
            <id column="orderitem_id" property="orderitemId"/>  
            <result column="product_id" property="productId"/>  
            <result column="count" property="count"/>  
            <!--嵌套一对一关系-->  
            <association property="customer" javaType="pojo.Customer">  
                <id column="cid" property="cid"/>  
                <result column="cname" property="cname"/>  
            </association>  
        </collection>   
    </resultMap>  
    
    • 关于出现重复列名的处理:在实际操作过程中,查询到的结果可能会出现相同的列名,这样会对映射到实体属性带来影响甚至出现报错,那么对待这个问题可以通过对列取别名的方式处理
  4. 常用的动态语句标签:通过动态sql标签可以进行条件判断,条件遍历等操作从而满足结果的需要

    <where> : 使用其可以代替sql语句中的where关键字,一般防止在条件查询的最外层

    <if >:条件判断标签,配置属性test=" 条件字符串 ",判断是否满足条件,满足则执行,不满足则跳过

    <select id="findOrderItemDetail" parameterType="pojo.Orderitem" resultMap="BaseResultMap">  
            select orderitem.orderitem_id,product.*   
            from orderitem,product  
            <where>  
                <if test="orderitemId!=null and orderitemId!=''">  
                    and orderitem.orderitem_id = #{orderitemId}  
                </if>  
                <if test="productId!=null and productId!=''">  
                    and orderitem.product_id = #{productId}  
                </if>  
                <if test="count!=null">  
                    and orderitem.count = #{count}  
                </if>  
            </where>  
    </select>  
    

    <set>:常用于<update>更新语句中,替代 sql中的“set”关键字,特别是在联合<if>进行判断时,可以有效方式当某个参数为空或者不合法是错误的更新到数据库中

    <update id="updateByPrimaryKeySelective" parameterType="pojo.Orderitem" >  
    update orderitem  
    <set >  
        <if test="productId != null" >  
        product_id = #{productId,jdbcType=VARCHAR},  
        </if>  
        <if test="count != null" >  
        count = #{count,jdbcType=INTEGER},  
        </if>  
    </set>  
    where orderitem_id = #{orderitemId,jdbcType=VARCHAR}  
    </update>  
    

    <choose><when></when><otherwise></otherwise></choose> 标签组:也是一个用于条件判断的标签组,和<if>的不同之处在于条件从<choose>进入,去匹配<when>中的添加,一旦匹配马上结束;若到找不到匹配项,将执行<other>中的语句;可以理解为<if>是 && 关系 <choose>是 || 关系

    <!-- 查询学生list,like姓名、或=性别、或=生日、或=班级,使用choose -->       
    <select id="getStudentListChooseEntity" parameterType="StudentEntity" resultMap="studentResultMap">       
        SELECT * from STUDENT_TBL ST        
        <where>       
            <choose>       
                <when test="studentName!=null and studentName!='' ">       
                        ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%')        
                </when>       
                <when test="studentSex!= null and studentSex!= '' ">       
                        AND ST.STUDENT_SEX = #{studentSex}        
                </when>       
                <when test="studentBirthday!=null">       
                    AND ST.STUDENT_BIRTHDAY = #{studentBirthday}        
                </when>       
                <when test="classEntity!=null and classEntity.classID !=null and classEntity.classID!='' ">       
                    AND ST.CLASS_ID = #{classEntity.classID}        
                </when>       
                <otherwise>       
                            
                </otherwise>       
            </choose>       
        </where>       
    </select>  
    

    <foreach>标签:该标签的作用是遍历集合类型的条件

    属性:collection=“array” / collection = “list” ----->是数组类型,还是集合类型
    item=“ productId ”------> 参数名
    open="(" separator="," close=")" ------>开始符号,分隔符号,结束符号
    index=“ ” ---->结束下标位置,不配置该参数时,默认为全部遍历

    <delete id="deleteByPriKeys" parameterType="java.lang.String">  
        delete from product where product_Id in  
        <foreach collection="list" item="productId" open="(" separator="," close=")">  
            #{productId,jdbcType = VARCHAR}  
        </foreach>  
    </delete>   
    

参考链接1
参考链接2

posted @ 2018-05-19 11:55  StoneGate  阅读(275)  评论(0)    收藏  举报