专栏首页海仔技术驿站MyBatis框架之第二篇

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中的属性名。(一对多结果的映射)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

推荐阅读

  • 远程办公经验为0,如何将日常工作平滑过度到线上?

    我是一名创业者,我的公司(深圳市友浩达科技有限公司)在2018年8月8日开始运营,现在还属于微型公司。这个春节假期,我一直十分关注疫情动向,也非常关心其对公司带来的影响。

    TVP官方团队
    TAPD 敏捷项目管理腾讯乐享企业邮箱企业编程算法
  • 数据中台,概念炒作还是另有奇效? | TVP思享

    作者简介:史凯,花名凯哥,腾讯云最具价值专家TVP,ThoughtWorks数据智能业务总经理。投身于企业数字化转型工作近20年。2000年初,在IBM 研发企业级中间件,接着加入埃森哲,为大型企业提供信息化架构规划,设计,ERP,云平台,数据仓库构建等技术咨询实施服务,随后在EMC负责企业应用转型业务,为企业提供云迁移,应用现代化服务。现在专注于企业智能化转型领域,是数据驱动的数字化转型的行业布道者,数据中台的推广者,精益数据创新体系的创始人,2019年荣获全球Data IQ 100人的数据赋能者称号,创业邦卓越生态聚合赋能官TOP 5。2019年度数字化转型专家奖。打造了行业第一个数据创新的数字化转型卡牌和工作坊。创建了精益数据创新方法论体系构建数据驱动的智能企业,并在多个企业验证成功,正在向国内外推广。

    TVP官方团队
    大数据数据分析企业
  • 扩展 Kubernetes 之 CRI

    使用 cri-containerd 的调用流程更为简洁, 省去了上面的调用流程的 1,2 两步

    王磊-AI基础
    Kubernetes
  • 扩展 Kubernetes 之 Kubectl Plugin

    kubectl 功能非常强大, 常见的命令使用方式可以参考 kubectl --help,或者这篇文章

    王磊-AI基础
    Kubernetes
  • 多种登录方式定量性能测试方案

    最近接到到一个测试任务,某服务提供了两种登录方式:1、账号密码登录;2、手机号+验证码登录。要对这两种登录按照一定的比例进行压测。

    八音弦
    测试服务 WeTest
  • 线程安全类在性能测试中应用

    首先验证接口参数签名是否正确,然后加锁去判断订单信息和状态,处理用户增添VIP时间事务,成功之后释放锁。锁是针对用户和订单的分布式锁,使用方案是用的redis。

    八音弦
    安全编程算法
  • 使用CDN(jsdelivr) 优化博客访问速度

    PS: 此篇文章适用于 使用 Github pages 或者 coding pages 的朋友,其他博客也类似.

    IFONLY@CUIT
    CDNGitGitHub开源
  • 扩展 Kubernetes 之 CNI

    Network Configuration 是 CNI 输入参数中最重要当部分, 可以存储在磁盘上

    王磊-AI基础
    Kubernetes
  • 聚焦【技术应变力】云加社区沙龙online重磅上线!

    云加社区结合特殊时期热点,挑选备受关注的音视频流量暴增、线下业务快速转线上、紧急上线防疫IoT应用等话题,邀请众多业界专家,为大家提供连续十一天的干货分享。从视野、预判、应对等多角度,帮助大家全面提升「技术应变力」!

    腾小云
  • 京东购物小程序购物车性能优化实践

    它是小程序开发工具内置的一个可视化监控工具,能够在 OS 级别上实时记录系统资源的使用情况。

    WecTeam
    渲染JavaScripthttps网络安全缓存

扫码关注云+社区

领取腾讯云代金券