Mybatis-常见SQL语句示例

作者: 栾呱呱 | 来源:发表于2017-10-15 18:06 被阅读504次

    官方说明文档:http://www.mybatis.org/mybatis-3/zh/index.html#

    resultType和resultMap区别

    resultType:从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。

    也就是说,使用resultType直接表示的就是返回类型,可以是基本类型(int、string)、list、map这些,也可以是具体的pojo对象

    • 完全限定名,意思是例如返回Task对象,那么值填写的是该Task类的完整类路径;如果返回的是基础类型,就是类似java.util.Map
    • 别名,意思是例如返回map类型,我们不需要写完整的java.util.Map,可以用map替代
    • 不能是集合本身,这句话意思是例如接口需要返回List<Task>,那么直接写resultType="com.baidu.vo.Task",而不是写成resultType="List<com.baidu.vo.Task>"

    resultMap:外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用。

    相对复杂一点,需要先定义一个外部标签<resultMap>,这里面一般定义了结果到pojo的映射关系,有id属性,在具体的查询语句中通过id寻找对应的resultMap

    • 外部 resultMap 的命名引用,意思是并不是直接的返回类型,只是一个引用标识,需要去找对应的该引用的定义地方

    DEMO-resultType

    • select * from task where id = {id} 输出单个Task对象

    TaskMapper.xml代码

    <select id="select" parameterType="int" resultType="com.baidu.pojo.entity.Task">
            select * from task where id = #{id}
    </select>
    

    TaskMapper.java代码

    Task select(int id);
    
    • select * from task 输出Task集合

    TaskMapper.xml代码

    <select id="select" resultType="com.baidu.pojo.entity.Task">
            select * from task 
    </select>
    

    TaskMapper.java代码

    List<Task> select();
    

    note:通过上面两个例子发现,无论输出单个对象还是一个列表,resultType的类型都是一样的。如果第二个例子中,TaskMapper.java里面方法返回值类型是Task而不是List<Task>的话,当查询的结果包含多条语句时,就会抛TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 10

    • select count(*) from task

    TaskMapper.xml代码

    <select id="select" resultType="int">
            select count(*) from task
    </select>
    

    TaskMapper.java代码

    int select();
    
    • select name from task where id = {id} 输出单个name

    TaskMapper.xml代码

    <select id="select" parameterType="int" resultType="String">
            select name from task where id = #{id}
    </select>
    

    TaskMapper.java代码

    String select(int id);
    
    • select distinct name from task 输出name集合

    TaskMapper.xml代码

    <select id="select" resultType="String">
            select distinct name from task
    </select>
    

    TaskMapper.java代码

    List<String> select();
    

    note:无论是单个name还是一个name集合,resultType都是String

    • select id, name from task where id = {id}

    TaskMapper.xml代码

    <select id="select" resultType="map">
            select id, name from task where id = #{id}
    </select>
    

    TaskMapper.java代码

    Map select();
    

    note:返回类型是map时,一条记录会映射为一个map对象,列名对应键,结果对应值,如果是多条结果,那么应该映射为类型的map的一个集合

    • select status, count(*) as num from task group by status desc 统计任务表里所有状态的个数

    TaskMapper.xml代码

    <select id="select" resultType="hashmap">
            select status, count(*) as num from task group by status desc
    </select>
    

    TaskMapper.java代码

    List<HashMap> select();
    

    note:注意这里的返回值是一个list,list中的元素是map对象,假如group之后有4组,那么就是包含4个map的数组

    • select * from task where id in (3, 4, 5) 参数是一个数组

    TaskMapper.xml代码

    <select id="select" resultType="com.baidu.pojo.entity.Task">
            select * from task where id in
            <foreach item="item" index="index" collection="list"
                     open="(" separator="," close=")">
                #{item}
            </foreach>
    </select>
    

    TaskMapper.java代码

    List<Task> select(List ids);
    

    note:item代表循环中的具体对象,如果collection属性是list,那item就表示list中的一个元素;collection是遍历的对象,可以是list、array,如果Mapper.java里传入参数时使用@param(“param”)来设置名字,那这里的collection属性就填写对应的参数名;separator是分隔符,例如sql中出现in语句时,就会设置separator=“,”分隔;open和close代表in语句里面的前后括号

    • insert into task (title, name) values ('标题', '名字') 参数是一个map

    TaskMapper.xml代码

    <insert id="insert" parameterType="map">
            insert into task
            <foreach collection="map.keys" item="key" open="(" close=")" separator=",">
                ${key}
            </foreach>
            values
            <foreach collection="map.keys" item="key" open="(" close=")" separator=",">
                #{map[${key}]}
            </foreach>
    </insert>
    

    TaskMapper.java代码

    int test(@Param("map") Map map);
    

    note:这里Mapper.java文件里面使用的@param注解,对应的collection就使用注解定义好的名字

    DEMO-resultMap

    定义一个Task类

    public class Task {
        private Integer id;
        private String title;
        private String name;
        private Date createAt;
    
        public Integer getId() {return id;}
        public void setId(Integer id) {this.id = id;}
        public String getTitle() {return title;}
        public void setTitle(String title) {this.title = title;}
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
        public Date getCreateAt() {return createAt;}
        public void setCreateAt(Date createAt) {this.createAt = createAt;}
    }
    

    定义一个resultMap

    <resultMap id="BaseResultMap" type="com.baidu.pojo.entity.Task">
            <id column="id" property="id" jdbcType="INTEGER"/>
            <result column="title" property="title" jdbcType="VARCHAR"/>
            <result column="name" property="name" jdbcType="VARCHAR"/>
            <result column="create_at" property="createAt" jdbcType="TIMESTAMP"/>
    </resultMap>
    

    note:column代表数据库表里面的属性,property代表赋值给实体对象的属性

    定义一个sql

    <sql id="Base_Column_List">
            id, title, name, create_at
    </sql>
    

    note:这个元素是用来定义可以重复使用的sql代码语句的,这里面把Task表的全部列名定义为了一个sql,是为了下面查询语句的重复使用

    • select * from task where create_at = '2017-07-07' 查询数据

    TaskMapper.xml代码

    <select id="select" resultMap="BaseResultMap" parameterType="com.baidu.pojo.entity.Task">
            select <include refid="Base_Column_List"/> from task
            <where>
                <if test="id != null">id=#{id}</if>
                <if test="title != null">and title=#{title}</if>
                <if test="name != null">and name=#{name}</if>
                <if test="createAt != null">and create_at=#{createAt}</if>
            </where>
    </select>
    

    TaskMapper.java代码

    List<Task> select(Task task);
    

    note:这里用到了resultMap属性,where元素知道只有在一个以上的if条件有值的情况下才去插入WHERE子句。而且,若最后的内容是AND或OR开头的,where元素也知道如何将他们去除。这里面的if语句很直观,就是代表如果传入的参数中,该属性不为空,那么就把该条件带上去

    • insert into task (title, name,create_at) values ('标题', '名字', '2017-07-07') 插入数据

    TaskMapper.xml代码

    <insert id="add" parameterType="com.baidu.pojo.entity.Task" useGeneratedKeys="true" keyProperty="id">
            insert into task (<include refid="Base_Column_List"/>) values (
            #{id,jdbcType=INTEGER}, 
            #{title,jdbcType=VARCHAR},
            #{name,jdbcType=VARCHAR},
            #{createAt,jdbcType=TIMESTAMP} )
    </insert>
    

    TaskMapper.java代码

    int add(Task task);
    

    note:useGeneratedKeys表示是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的属性中,这里就是id是自增长的主键,值可以通过getGenereatedKeys方法获取然后复制到task对象的属性上面

    • update task set name = '名字' where id = {id} 更新数据

    TaskMapper.xml代码

    <update id="update" parameterType="com.baidu.pojo.entity.Task">
            update task
            <set>
                <if test="title != null">title=#{title,jdbcType=VARCHAR},</if>
                <if test="name != null">name=#{name,jdbcType= VARCHAR},</if>
                <if test="createAt != null">create_at=#{createAt,jdbcType=TIMESTAMP}</if>
            </set>
    </update>
    

    TaskMapper.java代码

    int update(Task task);
    

    note:set 元素会动态前置SET关键字,同时也会消除无关的逗号

    • delete from task where create_at = '2017-07-07' 删除数据

    TaskMapper.xml代码

    <delete id="select" parameterType="com.baidu.pojo.entity.Task">
            delete from task
            <where>
                <if test="id != null">id=#{id}</if>
                <if test="title != null">and title=#{title}</if>
                <if test="name != null">and name=#{name}</if>
                <if test="createAt != null">and create_at=#{createAt}</if>
            </where>
    </delete>
    

    TaskMapper.java代码

    int delete(Task task);
    
    • select * from task where title = {title} and name = {name} 利用索引传递多个参数

    TaskMapper.xml代码

    <select id="select" resultMap="baseResultMap">
            select <include refid="Base_Column_List"/> from task where title = #{0} and name = #{1}
    </select>
    

    TaskMapper.java代码

    List<Task> select(String title, String name);
    

    note:使用#{index}指定参数,索引从0开始

    • select * from task where title = {title} and name = {name} 利用@param注解传递多个参数

    TaskMapper.xml代码

    <select id="select" resultMap="baseResultMap">
            select <include refid="Base_Column_List"/> from task where title = #{title} and name = #{name}
       
    </select>
    

    TaskMapper.java代码

    List<Task> select(@Param("title") String title, @Param("name") String name);
    

    DEMO-关联查询

    描述:一个计划有一个执行人,一个人只能执行一个计划

    定义一个User类

    public class User {
        private Integer id;
        private String name;
        
        public Integer getId() {return id;}
        public void setId(Integer id) {this.id = id;}
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
    }
    
    

    定义一个Plan类

    public class Plan {
        private Integer id;
        private String name;
        private User user;
    
        public Integer getId() {return id;}
        public void setId(Integer id) {this.id = id;}
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
        public String getUser() {return user;}
        public void setUser(User user) {this. user = user;}
    }
    
    • select * from plan, user where plan.uid = user.id and plan.id = #{id} 一对一关联查询(方式一)

    定义一个resultMap

    <resultMap id="PlanUserMap" type="com.baidu.pojo.entity.Plan">
            <id column="id" property="id" jdbcType="INTEGER"/>
            <result column="name" property="name" jdbcType="VARCHAR"/>
            <association property="user" javaType="com.baidu.pojo.entity.User">
                <id column="id" property="id" jdbcType="INTEGER"/>
                <result column="name" property="name" jdbcType="VARCHAR"/>
            </association>
    </resultMap>
    

    PlanMapper.xml代码

    <select id="select" parameterType="int" resultMap="PlanUserMap">
            select * from plan, user where plan.uid = user.id and plan.id = #{id}       
    </select>
    

    PlanMapper.java代码

    Plan select(int id);
    

    note:uid是Task表的外键,这里面用的是association标签

    • select * from plan, user where plan.uid = user.id and plan.id = #{id} 一对一关联查询(方式二)

    定义一个resultMap

    <resultMap id="PlanUserMap" type="com.baidu.pojo.entity.Plan">
            <id column="id" property="id" jdbcType="INTEGER"/>
            <result column="name" property="name" jdbcType="VARCHAR"/>
            <association column="uid" property="user" select="getUser"/>
    </resultMap>
    

    PlanMapper.xml代码

    <select id="select" parameterType="int" resultMap="PlanUserMap">
            select * from plan where id = #{id}       
    </select>
    
    <select id="getUser" parameterType="int" resultType="com.baidu.pojo.entity.User">
            select * from user where id = #{id}       
    </select>
    

    PlanMapper.java代码

    Plan select(int id);
    

    note:先查询出一条Plan记录,然后把该记录的uid值作为User表的id,查询对应的User记录


    描述:一个计划可以执行多个任务,一个任务属于一个计划

    定义一个Task类

    public class Task {
        private Integer id;
        private String title;
        private String name;
        private Date createAt;
    
        public Integer getId() {return id;}
        public void setId(Integer id) {this.id = id;}
        public String getTitle() {return title;}
        public void setTitle(String title) {this.title = title;}
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
        public Date getCreateAt() {return createAt;}
        public void setCreateAt(Date createAt) {this.createAt = createAt;}
    }
    

    定义一个Plan类

    public class Plan {
        private Integer id;
        private String name;
        private List<Task> tasks;
    
        public Integer getId() {return id;}
        public void setId(Integer id) {this.id = id;}
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
        public List<Task> getTasks() {return tasks;}
        public void setTasks(List<Task> tasks) {this. tasks = tasks;}
    }
    
    • select * from plan, task where plan.id = task.pid and plan.id = #{id} 一对多关联查询(方式一)

    定义一个resultMap

    <resultMap id="PlanTaskMap" type="com.baidu.pojo.entity.Plan">
            <id column="id" property="id" jdbcType="INTEGER"/>
            <result column="name" property="name" jdbcType="VARCHAR"/>
            <collection property="tasks" ofType="com.baidu.pojo.entity.Task">
                 <id column="id" property="id" jdbcType="INTEGER"/>
                 <result column="title" property="title" jdbcType="VARCHAR"/>
                 <result column="name" property="name" jdbcType="VARCHAR"/>
                 <result column="create_at" property="createAt" jdbcType="TIMASTAMP"/>
            </collection>
    </resultMap>
    

    PlanMapper.xml代码

    <select id="select" parameterType="int" resultMap="PlanTaskMap">
            select * from plan, task where plan.id = task.pid and plan.id = #{id}       
    </select>
    

    PlanMapper.java代码

    Plan select(int id);
    

    note:pid是Task表的外键,这里面用的是collection标签

    • select * from plan, task where plan.id = task.pid and plan.id = #{id} 一对多关联查询(方式二)

    定义一个resultMap

    <resultMap id="PlanTaskMap" type="com.baidu.pojo.entity.Plan">
            <id column="id" property="id" jdbcType="INTEGER"/>
            <result column="name" property="name" jdbcType="VARCHAR"/>
            <collection column="pid" property="tasks" ofType="com.baidu.pojo.entity.Task" select="getTask">
            </collection>
    </resultMap>
    

    PlanMapper.xml代码

    <select id="select" parameterType="int" resultMap="PlanTaskMap">
            select * from plan where id = #{id}       
    </select>
    
    <select id="getTask" parameterType="int" resultType="com.baidu.pojo.entity.Task">
            select * from user where id = #{id}       
    </select>
    

    PlanMapper.java代码

    Plan select(int id);
    

    note:先查询出一条Plan记录,然后把该记录的id值作为Task表的pid,查询对应的多条Task记录

    补充

    我们发现,无论结果是返回一个值还是一个数组,resultType的返回类型都是单一的对象,但是Mapper.java里面有的是单一值,有的是list,MyBatis是如何知道我们想要的是一个结果还是多个结果。其实,无论返回一个还是多个,MyBatis都是按照多个结果查询,看一下selectOne源码:

    public <T> T selectOne(String statement, Object parameter) {
        List<T> list = this.<T>selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }
    

    即使使用的是selectOne方法,里面调用的还是selectList方法,然后返回第一个值,代码中有一句大家可能会很熟悉。当返回值有多个,但是接口中的返回类型是单一的对象的时候,就会抛该错误

    相关文章

      网友评论

      本文标题:Mybatis-常见SQL语句示例

      本文链接:https://www.haomeiwen.com/subject/izpcuxtx.html