• MyBatis 映射文件详解


    普通的增改删查

    <?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.chy.mapper.StudentMapper">
        <insert id="insertStudent" parameterType="com.chy.pojo.Student">
            INSERT INTO student_tb(id,name,age,score)VALUES (#{id},#{name},#{age},#{score})
        </insert>
    
        <update id="updateStudent" parameterType="com.chy.pojo.Student">
            UPDATE student_tb SET name=#{name},age=#{age},score=#{score} WHERE id=#{id}
        </update>
    
        <delete id="deleteStudent" parameterType="Integer">
            DELETE FROM student_tb WHERE id=#{id}
        </delete>
    
        <select id="queryById" parameterType="Integer" resultType="com.chy.pojo.Student">
            SELECT * FROM student_tb WHERE id=#{id}
        </select>
    </mapper>

    <mapper>的namespace常用映射文件所在的 包名+映射文件名 。比如com.chy.mapper包下的映射文件StudentMapper.xml    =>    com.chy.mapper.StudentMapper

    parameterType指定传入的参数的数据类型,resultType指定将查询结果映射为何种数据类型。

     

    Student student = sqlSession.selectOne("com.chy.mapper.StudentMapper.queryById", 1);

    通过namespace和id来引用相应的元素,传入parameterType类型的参数。返回resultType指定的数据类型。

     事实上,如果通过id可以唯一确定要引用的元素,是可以省略namespace、只写id的。 


    模糊查询

    精确查询:必须完全相同,比如WHERE name = 'chy',name字段必须是chy才匹配,不能是什么chy1。

    模糊查询:只要包含即可,比如WHERE name LIKE '%chy%',只要name字段包含chy即可,可以匹配chy、1chy1......

    <select id="queryByName" parameterType="String" resultType="Student">
            SELECT * FROM student_tb WHERE name LIKE '%${value}%'
    </select>

    %是通配符,代表其他字符。

    ${}除了有#{}的功能外,还有连接字符串的作用。

    使用${}连接字符串不安全,不能防止sql注入,为了安全,尽量采用sql的concat()函数来连接字符串:

    <select id="queryByName" parameterType="String" resultType="String">
            SELECT name FROM student_tb WHERE name LIKE concat('%',#{value},'%')
    </select>

    sql的concat()函数可连接多个字符串,将要连接的字符串依次传入即可。

    注意使用的是#{}

    包含传入的参数即可 concat('%',#{value},'%') '%${value}%'
    以传入的参数开头 concat('%',#{value}) '%${value}'
    以传入的参数结尾 concat(#{value},'%') '${value}%'

      

    如果传入的是简单的数据类型,比如数值型、String,#{}、${}中可以随便写变量名,为了见名知义,#{}中一般写pojo类的字段名,${}中常写value。

    如果传入的是pojo类的对象,#{}、${}中只能写pojo类的字段名。


    pojo类中基本类型的成员变量、映射文件中的基本数据类型,尽量使用包装类型。

    比如 int =>  Integer,long => Long 。

    举个例子:

    成绩表中某个同学缺考、财务表中本月支出尚未填写,

    在sql中如果使用0表示,别人会以为是考了0分、本月支出就是0元。

    没有值的字段要用null表示。别人一看到null,就知道这家伙没成绩、缺考了,这个月的支出还没填写。

    数值型都可以转换为包装类型,比如 int型的0可以转换为Integer型的0;

    但包装类型比基本数值类型多了一个值:null,这个值在基本数值型中是找不到对应的。

    private int score; 我们没给这个字段赋值,jvm给的初始值是0,插到数据库的是0。

    private Integer score;我们没给这个字段赋值,jvm给包装类的初始值是null,插到数据库中就是null。如果值为0,给它赋值就是了score=0,这样插到数据库的就是0.

    包装类型比基本类型更全面些,基本类型可以表示的它也可以表示,基本类型不能表示的它也能表示。

    pojo类的成员变量、映射文件中的数据类型尽量使用包装类型。


     <mapper>常用的子元素

    • <select>、<insert>、<update>、<delete>
    • <sql>   用于定义可重用的sql片段
    • <resultMap>

    <select>、<insert>、<update>、<delete>都具有的属性

    • userCache   控制二级缓存的开启、关闭,Boolean值
    • flushCache  调用sql语句之后,是否需要清空之前查询的本地缓存和二级缓存,Boolean值
    • timeout   设置超时时间,默认单位秒,超时时会抛出异常
    • statementType   设置mybatis使用jdbc的哪种statement来工作,可选的值:STATEMENT、PREPARED(默认值)、CALLABLE,分别对应jdbc的Statement、PreparedStatement、CallableStatement

    <select>元素独有的属性

    • resultType   将查询结果映射到那种数据类型
    • resultMap  引用<resultMap>
    • fetchSize   获取记录的总条数

    <resultMap>的用法

    <resultMap>用于自定义查询结果集的映射规则。

    <resultMap id="" type="">
            <constructor>
                <idArg />
                <arg />
            </constructor>
    
            <id />
            <result />

         <discriminator>
            <case></case>
         </discriminator>
    <association property="" /> <collection></collection> </resultMap>

    type指定将结果集映射到哪种数据类型(哪个pojo类)。

    <constructor>用于构造器注入,pojo类需提供带参的构造器,这个基本不用。

    <association>用于一对一关联映射、<collection>用于一对多、多对多关联映射。

    <id>、<result>指定表的字段——pojo类的属性之间的映射,id是主键字段的映射,result是普通字段的映射。

        <resultMap id="carMap" type="com.chy.pojo.Car">
            <id property="id" column="car_id"/>
            <result property="name" column="car_name"/>
            <result property="price" column="car_price"/>
        </resultMap>
    
        <select id="queryById" parameterType="Integer" resultMap="resultMap">
            SELECT * FROM car_tb WHERE car_id=#{car_id}
        </select>

    如果表的字段名、pojo类的成员变量名完全一致,则可以缺省<id>、<result>(如果没有关联映射,可不使用<resultMap>),因为默认的映射就是表字段名、pojo类成员变量名一致。

    如果表的字段名、pojo类的成员变量名不一致,则只配置不一致的字段即可。


    <discriminator>  鉴别器

    有时候需要将结果集中的记录映射为不同类型的对象。

    比如说商城首页往往需要展示多种类型的商品。小米商城首页要展示手机、电脑、电视.......从商品表中查询新品,需要将这些记录映射为不同的实体类:MobilePhone、Computer、TV。

    <resultMap id="goodsMap" type="goods">
            <discriminator javaType="string" column="type">
                <case value="phone" resultType="mobilephone" />
                <case value="computer" resultType="computor" />
                <case value="tv" resultType="tv" />
            </discriminator>
    </resultMap>

    用结果集的某个字段来判断,如果这个字段的值是xxx,就将这条记录映射为指定的类型。

    • <resultMap>的type用于指定返回值类型,常使用父接口、父类
    • <discriminator>的column指定用哪个字段来判断,javaType指定这个字段对应的java类型
    • <case>的value指定一个常量值,resultType指定返回值类型,常使用实现类、子类,如果这个字段的值是该常量值,就将这条记录映射为指定的类型

    如果我们没有给<case>中的这些类写一个共同的接口、父类,那<resultMap>的type可以写成object。

    如果该类型也需要配置映射,可以在<case>中进行配置:

    <resultMap id="goodsMap" type="goods">
            <discriminator javaType="string" column="type">
                <case value="phone" resultType="mobilephone" />
                <case value="computer" resultType="computor" />
                <case value="tv" resultType="tv">
                    <id />
                    <result />
                    <association property="" />
                </case>
            </discriminator>
    </resultMap>

    鉴别器常用于结果集中的记录可以细分为多种类型的情况,比如查询体测成绩:

    • 身高、体重(公共项目)
    • 1000m、引体向上(男)
    • 800m、仰卧起坐(女)

    那我可以写一个父类PhysicalTest,把公共项目(身高、体重)的成绩作为成员变量,

    写一个子类MalePhysicalTest  extends  PhysicalTest,里面添加男生的1000m、引体向上,

    写一个子类FemalePhysicalTest  extends  PhysicalTest,里面添加女生的800m、仰卧起坐。

    在<discriminator>中根据gender来判断,如果是男生,就映射为MalePhysicalTest,是女生就映射为FemalePhysicalTest。

    把公共属性写在父类、父接口中,把特有属性写在子类中。


    插入记录与主键自增

    有2种情况:

    (1)使用的是支持主键自增的数据库,比如mysql、sql server,设计表时勾选主键自增

    插入记录时不设置主键的值,数据库会自动设置id的值。

    <insert id="insertStudent" parameterType="com.chy.pojo.Student" keyProperty="id" useGeneratedKeys="true">
            INSERT INTO student_tb(name,age,score)VALUES (#{name},#{age},#{score})
    </insert>
    Student student = new Student();
    student.setName("chy");
    sqlSession.insert("com.chy.mapper.StudentMapper.insertStudent", student);
    System.out.println(student.getId());
    • useGeneratedKeys   调用jdbc的getGeneratedKeys()来获取数据库中此条记录主键字段的值。
    •  keyProperty   将值赋给pojo指定的字段,如果要赋给多个字段,逗号分隔即可。

    这2个属性的作用是将数据库主键自增产生的值同步到pojo类的实例。

    (2)使用的是不支持主键自增的数据库,比如oracle,

        或者使用的是支持主键自增的数据库,但设计表时没有勾选主键自增。

    那只能手动设置主键字段的值。在<selectKey>中手动写一条sql语句来查询主键字段的值咯。

    <insert id="insertStudent" parameterType="com.chy.pojo.Student">
            <selectKey keyProperty="id" resultType="Integer" order="BEFORE">
                select if(max(id) is null ,1,max(id)+1) from student_tb
            </selectKey>
            INSERT INTO student_tb(id,name,age,score)VALUES (#{id},#{name},#{age},#{score})
    </insert>
    • keyProperty指定主键对应pojo类的哪个属性
    • resultType指定主键对应的java类型
    • order指定这2条sql语句的执行顺序。

    BEFORE:在执行insert 之前执行<selectKey>

     先执行<selectKey>中的sql语句,获得主键字段的值,

    再调用setter方法将这个值注入到pojo类的实例,然后将这个实例作为参数传给insert语句。

    主键字段已自动同步到pojo实例中。

    AFTER:在执行insert之后才执行<selectKey>。

     顺序是相对于insert而言的,毕竟insert才是主体,<selectKey>只是辅助用的。

    使用before、after,在<selectKey>中写的sql语句是不同的。

    select if(max(id) is null ,1,max(id)+1) from student_tb

    从表中查询id字段(int)的最大值,如果一条记录都没有,返回1;如果有记录,将id最大的值+1返回。

    说明

    <update>和<insert>一样具有以上的属性、子元素,<update>常用来返回所修改的记录的id。


    <sql>的用法示例

    原来的写法:

    <select id="queryById" parameterType="Integer" resultType="com.chy.pojo.Student">
            SELECT * FROM student_tb WHERE id=#{id}
    </select>

    使用<sql>的写法:

    <sql id="tableName">
        student_tb
    </sql>
    <select id="queryById" parameterType="Integer" resultType="com.chy.pojo.Student">
        SELECT * FROM <include refid="tableName" /> WHERE id=#{id}
    </select>

    在<sql>中定义sql语句的部分代码,然后使用<include />通过id将该部分代码包含进来。

  • 相关阅读:
    程序打印的日志哪里去了?结合slf4j来谈谈面向接口编程的重要性
    vue项目用npm安装sass包遇到的问题及解决办法
    nginx反向代理配置及常见指令
    你以为你以为的就是你以为的吗?记一次服务器点对点通知的联调过程
    jeecg逆向工程代码的生成及常见问题
    java注解
    终于有了,史上最强大的数据脱敏处理算法
    SpringBoot项目下的JUnit测试
    递归方法
    练习题
  • 原文地址:https://www.cnblogs.com/chy18883701161/p/12122079.html
Copyright © 2020-2023  润新知