天天看點

MyBatis架構之第二篇

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結和本聲明。

本文連結:https://blog.csdn.net/zhao1299002788/article/details/102136244

1、進階參數映射和傳回值映射(重點)
		a)Pojo包裝pojo的參數映射
		b)當結果集列名與pojo屬性名不一緻的傳回值映射
		2、動态sql(重點)
		3、關聯查詢結果(重點)
		a)一對一關聯結果
		b)一對多關聯結果
		4、Mybatis整合spring
		5、逆向工程
		2.事前代碼準備
		今天學習内容的練習主要以MyBatis動态代理的方式通路編寫通路資料庫的代碼,是以參照昨天的工程重新建立一個新工程作為今天代碼練習的內建,同時需要把一些動态代理需要的目錄、空檔案提前建構好,以友善後面使用。
		2.1.工程代碼結構(UTF8)

		2.2.Mapper映射檔案及對應的接口檔案
		OrderMapper.xml
		<?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="cn.baidu.dao.OrderMapper">
			<!-- SQL -->
			
		</mapper>
		OrderMapper.java
		package cn.baidu.dao;

		public interface OrderMapper {

		}
		UserMapper.xml
		<?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="cn.baidu.dao.UserMapper">
			<!-- SQL -->
			
		</mapper>
		UserMapper.java
		package cn.baidu.dao;

		public interface UserMapper {

		}

		2.3.POJO定義
		1.将昨天工程中的【User.java】拷貝到pojo的包下
		2.把【資料\03.pojo\Order.java】拷貝到pojo的包下。
		2.4.配置檔案和屬性檔案
		1.把昨天工程中Source Folder【config】下的全部配置檔案和屬性檔案拷貝過來。
		2.走查一下配置檔案,把沒有必要的注釋删除,需要修改的配置修改。
		<?xml version="1.0" encoding="UTF-8"?>
		<!DOCTYPE configuration
		  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
		  "http://mybatis.org/dtd/mybatis-3-config.dtd">
		<configuration>
			<!-- 配置屬性檔案 -->
			<properties resource="jdbc.properties" />
			
			<!-- 資料庫環境的配置 -->
			<environments default="dev">
				<!-- 開發資料庫環境的配置 -->
				<environment id="dev">
					<!-- 事務管理的配置 -->
					<transactionManager type="JDBC"/>
					<!-- 資料源配置:driver, url, username, password -->
					<dataSource type="POOLED">
						<property name="driver" value="${jdbc.driver}"/>
						<property name="url" value="${jdbc.url}"/>
						<property name="username" value="${jdbc.username}"/>
						<property name="password" value="${jdbc.password}"/>
					</dataSource>
				</environment>
			</environments>
			
			<!-- 配置映射檔案 -->
			<mappers>
				<!-- 通過包掃描DAO接口的方式批量加載映射檔案 -->
				<package name="cn.baidu.dao"/>
			</mappers>
		</configuration>

		2.5.測試類
		package mybatis2;

		import java.io.InputStream;

		import org.apache.ibatis.io.Resources;
		import org.apache.ibatis.session.SqlSession;
		import org.apache.ibatis.session.SqlSessionFactory;
		import org.apache.ibatis.session.SqlSessionFactoryBuilder;
		import org.junit.Before;
		import org.junit.Test;

		public class MyTest {
			
			private SqlSessionFactory sqlSessionFactory;
			
			// 測試初始化函數
			@Before
			public void init() throws Exception {
				// 讀取配置檔案
				InputStream inputStream = Resources.getResourceAsStream("MyBatisConfig.xml");
				// 根據主配置檔案建立會話工廠
				sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			}

			// 測試通過接口加載與之對應的映射檔案
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = null;
				try {
					sqlSession = sqlSessionFactory.openSession();
					// 建立DAO的動态代理對象
					
					// 執行資料庫操作
					
				} catch(Exception ex) {
					ex.printStackTrace();
					throw ex;
				} finally {
					sqlSession.close();
				}
			}
		}

		3.進階輸入映射(重點)
		3.1.綜合查詢

		綜合查詢在實際業務需求中十分常見。綜合查詢頁面往往是包含多種查詢次元的條件,比如上面的截圖就是淘寶的訂單查詢頁面。我們看到查詢訂單的條件包括:訂單基本資訊、使用者資訊、售後資訊。
		如果持久層使用MyBatis,應該如何接收參數呢? 
		3.1.1.需求
		查詢:使用者名是姓王的并且手機是135開頭的,訂單狀态是【待發貨】的訂單資訊。
		【SQL語句】有訂單又有使用者,SQL應該是一個關聯查詢:
		SELECT 
			o.orderId,
			o.userId,
			o.orderStatus,
			o.goodsId,
			o.createDateTime
		FROM
			order1 o,
			user u
		WHERE
			u.name LIKE '王%'
			AND u.mobile LIKE '135%'
			AND o.orderStatus = '02'
			AND o.userId = u.userId

		3.1.2.定義綜合查詢條件用POJO
		因為查詢條件是多元度的,它既不屬于使用者也不屬于訂單,是以不能用User.java和Order.java,需要重新定義一個包含User和Order的新POJO。
		通常我們把儲存查詢條件的pojo稱為QueryVo.java,其實就是普通的java bean。我們需要訂單基本資訊和使用者資訊作為條件進行查詢,是以其中包括了使用者資訊和訂單資訊。
		【QueryVo.java】
		public class QueryVo {
			// 使用者資訊
			private User user;
			
			// 訂單資訊
			private Order order;

			setter/getter。。。。。
		}
		上面需求中的SQL需要兩方面條件,一方面是訂單的,一方面是使用者的,是以可以在QueryVo中定義一個Order對象用于儲存訂單的查詢條件,再定義一個User對象用于儲存使用者的查詢條件。這樣不容易混亂也不容易出現名稱相似的屬性造成的不知道該用哪個。
		注意:我們不要把user的屬性和order的屬性條件混合到一起定義,這樣定義沒有錯,而且在參數映射時也簡單了,但是會讓Vo變得很混亂,分不清屬性誰是誰的。
		3.1.3.SQL映射檔案
		【OrderMapper.xml】
		<?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="cn.baidu.dao.OrderMapper">
			<!-- SQL -->
			<!-- 根據QueryVo查詢訂單資訊 -->
			<select id="findOrderByQueryVo" parameterType="cn.baidu.pojo.QueryVo"
				resultType="cn.baidu.pojo.Order">
				SELECT 
					o.orderId,
					o.userId,
					o.orderStatus,
					o.goodsId,
					o.createDateTime
				FROM
					order1 o,
					user u
				WHERE
					u.name LIKE #{user.name}
					AND u.mobile LIKE #{user.mobile}
					AND o.orderStatus = #{order.orderStatus}
					AND o.userId = u.userId
			</select>
		</mapper>

		3.1.4.定義接口
		【OrderMapper.java】
		package cn.baidu.dao;

		import cn.baidu.pojo.QueryVo;
		import cn.baidu.pojo.Order;

		public interface OrderMapper {
			
			// 根據綜合查詢條件查詢訂單資訊
			public Order findOrderByQueryVo(QueryVo vo) throws Exception;
		}

		3.1.5.用戶端測試程式
		【MyTest.java】
			// 測試根據QueryVo查詢訂單資訊
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				User user = new User();
				Order order = new Order();
				user.setName("王%");
				user.setMobile("135%");
				order.setOrderStatus("02");
				QueryVo vo = new QueryVo();
				vo.setOrder(order);
				vo.setUser(user);
				// 執行資料庫操作
				List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
				System.out.println(orderList);
				sqlSession.close();
			}
		<SQL映射規範>(需要掌握)
		·參數映射規範(四)
			傳多個參數并且是POJO包裝類型時,parameterType="pojo包裝pojo類型",占位符中的變量名等于Vo的屬性.屬性.屬性...,直到找到傳參屬性名為止。

		4.進階輸出映射(重點)
		按照傳回值映射的規範MyBatis可以将SQL結果集自動的生成指定類型的java對象,但是如果滿足不了傳回值映射的規範怎麼辦?簡單點說就是結果集列名與pojo中的屬性名不相等的時候我們怎麼做傳回值映射?
		解決的辦法:就是手動定義傳回值映射。
		4.1.需求
		根據訂單id查詢資料庫中order2表的訂單資訊。但order2表的最大問題就是字段名是以下劃線分割的,這與Order的pojo中的屬性名不一緻。
		4.2.手動定義傳回值映射
		4.2.1.定義傳回值映射
		【OrderMapper.xml】
		<說明>(需要掌握)
		項目	解釋
		<resultMap>	用于自定義傳回值映射的規則,即自定義哪個列名對應哪個屬性名。
		id	傳回值映射的唯一辨別
		type	傳回值映射中java對象的類型
		<result>	用于定義一個傳回值映射規範的标簽,一個<resultMap>可以包含多個<result>
		column	傳回值映射中的列名
		property	傳回值映射中的屬性名
		<id>	用于定義傳回值映射中主鍵列名與字段名的映射關系。用法和<result>一模一樣,隻是增加可讀性。
		<SQL映射示例>
			<!-- 自定義傳回值映射的規範 -->
			<resultMap type="cn.baidu.pojo.Order" id="order2ResultMap">
				<id column="order_id" property="orderId"/>
				<!-- <result column="order_id" property="orderId"/> -->
				<result column="user_id" property="userId"/>
				<result column="order_status" property="orderStatus"/>
				<result column="goods_id" property="goodsId"/>
				<result column="create_date_time" property="createDateTime"/>
			</resultMap>
		自定義了規範,MyBatis就可以利用這個自定義規範進行傳回值映射了。
		4.2.2.SQL
		【OrderMapper.xml】
		<說明>(需要掌握)
		項目	解釋
		resultMap	引用傳回值映射的自定義規範
		<SQL映射示例>
			<!-- 根據id查詢order2表的訂單資訊 -->
			<select id="findOrder2ById" parameterType="String" resultMap="order2ResultMap">
				SELECT 
					order_id,
					user_id,
					order_status,
					goods_id,
					create_date_time
				FROM
					order2
				WHERE
					order_id = #{orderId}
			</select>

		4.2.3.接口
		【OrderMapper.java】
			// 根據id查詢訂單資訊
			public Order findOrder2ById(String orderId) throws Exception;

		4.2.4.用戶端測試程式
		【MyTest.java】
			// 測試根據id查詢訂單資訊
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				// 執行資料庫操作
				Order orderInfo = orderMapper.findOrder2ById("6d081184-433e-11e7-ab09-448a5b6dba5c");
				System.out.println(orderInfo); 
				sqlSession.close();
			}

		4.3.用SQL字段别名滿足傳回值映射規範
		利用SQL的字段可以定義别名的功能,滿足字段名與POJO屬性名相同的要求。
		4.3.1.SQL
		【OrderMapper.xml】
			<!-- 根據id查詢order2表的訂單資訊2 -->
			<select id="findOrder2ById2" parameterType="String" resultType="cn.baidu.pojo.Order">
				SELECT 
					order_id as orderId,
					user_id as userId,
					order_status as orderStatus,
					goods_id as goodsId,
					create_date_time as createDateTime
				FROM
					order2
				WHERE
					order_id = #{orderId}
			</select>

		4.3.2.接口
		【OrderMapper.java】
			// 根據id查詢訂單資訊2
			public Order findOrder2ById2(String orderId) throws Exception;

		4.3.3.用戶端測試程式
		【MyTest.java】
			// 測試根據id查詢訂單資訊
			@Test
			public void test2() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				// 執行資料庫操作
		//		Order orderInfo = orderMapper.findOrderById("6d081184-433e-11e7-ab09-448a5b6dba5c");
				Order orderInfo = orderMapper.findOrder2ById2("6d081184-433e-11e7-ab09-448a5b6dba5c");
				System.out.println(orderInfo);
				sqlSession.close();
			}

		5.動态SQL(重點)
		本章内容針對SQL映射,賦予SQL映射更加強大靈活的特性,讓SQL映射更能适應複雜多變的參數請求。是以本節内容比較雜,内容也較多,但每塊内容都相對獨立,不難掌握。
		5.1.1.動态SQL條件

		5.1.2.<if>标簽
		【OrderMapper.xml】
		<說明>(需要掌握)
		項目	解釋
		<if>	用于判斷它包含的SQL語句是否需要添加。
		test	判斷的邏輯條件,and表示與,or表示或,邏輯判斷為true是添加包含的SQL語句,false就忽略。
		<SQL映射示例>
			<!-- 根據動态條件查詢訂單資訊 -->
			<select id="findOrderByQueryVo2" parameterType="cn.baidu.pojo.QueryVo" 
				resultType="cn.baidu.pojo.Order">
				SELECT 
					o.orderId,
					o.userId,
					o.orderStatus,
					o.goodsId,
					o.createDateTime
				FROM
					order1 o,
					user u
				WHERE 1 = 1
					<if test="user.name != null and user.name != ''">
						AND u.name LIKE #{user.name}
					</if>
					<if test="user.mobile != null and user.mobile != ''">
						AND u.mobile LIKE #{user.mobile}
					</if>
					<if test="order.orderStatus != null and order.orderStatus != ''">
						AND o.orderStatus = #{order.orderStatus}
					</if>
					and o.userId = u.userId
			</select>

		【OrderMapper.java】
			// 根據動态查詢條件查詢訂單資訊
			public List<Order> findOrderByQueryVo2(CustomQueryVo vo) throws Exception;

		【MyTest.java】
			// 測試根據動态查詢條件查詢訂單資訊
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				User user = new User();
				Order order = new Order();
				user.setName("王%");
				user.setMobile("135%");
				order.setOrderStatus("02");
				QueryVo vo = new QueryVo();
				vo.setOrder(order);
				vo.setUser(user);
				// 執行資料庫操作
		//		List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
				List<Order> orderList = orderMapper.findOrderByQueryVo2(vo);
				System.out.println(orderList);
				sqlSession.close();
			}

		if标簽不僅僅用于動态條件,SQL中所有接收參數的部分都可以通過if判斷決定是否要追加,比如udate更新中可以實作更新項目的動态更新:
			<update id="updateUser" parameterType="cn.baidu.pojo.User">
				UPDATE user 
				SET
					<if test="name != null and name != ''">
						name = #{name}, 
					</if>
					<if test="mobile != null and mobile != ''">
						mobile = #{mobile}, 
					</if>
					<if test="sex != null and sex != ''">
						sex = #{sex}, 
					</if>
					<if test="age != null and age != ''">
						age = #{age}, 
					</if>
					<if test="address != null and address != ''">
						address = #{address},
					</if>
				WHERE
					userId = #{userId}
			</update>
		上面的示例是有缺陷的,這個等到後面的學習中會改進它,現在隻是讓大家看到if标簽不僅僅應用于where條件。
		5.2.完善動态SQL條件
		5.2.1.<where>标簽
		【OrderMapper.xml】
		<說明>(需要掌握)
		項目	解釋
		<where>	用于建構完整where條件的标簽,有了它就不需要寫where關鍵字了
		它還能夠去掉第一個條件前面的and或or,是以<where>可以和<if>标簽組合實作更完美的動态條件。
		<SQL映射示例>
			<!-- 根據動态條件查詢訂單資訊(改進) -->
			<select id="findOrderByQueryVo3" parameterType="cn.baidu.pojo.QueryVo" 
				resultType="cn.baidu.pojo.Order">
				SELECT 
					o.orderId,
					o.userId,
					o.orderStatus,
					o.goodsId,
					o.createDateTime
				FROM
					order1 o,
					user u
				<where>
					<if test="user.name != null and user.name != ''">
						AND u.name LIKE #{user.name}
					</if>
					<if test="user.mobile != null and user.mobile != ''">
						AND u.mobile LIKE #{user.mobile}
					</if>
					<if test="order.orderStatus != null and order.orderStatus != ''">
						AND o.orderStatus = #{order.orderStatus}
					</if>
					and o.userId = u.userId
				</where>
			</select>
		【OrderMapper.java】
			// 根據動态查詢條件查詢訂單資訊(改進)
			public List<Order> findOrderByQueryVo3(CustomQueryVo vo) throws Exception;
		【MyTest.java】
			// 測試根據動态查詢條件查詢訂單資訊
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				User user = new User();
				Order order = new Order();
				user.setName("王%");
				user.setMobile("135%");
				order.setOrderStatus("02");
				QueryVo vo = new QueryVo();
				vo.setOrder(order);
				vo.setUser(user);
				// 執行資料庫操作
		//		List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
		//		List<Order> orderList = orderMapper.findOrderByQueryVo2(vo); 
				List<Order> orderList = orderMapper.findOrderByQueryVo3(vo);
				System.out.println(orderList);
				sqlSession.close();
			}

		5.3.SQL代碼片段的複用
		5.3.1.定義可重用的SQL代碼段
		【OrderMapper.xml】把【findOrderByQueryVo2】和【findOrderByQueryVo3】中的條件提取出去:
		<說明>(需要掌握)
		項目	解釋
		<sql>	定義可共用SQL片段的标簽。将可共用的SQL片段(可以包含其他動态标簽)包含在<sql></sql>中間
		id	這個共用SQL片段的唯一辨別
		<SQL映射示例>
			<!-- 訂單資訊的查詢條件 -->
			<sql id="order_query_condition">
				<if test="user.name != null and user.name != ''">
					AND u.name LIKE #{user.name}
				</if>
				<if test="user.mobile != null and user.mobile != ''">
					AND u.mobile LIKE #{user.mobile}
				</if>
				<if test="order.orderStatus != null and order.orderStatus != ''">
					AND o.orderStatus = #{order.orderStatus}
				</if>
			</sql>

		修改後的【findOrderByQueryVo2】和【findOrderByQueryVo3】
		<說明>(需要掌握)
		項目	解釋
		<include>	引用已經定義好的SQL片段
		refid	引用的SQL片段的id
		<SQL映射示例>
			<!-- 根據動态條件查詢訂單資訊 -->
			<select id="findOrderByQueryVo2" parameterType="cn.baidu.pojo.QueryVo" 
				resultType="cn.baidu.pojo.Order">
				SELECT 
					o.orderId,
					o.userId,
					o.orderStatus,
					o.goodsId,
					o.createDateTime
				FROM
					order1 o,
					user u
				WHERE 1 = 1
					<include refid="order_query_conditions"/>
					and o.userId = u.userId
			</select>
			
			<!-- 根據動态條件查詢訂單資訊(改進) -->
			<select id="findOrderByQueryVo3" parameterType="cn.baidu.pojo.QueryVo" 
				resultType="cn.baidu.pojo.Order">
				SELECT 
					o.orderId,
					o.userId,
					o.orderStatus,
					o.goodsId,
					o.createDateTime
				FROM
					order1 o,
					user u
				<where>
					<include refid="order_query_conditions"/>
					and o.userId = u.userId
				</where>
			</select>
		可以測試一下,結果仍然可以執行。
		5.4.動态多值SQL條件:foreach

		上面的螢幕尺寸是可以多選的。對于同一個條件可以選擇多個條件值的情況下如何處理?
		5.4.1.處理in條件
		比如根據多個訂單狀态查詢訂單資訊,我們需要傳遞多個訂單狀态。我們可以在查詢條件的pojo類QueryVo中添加一個List<String>類型的屬性,也可以直接傳遞List<String>類型的java對象。
		1.在QueryVo中定義List<String>類型的屬性:
		【QueryVo.java】
		public class QueryVo {
			。。。。。。。
			// 訂單狀态清單
			private List<String> orderStatusList;
			。。。。。。。

			/**
			 * @return the orderStatusList
			 */
			public List<String> getOrderStatusList() {
				return orderStatusList;
			}

			/**
			 * @param orderStatusList the orderStatusList to set
			 */
			public void setOrderStatusList(List<String> orderStatusList) {
				this.orderStatusList = orderStatusList;
			}
		}

		【OrderMapper.xml】
		<說明>(需要掌握)
		項目	解釋
		<foreach>	在參數映射中,用于循環周遊集合類型的參數。
		collection	表示要循環周遊的集合對象名稱
		item	每次周遊時使用的臨時變量名稱,在循環内部用占位符來引用
		separator	每次循環之間的分隔符号
		open	循環開始之前的SQL語句部分(可選)
		close	循環結束之後的SQL語句部分(可選)
		<SQL映射示例>
			<!-- 根據多個訂單狀态查詢訂單資訊(Vo中包裝List) -->
			<select id="findOrderByOrderStatus" parameterType="cn.baidu.pojo.QueryVo"
				resultType="cn.baidu.pojo.Order">
				SELECT 
					orderId,userId,orderStatus,goodsId,createDateTime
				FROM
					order1
				WHERE
					<!-- 不帶open和close屬性的形式 -->
					orderStatus in (
					<foreach collection="orderStatusList" item="orderStatus" separator=",">
						#{orderStatus}
					</foreach>
					)
					或者
					<foreach collection="orderStatusList" item="orderStatus" separator=","
						open="orderStatus in (" close=")">
						#{orderStatus}
					</foreach>
			</select>
		<SQL映射規範>(需要掌握)
		·參數映射規範(五)——<foreach>标簽專用
			處理集合參數,如果參數是parameterType="Pojo(包含List屬性)"時, <foreach>中collection必須是List屬性的變量名稱。

		【OrderMapper.java】
			// 根據多個訂單狀态查詢訂單資訊(Vo包裝List)
			public List<Order> findOrderByOrderStatus(CustomQueryVo vo) throws Exception;

		【MyTest.java】
			// 根據多個訂單狀态查詢訂單資訊(Vo包裝List)
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = null; 
				sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				List<String> orderStatusList = new ArrayList<String>();
				orderStatusList.add("01");
				orderStatusList.add("02");
				orderStatusList.add("03");
				QueryVo vo = new QueryVo();
				vo.setOrderStatusList(orderStatusList);
				// 執行資料庫操作
				List<Order> orderList = orderMapper.findOrderByOrderStatus(vo);
				System.out.println(orderList); 
				sqlSession.close();
			}

		2.直接傳遞List:
		【OrderMapper.xml】
			<!-- 根據多個訂單狀态查詢訂單資訊2(直接傳遞List) -->
			<select id="findOrderByOrderStatus2" parameterType="java.util.List"
				resultType="cn.baidu.pojo.Order">
				SELECT 
					orderId,userId,orderStatus,goodsId,createDateTime
				FROM
					order1
				WHERE
					<foreach collection="list" item="orderStatus" separator=","
						open="orderStatus in (" close=")">
						#{orderStatus}
					</foreach>
			</select>
		<SQL映射規範>(需要掌握)
		·參數映射規範(六)——<foreach>标簽專用
			處理集合參數,如果參數是parameterType="List"時,<foreach>中collection屬性值必須是list(必須小寫,不能變)

		【OrderMapper.java】
			// 根據多個訂單狀态查詢訂單資訊2(直接傳遞List)
			public List<Order> findOrderByOrderStatus2(List<String> statusList) throws Exception;

		【MyTest.java】
			// 根據多個訂單狀态查詢訂單資訊1(Vo包裝List)
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = null; 
				sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				List<String> orderStatusList = new ArrayList<String>();
				orderStatusLis.add("01");
				orderStatusLis.add("02");
				orderStatusLis.add("03");
				CustomQueryVo vo = new CustomQueryVo();
				vo.setOrderStatusList(orderStatusLis);
				// 執行資料庫操作
		//		List<Order> orderList = orderMapper.findOrderByOrderStatus1(vo);
				List<Order> orderList2 = orderMapper.findOrderByOrderStatus2(orderStatusLis);
				System.out.println(orderList2); 
				sqlSession.close();
			}
		5.4.2.or條件
		【OrderMapper.xml】
			<!-- 根據多個訂單狀态查詢訂單資訊3(or條件) -->
			<select id="findOrderByOrderStatus3" parameterType="java.util.List"
				resultType="cn.baidu.pojo.Order">
				SELECT 
					orderId,userId,orderStatus,goodsId,createDateTime
				FROM
					order1
				WHERE
					<foreach collection="list" item="orderStatus" separator="or">
						orderStatus = #{orderStatus}
					</foreach>
			</select>

		【OrderMapper.java】
			// 根據多個訂單狀态查詢訂單資訊3(or條件)
			public List<Order> findOrderByOrderStatus3(List<String> statusList) throws Exception;

		【MyTest.java】
			// 根據多個訂單狀态查詢訂單資訊
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = null; 
				sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				List<String> orderStatusList = new ArrayList<String>();
				orderStatusLis.add("01");
				orderStatusLis.add("02");
				orderStatusLis.add("03");
				CustomQueryVo vo = new CustomQueryVo();
				vo.setOrderStatusList(orderStatusLis);
				// 執行資料庫操作
		//		List<Order> orderList = orderMapper.findOrderByOrderStatus1(vo);
		//		List<Order> orderList2 = orderMapper.findOrderByOrderStatus2(orderStatusLis); 
				List<Order> orderList3 = orderMapper.findOrderByOrderStatus3(orderStatusLis);
				System.out.println(orderList3); 
				sqlSession.close();
			}

		5.5.小結
		上面的動态标簽: <if>, <where>, <sql>, <foreach>無論你如何使用我們始終要記住一個宗旨:
			保證動态形成的SQL語句的文法正确
		隻要你能包裝SQL文法正确, 你就可以靈活的使用這些動态标簽實作你自己的動态SQL。
		6.關聯查詢結果(重點)
		6.1.商品訂單資料模型


		注意:這裡面兩個表的關聯都是由SQL控制的,跟MyBatis一點關系都沒有,現在我們面臨的問題就是怎樣把具有關聯關系的結果集通過結果集映射傳回給Java程式。
		6.2.一對一查詢結果集
		6.2.1.SQL語句
				SELECT	
					o.orderId,
					o.goodsId,
					o.orderStatus,
					u.name,
					u.address,
					u.mobile
				FROM
					order1 o,
					user u
				WHERE
					o.userId = u.userId
					AND o.orderId = '52076fa9-433e-11e7-ab09-448a5b6dba5c'

		6.2.2.修改訂單POJO
		如果查詢結果中包含使用者資訊,就需要在Order.java pojo中增加User類型的屬性,然後把使用者資訊儲存在這個User屬性中。
		package cn.baidu.pojo;

		/**
		 * 訂單資訊POJO
		 * 
		 * @author Derek Sun
		 *
		 */
		public class Order { 
			
			private String orderId;

			private Integer userId;

			private String orderStatus;

			private String goodsId;

			private Date createDateTime;
			
			private User user;

			 。。。。。。
		}
		在實際業務中可能不僅僅包含使用者資訊,還可能有訂單對應的商品資訊、物流資訊等等。
			由于查詢結果中需要包含一個User類型的對象,這樣的結果集結構比較複雜,是以需要我們手動定義傳回值映射,這就需要ResultMap發揮作用的時候了。
		需要在定義傳回值映射時在ResultMap中定義一個User類型的對象,并把屬于使用者的查詢結果映射給User對象的屬性。
		6.2.3.ResultMap中定義POJO對象
		【OrderMapper.xml】
		<說明>(需要掌握)
		項目	解釋
		<association>	用于在ResultMap标簽中定義POJO對象 
		property	定義的POJO對象名稱(注意:名稱不能随便命名,必須符合傳回值映射規範)
		javaType	定義的POJO對象的類型
		<SQL映射示例>
			<!-- 一對一查詢結果集的傳回 -->
			<!-- 定義訂單綜合查詢結果與自定義訂單pojo屬性之間的對應關系 -->
			<resultMap type="cn.baidu.pojo.Order" id="orderResultMap1">
				<id column="order_id" property="orderId" />
				<result column="goods_id" property="goodsId" />
				<result column="order_status" property="orderStatus" />
				<association property="user" javaType="cn.baidu.pojo.User">
					<result column="name" property="name"/>
					<result column="address" property="address"/>
					<result column="mobile" property="mobile"/>
				</association>
			</resultMap>
			<!-- 根據訂單id查詢訂單綜合資訊(訂單基本資訊、所屬使用者資訊...) -->
			<select id="findOrderAndUserByOrderId" parameterType="string" 
				resultMap="orderResultMap1"> 
				SELECT	
					o.orderId,
					o.goodsId,
					o.orderStatus,
					u.name,
					u.address,
					u.mobile
				FROM
					order1 o,
					user u
				WHERE
					o.userId = u.userId
					AND o.orderId = #{id}
			</select>
		<SQL映射規範>(需要掌握)
		·傳回值映射規範(四)
			在<resultMap>中用<association>定義POJO對象,property的值必須等于<resultMap>的type指定的POJO中的屬性名。(一對一結果的映射)

		6.2.4.定義接口
		【OrderMapper.java】
			// 根據訂單id查詢訂單綜合資訊(訂單基本資訊、所屬使用者資訊...)
			public Order findOrderAndUserByOrderId(String orderId) throws Exception;
		6.2.5.用戶端測試程式
		【MyTest.java】
			// 測試根據訂單id查詢訂單綜合資訊(訂單基本資訊、所屬使用者資訊...)
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
				Order order = orderMapper.findOrderAndUserByOrderId("5f560c1e-433e-11e7-ab09-448a5b6dba5c");
				System.out.println(order);
				sqlSession.close();
			}

		6.2.6.擴充
		如果傳回多條一對一的查詢結果,該如何來做?
		1.SQL
		SELECT
			o.orderId,
			o.orderStatus,
			o.goodsId,
			u.userId,
			u.name,
			u.address
		FROM
			order1 o,
			user u
		WHERE
			o.userId = u.userId
			AND o.orderStatus = '02'

		2.POJO
		同【Order.java】
		3.接口定義
			// 根據訂單狀态查詢訂單綜合資訊(訂單基本資訊、所屬使用者資訊...)
			public List<Order> selectOrderAndUserByOrderStatus(String orderStatus) throws Exception;

		4.映射檔案
			<!-- 根據訂單狀态查詢訂單綜合資訊(訂單基本資訊、所屬使用者資訊...) -->
			<select id="selectOrderAndUserByOrderStatus" parameterType="String" 
				resultMap="customOrderResultType">
				SELECT
					o.orderId,
					o.orderStatus,
					o.goodsId,
					u.userId,
					u.name,
					u.address
				FROM
					order1 o,
					user u
				WHERE
					o.userId = u.userId
					AND o.orderStatus = #{status}
			</select>

		5.用戶端測試
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); 
				List<CustomOrder> orderList = orderMapper.selectOrderAndUserByOrderStatus("02");
				System.out.println(orderList);
				sqlSession.close();
			}
		執行結果:

		總結:無論是單條還是多條一對一結果,<resultMap> + <association>的組合都适用。association裡面還可以再嵌套association。

		6.3.一對多查詢結果集
		6.3.1.SQL語句
				SELECT 
					u.name,
					u.address, 
					u.mobile,
					o.order_id,
					o.order_status,
					o.goods_id
				FROM
					user u,
					order2 o
				WHERE
					o.user_id = u.userId
					AND u.userId = 1001	
		從SQL查詢的結果集上看使用者名和位址都是重複的,這個使用者相關的訂單資訊是多條不同的,這樣的結果集最終傳回到java對象中應該是一個使用者資訊,其中包含一個關于這個使用者的訂單資訊的List集合。
		6.3.2.修改使用者POJO
		如果查詢使用者結果中包含多個訂單資訊,就需要在User.java pojo中增加Order類型的List屬性,然後把屬于這個使用者多條訂單資訊儲存到List<Order>屬性中。
		package cn.baidu.pojo;

		import java.util.List;

		/**
		 * 使用者資訊POJO
		 * 
		 * @author Derek Sun
		 *
		 */
		public class User { 
			
			private String name;

			private int userId;
			
			private String mobile;
			
			private String sex;
			
			private int age;
			
			private String address;

			// 使用者訂單資訊清單
			private List<Order> orderList;

			 。。。。。。。
		}

		在實際業務中可能不僅僅包含訂單資訊,還可能有使用者信用度資訊、使用者消費額度資訊、推薦商品資訊清單等等。

		由于查詢結果中需要包含一個List<Order>類型的對象,這樣的結果集結構比較複雜,是以需要我們手動定義傳回值映射,這就需要ResultMap發揮作用的時候了。
		需要在定義傳回值映射時在ResultMap中定義一個List<Order>類型的對象,并把屬于這個使用者的訂單查詢結果映射給List<Order>對象。
		6.3.3.ResultMap中定義List對象
		【UserMapper.xml】
		<說明>(需要掌握)
		項目	解釋
		<collection>	用于在ResultMap标簽中定義List類型的對象 
		property	定義的List類型的對象名稱(注意:名稱不能随便命名,必須符合傳回值映射規範)
		ofType	List中泛型的類型,即List其中一個對象的類型
		<SQL映射示例>
			<!-- 一對多查詢結果集傳回 -->
			<!-- 定義使用者綜合查詢結果集與自定義使用者pojo屬性之間的對應關系 -->
			<resultMap type="cn.baidu.pojo.User" id="userResultMap">
				<result column="name" property="name" />
				<result column="address" property="address" /> 
				<result column="mobile" property="mobile"/>
				<collection property="orderList" ofType="cn.baidu.pojo.Order">
					<id column="order_id" property="orderId" />
					<result column="order_status" property="orderStatus" />
					<result column="goods_id" property="goodsId" />
				</collection>
			</resultMap>
			<!-- 根據使用者id查詢使用者綜合資訊(使用者基本資訊, 使用者訂單資訊....) -->
			<select id="findUserAndOrderByUserId" parameterType="int" resultMap="userResultMap">
				SELECT 
					u.name,
					u.address, 
					u.mobile,
					o.order_id,
					o.order_status,
					o.goods_id
				FROM
					user u,
					order2 o
				WHERE
					o.user_id = u.userId
					AND u.userId = #{id}
			</select>
		<SQL映射規範>(需要掌握)
		·傳回值映射規範(五)
			在<resultMap>中用<collection>定義List對象,property的值必須等于<resultMap>的type指定的POJO中的屬性名。(一對多結果的映射)

		6.3.4.定義接口
		【OrderMapper.java】
		package cn.baidu.dao;
		import cn.baidu.pojo.User;
		public interface UserMapper {
			// 根據使用者id查詢使用者綜合資訊(使用者基本資訊, 使用者訂單資訊....)
			public User findUserAndOrderByUserId(Integer id) throws Exception;
		}
		6.3.5.用戶端測試程式
		【MyTest.java】
			// 測試根據使用者id查詢使用者綜合資訊(使用者基本資訊, 使用者訂單資訊....)
			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
				User user = userMapper.findUserAndOrderByUserId(1001);
				sqlSession.close();
			}

		6.3.6.擴充
		如果傳回多條一對多的查詢結果,該如何來做?(多條一對多也可以了解成多對多,實際上多對多最終都是轉化成一對多來實作的。)
		1.SQL
		SELECT
			u.userId,
			u.name,
			u.mobile,
			o.orderId,
			o.orderStatus,
			o.goodsId
		FROM
			user u,
			order1 o
		WHERE
			u.userId = o.userId
			AND u.name LIKE '王%'

		2.POJO
		同【User.java】

		3.接口定義
			// 根據使用者名模糊查詢使用者綜合資訊(使用者基本資訊, 使用者訂單資訊....)
			public List<User> selectUserAndOrderListByUserName(String userName) throws Exception;

		4.映射檔案
			<!-- 根據使用者名模糊查詢使用者綜合資訊(使用者基本資訊, 使用者訂單資訊....) -->
			<select id="selectUserAndOrderListByUserName" parameterType="String"
				resultMap="userResultMap">
				SELECT
					u.userId,
					u.name,
					u.mobile,
					o.orderId,
					o.orderStatus,
					o.goodsId
				FROM
					user u,
					order1 o
				WHERE
					u.userId = o.userId
					AND u.name LIKE #{userName}
			</select>

		5.用戶端測試

			@Test
			public void test1() throws Exception {
				SqlSession sqlSession = sqlSessionFactory.openSession();
				// 建立DAO的動态代理對象
				UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
				List<User> userList = userMapper.selectUserAndOrderListByUserName("王%");
				sqlSession.close();
			}
		執行結果:

		總結:無論是單條還是多條一對多結果,<resultMap> + <collection>的組合都适用。collection裡面還可以再嵌套collection,但是一般沒有那麼複雜的資料結構。
		7.輸入輸出映射小結(重點)
		<SQL映射規範>(需要掌握)
		·參數映射規範
			1)傳單個參數時,parameterType="java簡單類型",占位符中的變量可以任意名稱,但不能沒有。
			2)傳單個參數時,parameterType="java簡單類型",拼接符中的變量名必須是value,也不能沒有。
			3)傳多個參數時,parameterType="pojo類型",占位符或拼接符的變量名必須等于pojo中的屬性名。
			4)傳多個參數并且是POJO包裝類型時,parameterType="pojo包裝pojo類型",占位符中的變量名等于Vo的屬性.屬性.屬性...,直到找到傳參屬性為止。
			5)<foreach>标簽專用——處理集合參數,如果參數是parameterType="Pojo(包含List屬性)"時, <foreach>中collection必須是List屬性的變量名稱。
			6)<foreach>标簽專用——處理集合參數,如果參數是parameterType="List"時,<foreach>中collection屬性值必須是list(必須小寫,不能變)。

		·傳回值映射規範
			1)傳回單值時,resultType="java簡單類型",值直接傳回給java程式。
			2)傳回單條記錄時,resultType="pojo類型",結果集的列名必須等于pojo的屬性名。
			3)傳回多條記錄時,resultType="集合的pojo泛型的類型",結果集列名必須等于pojo泛型的屬性名。
			4)在<resultMap>中用<association>定義POJO對象,property的值必須等于<resultMap>的type指定的POJO中的屬性名。(一對一結果的映射)
			5)在<resultMap>中用<collection>定義List對象,property的值必須等于<resultMap>的type指定的POJO中的屬性名。(一對多結果的映射)           

複制