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>

相關文章
相關標籤/搜索