1. 在Mapper映射文件中,能够经过parameterType指定SQL语句所要输入参数的类型,类型能够是java简单类型(String和七个基本类型以及基本类型的包装类)、hashmap、pojo的包装类型。java
<?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="dao.UserMapper"> <select id="findUserById" parameterType="java.lang.String" resultType="entity.User"> select * from cn_user where cn_user_id=#{id} </select> </mapper>
2. 在查询或其余SQL语句中,所须要的参数多是多个,而parameterType属性只能指定一个输入参数的类型,也就是只能接受一个对象,因此咱们须要将这些参数封装到一个包装类中,这个包装类必须符合JavaBean规范,有时候须要传入查询条件很复杂,可能包括用户信息、其它信息等,而每个数据库表都对应这一个Java实体类,除非数据库表的字段发生变化,通常不修改原实体类,建议使用自定义的包装类型的pojo,在包装类型的pojo中将复杂的查询条件包装进去,好比程序员
//与数据库User表对应的实体类,类中的每一个属性名与user表的字段一致,并且符合javabean规范 public class User implements Serializable{ private String cn_user_id; private String cn_user_name; private String cn_user_password; public String getCn_user_id() { return cn_user_id; } public void setCn_user_id(String cn_user_id) { this.cn_user_id = cn_user_id; } public String getCn_user_name() { return cn_user_name; } public void setCn_user_name(String cn_user_name) { this.cn_user_name = cn_user_name; } public String getCn_user_password() { return cn_user_password; } public void setCn_user_password(String cn_user_password) { this.cn_user_password = cn_user_password; } @Override public String toString() { return "User [cn_user_id=" + cn_user_id + ", cn_user_name=" + cn_user_name + "]"; } }
/** * User应用扩展类,用于应变多种需求而创造的类 * 一般不在源类Uesr上直接进行修改,而是经过继承来添加一些额外的属性,该类也必须符合javabean规范 * */ public class UserCustom extends User{ //添加某些属性 }
//经过该类所须要的几个参数所在的扩展类的对象做为属性组合进来,参数输入映射就经过该类完成 public class queryUserVo{ private UserCustom user; //或包含其余属性 public User getUser() { return user; } public void setUser(UserCustom user) { this.user = user; } @Override public String toString() { // TODO Auto-generated method stub return user.getCn_user_name(); } }
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="dao.UserDao"> <!--经过 属性.属性.属性··· 的表达式从传入的参数包装对象中取出所须要的参数数据--> <select id="findUserById" parameterType="queryUserVo" resultType="UserCustom"> select * from cn_user where cn_user_id=#{user.cn_user_id} </select> </mapper>
2. resultMapsql
1. 在Mapper映射文件中,能够经过resultMap进行高级输出映射。数据库
2. 若是查询出来的列名和pojo的属性名不一致,经过定义一个resultMap对列名和pojo属性名之间做一个映射关系。首先要定义resultMap,而后使用resultMap做为statement的输出映射类型。数组
<!--好比下面的SQL语句中查询获得的字段名为name而不是cn_user_name,与User中的属性名没法对应,会产生问题--> <select id="findUserById" parameterType="java.lang.String" resultType="entity.User"> select cn_user_name name from cn_user where cn_user_id=#{id} </select> <!--使用resultMap--> <select id="findUserById" parameterType="java.lang.String" resultMap="username"> select cn_user_name name from cn_user where cn_user_id=#{id} </select> <!-- type指查询结果集所映射的Java类型,能够是别名或全限定名 id指该resultMap的惟一标识 --> <resultMap type="entity.User" id="username"> <!-- result标签指定java类型中的属性property与查询到的字段column之间的映射关系 --> <result column="name" property="cn_user_name"/> </resultMap>
3. 关联查询,首先搞清一对1、一对多和多对多查询,User表、NoteBook表和Note表,NoteBook表以User表的主键做为外键进行关联,Note表以NoteBook表的主键做为外键进行关联:mybatis
若是使用resultMap实现一对一关联查询,须要单独定义resultMap,实现有点麻烦,若是对查询结果有特殊的要求,使用resultMap能够完成将关联查询映射pojo的属性中。app
resultMap能够实现延迟加载,resultType没法实现延迟加载。ide
4. resultMap对于一对一查询的使用:以User用户表与NoteBook笔记本表为例,NoteBook表为查询主表,经过NoteBook表中的User表外键关联查询User表中的数据this
public class NoteBook implements Serializable { private String cn_notebook_id; private String cn_user_id; private String cn_notebook_type_id; private String cn_notebook_name; private String cn_notebook_desc; private Timestamp cn_notebook_createtime; //省略get/set方法 } public class User implements Serializable{ private String cn_user_id; private String cn_user_name; private String cn_user_password; private String cn_user_token; private String cn_user_nick; //省略get/set方法 } //若是只须要查询获得User中的部分属性,能够直接写属性,而不须要将整个User对象做为属性 public class UserAndNoteBook1 extends NoteBook { private String cn_user_name; // private String cn_user_id; public String getCn_user_name() { return cn_user_name; } public void setCn_user_name(String cn_user_name) { this.cn_user_name = cn_user_name; } } public class UserAndNoteBook2 extends NoteBook{ private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
<?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="dao.NoteBookDao"> <!-- 经过resultType实现一对一映射 将整个查询的结果映射到entity.UserAndNoteBook1类中 --> <select id="findNoteBookAndUser1" parameterType="String" resultType="entity.UserAndNoteBook1"> select cn_notebook.*,cn_user_name from cn_notebook,cn_user where cn_user.cn_user_id=cn_notebook.cn_user_id and cn_notebook.cn_notebook_id=#{id} </select> <!-- 经过resultMap实现一对一映射 --> <select id="findNoteBookAndUser2" parameterType="String" resultMap="UserAndNoteBook"> select cn_notebook.*,cn_user.* from cn_notebook,cn_user where cn_user.cn_user_id=cn_notebook.cn_user_id and cn_notebook.cn_notebook_id=#{id} </select> <!-- 定义映射结果集resultMap type指定将整个查询的结果映射到entity.UserAndNoteBook2类中, id为当前定义的resultMap在整个Mapper文件中惟一标示,经过该id属性来引用该resultMap --> <resultMap type="entity.UserAndNoteBook2" id="UserAndNoteBook"> <!-- id:指定查询列中的主键,订单信息的中的主键,若是有多个主键,配置多个id column:数据库表中的字段名 property:类中的属性名 经过column和property将数据库表中的字段映射到pojo类中指定的属性中 --> <id column="cn_notebook_id" property="cn_notebook_id"/> <result column="cn_user_id" property="cn_user_id"/> <result column="cn_notebook_type_id" property="cn_notebook_type_id"/> <result column="cn_notebook_name" property="cn_notebook_name"/> <result column="cn_notebook_desc" property="cn_notebook_desc"/> <result column="cn_notebook_createtime" property="cn_notebook_createtime"/> <!-- association:用于映射关联查询单个对象的信息,一对一关联映射查询实现的关键标签 property:要将关联查询的用户信息映射到UserAndNoteBook2类中的user属性中 javaType:指定映射的user属性的类型 --> <association property="user" javaType="entity.User"> <id column="cn_user_id" property="cn_user_id"/> <result column="cn_user_name" property="cn_user_name"/> <result column="cn_user_password" property="cn_user_password"/> <result column="cn_user_token" property="cn_user_token"/> <result column="cn_user_nick" property="cn_user_nick"/> </association> </resultMap> </mapper>
5. resultMap对于一对多查询的使用:以User用户表与NoteBook笔记本表为例,User表为查询主表,经过User表中的主键关联查询NoteBook表中的数据,一行User数据(或者说一个User对象)对应多行NoteBook数据(多个NoteBook对象)spa
public class UserCustom extends User{ private List<NoteBook> books; public List<NoteBook> getBooks() { return books; } public void setBooks(List<NoteBook> books) { this.books = books; } }
<?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="dao.UserDao"> <select id="findUserWithNoteBook" parameterType="java.lang.String" resultMap="UserWithNoteBook"> SELECT cn_notebook.*, cn_user.* FROM cn_notebook, cn_user WHERE cn_user.cn_user_id = cn_notebook.cn_user_id and cn_user.cn_user_id=#{id} </select> <resultMap id="UserWithNoteBook" type="entity.UserCustom"> <id column="cn_user_id" property="cn_user_id"/> <result column="cn_user_name" property="cn_user_name"/> <result column="cn_user_password" property="cn_user_password"/> <result column="cn_user_token" property="cn_user_token"/> <!--对于一对多关系映射,应使用collection 子标签, property指定将全部查询到的NoteBook集合存放到books属性对象中, ofType指定查询到的每一条NoteBook数据都映射为entity.NoteBook类对象 --> <collection property="books" ofType="entity.NoteBook"> <id column="cn_notebook_id" property="cn_notebook_id"/> <result column="cn_user_id" property="cn_user_id"/> <result column="cn_notebook_type_id" property="cn_notebook_type_id"/> <result column="cn_notebook_name" property="cn_notebook_name"/> <result column="cn_notebook_desc" property="cn_notebook_desc"/> <result column="cn_notebook_createtime" property="cn_notebook_createtime"/> </collection> </resultMap> </mapper>
6. resultMap对于多对多查询的使用:以User用户表与NoteBook笔记本表与Note笔记表为例,User表为查询主表,经过User表中的主键关联查询NoteBook表中的数据,一行User数据(或者说一个User对象)对应多行NoteBook数据(多个NoteBook对象),而后再经过查询到的每个NoteBook中的主键id,关联查询该NoteBook有多少Note
public class Note implements Serializable{ private String cn_note_id; private String cn_notebook_id; private String cn_note_title; private String cn_note_body; //省略get/set方法 } public class NoteBookVo extends NoteBook{ private List<Note> notes; public List<Note> getNotes() { return notes; } public void setNotes(List<Note> notes) { this.notes = notes; } } public class UserVo extends User{ private List<NoteBookVo> books; public List<NoteBookVo> getBooks() { return books; } public void setBooks(List<NoteBookVo> books) { this.books = books; } }
<?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="dao.UserDao"> <select id="find" parameterType="java.lang.String" resultMap="UserVo"> SELECT cn_notebook.*, cn_user.*,cn_note.* FROM cn_notebook, cn_user, cn_note WHERE cn_user.cn_user_id = cn_notebook.cn_user_id and cn_user.cn_user_id=#{id} and cn_note.cn_notebook_id=cn_notebook.cn_notebook_id </select> <resultMap id="UserVo" type="entity.UserVo"> <id column="cn_user_id" property="cn_user_id"/> <result column="cn_user_name" property="cn_user_name"/> <result column="cn_user_password" property="cn_user_password"/> <result column="cn_user_token" property="cn_user_token"/> <collection property="books" ofType="entity.NoteBookVo"> <id column="cn_notebook_id" property="cn_notebook_id"/> <result column="cn_user_id" property="cn_user_id"/> <result column="cn_notebook_type_id" property="cn_notebook_type_id"/> <result column="cn_notebook_name" property="cn_notebook_name"/> <result column="cn_notebook_desc" property="cn_notebook_desc"/> <result column="cn_notebook_createtime" property="cn_notebook_createtime"/> <collection property="notes" ofType="entity.Note"> <id column="cn_note_id" property="cn_note_id"/> <result column="cn_notebook_id" property="cn_notebook_id"/> <result column="cn_note_title" property="cn_note_title"/> <result column="cn_note_body" property="cn_note_body"/> </collection> </collection> </resultMap> </mapper>
6. 关于resultMap中的关联查询映射,实际上主要就是collection与association两个子标签的运用,这两个子标签之间能够互相嵌套,以应对要映射的类中包含pojo类型的属性或者是包含集合类型的属性,或者是属性的属性中包含pojo类型的属性或包含集合类型的属性,经过collection与association两个子标签的互相嵌套使用就能够解决具备复杂属性的映射类问题。若是过属性为集合就使用collection,若是为pojo类型就使用association,二者须要之间的使用区别就在于collection标签的属性中指定集合中元素映射的类型使用ofType,association标签的属性中指定映射的类型使用javaType。
1. 动态SQL即Mybatis对sql语句进行灵活操做,经过一些标签进行判断,对sql进行灵活拼接、组装。
2. 条件判断标签<if test=""></if>:对输入的参数进行判断,若是输入参数知足条件才进行SQL语句拼接。若是传入的参数是一个包装对象,那么就经过属性.属性.属性··来对参数进行判断
<!--无判断sql--> <select id="findUserById" parameterType="entity.User" resultType="entity.User"> select * from cn_user where cn_user_id=#{id} and cn_user_name=#{cn_user_name} and cn_user_password=#{cn_user_password} </select> <!--无判断添加if标签判断--> <select id="findUserById" parameterType="entity.User" resultType="entity.User"> select * from cn_user <!-- where标签至关于sql中的where关键字,但该标签还能够自动消除拼接的sql语句中第一个and、or关键字 好比,若是cn_user_name为空那么就会拼接and cn_user_password=#{cn_user_password},and关键字是多余的 而where标签就会消除and标签,并且还至关于where关键字 --> <where> <!-- 判断参数是否为空 --> <if test="cn_user_name!=null and cn_user_name!=''"> and cn_user_name=#{cn_user_name} </if> <if test="cn_user_password!=null and cn_user_password!=''"> and cn_user_password=#{cn_user_password} </if> </where> </select>
3. SQL片断:将一些的频繁出现的sql代码块提取出来,成为一个SQL片断,能够提升SQL的复用性,其它的statement中就能够引用sql片断,方便程序员进行开发,经过标签<sql id=""></sql>定义,好比将上面的判断条件部分的提取为一个代码块
<!-- 经过id定义该SQL片断在当前Mapper文件中的惟一标示,经过该id就能够被其余sql语句引用 通常来讲SQL片断要基于单表,其次SQL片断中不要出现where关键字或者where标签,由于若是sql片断中 有了一个where那么组合其余sql片断是就会出现错误 --> <sql id="query_if"> <!-- 判断参数是否为空 --> <if test="cn_user_name!=null and cn_user_name!=''"> cn_user_name=#{cn_user_name} </if> <if test="cn_user_password!=null and cn_user_password!=''"> and cn_user_password=#{cn_user_password} </if> </sql> <select id="findUserById" parameterType="entity.User" resultType="entity.User"> select * from cn_user <where> <!-- 引用sql片断,若是引用的SQL片断在另外一个mapper文件中,那么就要在SQL片断的id 前面加上SQL片断所在的mapper文件的namespace,好比 usermapper.query_if --> <include refid="query_if"></include> </where> </select>
4. 若是Mapper映射文件中sql语句的映射输入对象是一个包装对象,并且该包装对象的属性是一个List或者数组对象,能够经过foreach 标签来对该属性对象进行解析遍历:好比以下两种sql语句形式
第一种形式:select * from cn_user where cn_user_id=123 or cn_user_id=2342 or cn_user_id=34636 该形式中的where部分可变为以下SQL片断 <where> <!-- collection:指定输入映射对象中的List或数组类型的属性 separator:指定遍历拼接的两个片断之间进行分隔 的关键字,好比and、or index:用来表示遍历的每一个元素的下标,能够经过该index属性值来提取元素下标 item:用来表示遍历的每一个元素 open:表示遍历拼接SQL片断以前要添加的SQL片断 close:表示遍历拼接SQL片断以后要添加的SQL片断 --> <foreach collection="ids" separator="or" index="index" item="id" open="(" close=")"> cn_user_id=#{id}<!--注意,这里的#{}中必须写与item指定的字符串相同--> </foreach> </where> 第二种形式:select * from cn_user where cn_user_id in (1,2,3,4) 该形式中的where部分可变为以下SQL片断 <where> <foreach collection="ids" separator="," index="index" item="id" open="cn_user_id in (" close=")"> #{id}<!--注意,这里的#{}中必须写与item指定的字符串相同--> </foreach> </where>
<foreach collection="" separator="" index="" item="" open="" close=""></foreach>