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.StudentMapperjava

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

 

 

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

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

 事实上,若是经过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>

%是通配符,表明其余字符。mybatis

${}除了有#{}的功能外,还有链接字符串的做用。oracle

 

 

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

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

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

注意使用的是#{}

 

 

包含传入的参数便可 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将该部分代码包含进来。

相关文章
相关标签/搜索