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

MyBatis框架之第二篇的更多相关文章

  1. Mybatis之旅第二篇-Mapper动态代理方式

    一.引言 通过上一篇mybatis的入门学习,我们已经会使用mybatis实现简单的增删改查,但是我们也发现了用原始Dao开发的一些问题: Dao方法体存在重复代码:通过SqlSessionFacto ...

  2. MyBatis框架之第一篇

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis.201 ...

  3. Lucene&Solr框架之第二篇

    2.1.开发环境准备 2.1.1.数据库jar包 我们这里可以尝试着从数据库中采集数据,因此需要连接数据库,我们一直用MySQL,所以这里需要MySQL的jar包 2.1.2.MyBatis的jar包 ...

  4. SpringMVC框架之第二篇

    6.参数绑定(重点) Springmvc作为表现层框架,是连接页面和service层的桥梁,它负责所有请求的中转.怎么从请求中接收参数是重点,这也体现了我们刚开始说的Springmvc的第一个作用:“ ...

  5. Django框架之第二篇--app注册、静态文件配置、form表单提交、pycharm连接数据库、django使用mysql数据库、表字段的增删改查、表数据的增删改查

    本节知识点大致为:静态文件配置.form表单提交数据后端如何获取.request方法.pycharm连接数据库,django使用mysql数据库.表字段的增删改查.表数据的增删改查 一.创建app,创 ...

  6. mybatis框架的第二天

    一.mybatis的基础crud的操作 先在接口中,写对应的方法名称,返回类型,访问符. 之后在映射配置文件中,写具体的实现 二.mybati中crud的细节 1.模糊查询 这是接口中 这是xml中 ...

  7. Java学习笔记——浅谈数据结构与Java集合框架(第二篇、Queue、Set)

    江南好,何处异京华. 香散翠帘多在水,绿残红叶胜于花.无事避风沙. --<纳兰词> 诗词再好,大图不能忘 上大图: 先说说栈和队列: 栈就好比手枪的弹匣,你往里面压入子弹,最先压入的子弹就 ...

  8. Django(三)框架之第二篇

    https://www.cnblogs.com/haiyan123/p/7717788.html 一.知识点回顾 1.MTV模型 model:模型,和数据库相关的 template:模板,存放html ...

  9. Django框架之第二篇

    一.知识点回顾 1.MTV模型 model:模型,和数据库相关的 template:模板,存放html文件,模板语法(目的是将变量如何巧妙的嵌入到HTML页面中). views:视图函数 另加urls ...

随机推荐

  1. 小白的springboot之路(九)、集成MongoDB

    0.前言 MongoDB是一个高性能.开源的文档型数据库,是当前nosql数据库中最热门的一种,在企业中广泛应用:虽然前段时间更改了开源协议导致被很多企业舍弃,但主要是对云服务商影响较大,对我们来说其 ...

  2. vue & nodejs jwt 的基于token身份验证

    现在比较流行的验证方式,是带着token的登录验证 原理 1. 登陆时,客户端发送用户名密码 2. 服务端验证用户名密码是否正确,校验通过就会生成一个有时效的token串,发送给客户端 3. 客户端储 ...

  3. Android开发模版代码(4)——状态栏设置

    下面的代码是基于开源项目SystemBarTint,我们需要添加其依赖 compile 'com.readystatesoftware.systembartint:systembartint:1.0. ...

  4. dataguard ORA-12514: TNS:listener does not currently know of service requested in connect descriptor

    错误的意思是listener 不知道连接解析器中的请求服务,这里要说静态监听和动态监听了动态注册是在instance启动的时候PMON进程根据init.ora中的instance_name,servi ...

  5. python--推倒式(列表、字典、集合)

    python的各种推导式(列表推导式.字典推导式.集合推导式) 推导式comprehensions(又称解析式),是Python的一种独有特性.推导式是可以从一个数据序列构建另一个新的数据序列的结构体 ...

  6. java之动态代理设计模式

    代理:专门完成代理请求的操作类,是所有动态代理类的父类,通过此类为一个或多个接口动态地生成实现类. 弄清动态代理的关键是清楚java的反射机制,在https://www.cnblogs.com/xix ...

  7. Git常用进阶操作之一

    提起Git,经常做项目的我们都不陌生,我们常用的功能有哪些呢? 这里按个人使用情况简单总结一下. 像新建远程仓库.新建分支这些就不说了,不熟的同学可以翻看我前面写的git基本操作. 1.首先提一下为每 ...

  8. strcmp函数和memcmp函数的用法区别及联系

    前言: C语言中有很多东西容易搞混,最近笔者就遇到了一个问题.这里做个记录.就是memcmp和strcmp两者的用法,这里做个对比: 功能对比: A memcmp: 函数原型: int memcmp( ...

  9. Cordova搭建,所遇到问题处理

    环境:NodeJs.[Android SDK | IOS] 安装:npm install -g cordova 过程: 1.创建一个项目:cordova create myApp 2.选择平台: co ...

  10. IT兄弟连 HTML5教程 CSS3属性特效 3D变换2

    3  perspective-origin景深基点 perspective-origin景深基点属性时3D变形中另一个重要属性,主要用来决定perspective属性的源点角度.它实际上设置了X轴和Y ...