Mybatis应用学习(3)——Mapper映射文件编写

1. Mybatis的映射配置文件Mapper.xml

1.1 输入参数映射

    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>

1.2 输出参数映射

    1. resultType

  1. 在Mapper映射文件中,能够经过resultType指定SQL语句查询结果所要映射的输出类型,类型能够是java简单类型(String和七个基本类型以及基本类型的包装类)、hashmap、pojo的包装类型。使用resultType进行输出映射,只有查询出来的列名(可能会在SQL语句中给查询的字段起别名)和pojo中的属性名一致,该列才能够映射成功。若是查询出来的列名和pojo中的属性名所有不一致,没有建立pojo对象。只要查询出来的列名和pojo中的属性有一个一致,就会建立pojo对象,不一致的属性的值为null。
  2. 查询出来的结果集必须只有一行且一列,可使用简单类型(String和7个基本类型)进行输出映射。
  3. 不论是输出的pojo单个对象仍是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是同样的。具体区别在mapper.java指定的方法返回值类型不同
  • 输出单个pojo对象,方法返回值是单个对象类型

  • 输出pojo对象list,方法返回值是List<Pojo>

    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

  • 一对多:好比User用户表与NoteBook笔记本表之间,查询一个用户的全部笔记本,一个用户能够有多个笔记本,User为查询主表,NoteBook为关联表,也就是经过User表中的主键与NoteBook表的外键的关联关系来查询NoteBook表中的数据,因此就是一对多的关系
  • 一对一:好比User用户表与NoteBook笔记本表之间,查询笔记本的用户,一个笔记本只能有一个用户,NoteBook为查询主表,User表为关联表,也就是经过NoteBook表中的外键与User表主键的关联关系来查询,因此就是一对一的关系;                                                                                            一对一关联查询可使用resultType,使用resultType实现较为简单,若是pojo中没有包括查询出来的列名,须要增长列名对应的属性,便可完成映射,若是没有查询结果的特殊要求建议使用resultType。

     

    若是使用resultMap实现一对一关联查询,须要单独定义resultMap,实现有点麻烦,若是对查询结果有特殊的要求,使用resultMap能够完成将关联查询映射pojo的属性中。app

     

    resultMap能够实现延迟加载,resultType没法实现延迟加载。ide

  • 多对多:好比User用户表与NoteBook笔记本表与Note笔记表之间,查询一个用户的全部笔记本以及笔记,一个用户会有多个笔记本,一个笔记本会包含多个笔记,User表与Note表之间无直接关联关系,而是经过NoteBook表创建间接关联,User为查询主表,NoteBook笔记本表与Note笔记表为关联表,经过User表中的主键与NoteBook表的外键的关联关系来查询用户有多少笔记本,再经过每个笔记本的主键与笔记中外键的关联关系查询到每个笔记本的全部笔记,这就是多对多查询

    4. resultMap对于一对一查询的使用:以User用户表与NoteBook笔记本表为例,NoteBook表为查询主表,经过NoteBook表中的User表外键关联查询User表中的数据this

 

  • 首先写好pojo包装映射类,由于NoteBook表为查询主表,因此pojo类继承NoteBook实体类,而后再添加所要关联查询的User属性,甚至是能够将整个User类做为pojo类的属性,一个NoteBook对象对应一个User对象
    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;
    	}
    }

     

  • 编写Mapper映射文件中的SQL语句与映射关系:
    <?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

  • 首先写好pojo保证类,以User表为主表,因此应继承User类,一个User对象对应多个NoteBook对象,因此pojo类中添加一个List<NoteBook>类型的books属性
    public class UserCustom extends User{
    	private List<NoteBook> books;
    
    	public List<NoteBook> getBooks() {
    		return books;
    	}
    
    	public void setBooks(List<NoteBook> books) {
    		this.books = books;
    	}
    }

     

  • 编写Mapper映射文件中的SQL语句与映射关系:
    <?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

  • 首先定义pojo包装类:User为主表,因此pojo继承User类;要经过NoteBook关联查询获得Note,因此还得对NoteBook建立一个扩展pojo类,该pojo类要添加一个List<Note>类型的notes属性;User类的扩展pojo类就要添加一个以NoteBook的扩展pojo类做为泛型的集合属性books
    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;
    	}
    	
    }

     

  • 编写SQL语句以及映射关系:
    <?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。

2. 动态SQL

    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>

相关文章
相关标签/搜索