mybatis高级查询
一对一查询
背景:现在有如下两张表,一张用户表(user)一张订单表(orders),因为一个用户可以有多个订单,所以用户表对订单表是一对多的关系;而订单对用户则是一对一的关系,在订单表中有用户表的外键uid,此外键指向用户表的主键id。
对应的User实体类:
public class User {
private long uid ;
private String username ;
private String password ;
private String name ;
private String email ;
private String phone ;
private String addr ;
private int state ;
private String code;
//省略setter getter方法
对应的Order实体类:
public class Orders {
private long oid;
private double total;
private Date orderTime;
private int state;
//省略setter getter方法
需求:查询主表Orders,关联查询User表。(一个订单属于一个用户)
主表:Orders
关联查询表:User
sql:
select orders.*,user.username,user.name,user.addr from orders,user where orders.uid = user.uid;
这里只关联User表查询username,name,addr三个属性。
1.使用resultType输出映射
因为使用resultType进行输出映射有个特点:就是从数据库查询出的列名要和映射到的pojo类的属性值一致。
这下该怎么办呢?Orders实体类中没有User实体类中的属性,User实体类中也没有Orders类中的属性。
解决办法:新建一个OrdersPojo继承Orders类,并在这个类中扩展username,name,addr这三个要查询的属性。
这里你肯定要问了,为什么要新建一个类?为什么要继承Orders类?
因为我们输出的pojo对象需要包括sql查询出的属性,这两个实体类中都没有完全包含这些输出属性,所以要新建一个pojo类来接收输出映射。继承Orders类的原因是因为主要查询的是Orders类,关联查询出的user类属性少,所以为了方便才继承Orders类。
OrderPojo 类映射输出类:
public class OrderPojo extends Orders{
private String username ;
private String name ;
private String addr ;
//省略setter getter方法
接下来要编写mapper.xml配置文件
<mapper namespace="com.mybatis.pojo.dao.OrderPojoDao">
<select id="queryOrders" resultType="com.mybatis.pojo.OrderPojo">
select orders.*
,user.username,user.name,user.addr
from orders,user where orders.uid =
user.uid;
</select>
</mapper>
Namespace指向mapper.java接口,输出映射是OrderPojo类
mapper接口:
public interface OrderPojoDao {
/***
* resultType:根据订单表管理查询用户表
*/
public List<OrderPojo> queryOrders();
}
注意:
1.namespace要是mapper.java接口的全路径.
2.id是方法名
3.输出映射是方法的返回值类型,这里用List,mybatis动态代理会自动调用selectList方法
4.输入映射是方法的参数,这里没有输入的参数,所以不用写。
测试类:
// 声明SqlSessionFactory
SqlSessionFactory sqlSessionFactory = null;
@Before
public void initFactory() throws Exception {
String resource = "sqlMapConfig.xml";
// 读取配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/***
* 测试resultType
*/
@Test
public void queryOrdersTest() {
// 声明SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderPojoDao orderPojoDao = sqlSession.getMapper(OrderPojoDao.class);
List<OrderPojo> list = orderPojoDao.queryOrders();
System.out.println(list.toString());
sqlSession.close();
}
输出结果:
框住的是新增的三个属性,并且都映射到了值;如图可见总共查询出8条记录,和上面sql查询结果一致,并且属性也都全部成功映射。
2.使用resultMap映射输出
目标:使用resultMap把映射结果映射到Orders类中。
1.因为映射到Orders类中,所以不用新建pojo类
2.因为查询关联user表,所以要在Orders类中添加User属性
Orders类:
public class Orders {
private long oid;
private double total;
private Date orderTime;
private int state;
// 关联User类
private User user;
//省略setter getter
}
这里主要使用resultMap规则:
1.先定义resultMap
2.输出类型是resultMap
配置文件:mapper.xml:
<!-- resultMap映射 -->
<resultMap type="com.mybatis.shopping.Orders" id="queryByResultMap">
<!-- 配置订单信息 -->
<id column="oid" property="oid" />
<result column="total" property="total" />
<result column="orderTime" property="orderTime" />
<result column="state" property="state" />
<!-- 配置映射的关联用户信息 -->
<association property="user" javaType="com.mybatis.shopping.User">
<id column="uid" property="uid" />
<result column="username" property="username" />
<result column="name" property="name" />
<result column="addr" property="addr" />
</association>
</resultMap>
<select id="queryOrdersResultMap" resultMap="queryByResultMap">
select orders.*
,user.username,user.name,user.addr
from orders,user where orders.uid =
user.uid;
</select>
association 用来映射单个pojo对象。
Mappper.java接口:
/***
* resultMap:根据订单表管理查询用户表
*/
public List<Orders> queryOrdersResultMap();
测试类:
@Test
public void queryOrdersResultMapTest() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderPojoDao orderPojoDao = sqlSession.getMapper(OrderPojoDao.class);
List<Orders> orderList = orderPojoDao.queryOrdersResultMap();
System.out.println(orderList);
}
由图可见,user属性已经被成功映射。
查询到的同样是8条数据,由图可见,username,name,addr都成功映射到user属性中了。
总结
ResultType:使用比较简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,才可完成映射。
ResultMap:需要单独定义,如果对查询结果又特殊要求,使用resultMap可以完成将管理查询映射到pojo属性中。
ResultMap可以实现延迟加载,resultType不能实现。
高级映射一对多
需求:查询订单及订单明细的信息。
主查询表:订单表
关联查询表:订单明细表
用户表和订单表的关系是一对多,订单表和订单明细表的关系也是一对多。现在以订单表为主表关联查询用户表和订单明细表。
sql:
select
orders.* ,user.username,user.addr,user.name,
orderitem.itemid,orderitem.count,orderitem.subtotal
from orders,user,orderitem where
orders.uid = user.uid and orderitem.oid
= orders.oid;
如图,查询主表orders关联查询user表和orderitem表的结果。
由图知道oid总共有三行,说明对应三个订单详情,而且oid=2的订单total是1849,恰好是三个订单项的subtotal的总和。
现在要求把订单项映射输出到ordes实体中,并映射成集合。
那么就需要在orders表中定义订单项的集合。
Oders.java:
public class Orders {
private long oid;
private double total;
private Date orderTime;
private int state;
// 关联User类
private User user;
// 订单项集合
private List<OrderItem> orderItems;
接下来编写mappe.xml程序:
由于是一对多的高级映射,这里采用resultMap的形式输出
<resultMap type="com.mybatis.shopping.Orders" id="queryOrdersAndOrderItem">
<!-- 配置订单信息 -->
<id column="oid" property="oid" />
<result column="total" property="total" />
<result column="orderTime" property="orderTime" />
<result column="state" property="state" />
<!-- 配置用户信息 -->
<association property="user" javaType="com.mybatis.shopping.User">
<id column="uid" property="uid" />
<result column="username" property="username" />
<result column="name" property="name" />
<result column="addr" property="addr" />
</association>
<!-- 配置订单条目集合信息 -->
<collection property="orderItems" ofType="com.mybatis.shopping.OrderItem">
<id column="itemid" property="itemid" />
<result column="count" property="count" />
<result column="subtotal" property="subtotal" />
</collection>
</resultMap>
<!-- 查询订单表,用户,订单明细表 -->
<select id="queryOrdersAndOrderItemAndUser" resultMap="queryOrdersAndOrderItem">
select
orders.* ,user.username,user.addr,user.name,
orderitem.itemid,orderitem.count,orderitem.subtotal
from orders,user,orderitem where
orders.uid = user.uid and orderitem.oid
= orders.oid;
</select>
collection :映射到集合。
Mapper.java接口
public List<Orders> queryOrdersAndOrderItemAndUser();
测试类:
@Test
public void queryOrdersAndOrderItemAndUserTest() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderPojoDao orderPojoDao = sqlSession.getMapper(OrderPojoDao.class);
List<Orders> list = orderPojoDao.queryOrdersAndOrderItemAndUser();
System.out.println(list);
}
输出:
有图可见,orderitem属性和user属性都被映射到了。
高级查询之多对多查询
需求:查询用户表购买的商品。
分析:因为用户和商品并没有直接关系,所以要查询用户购买的所有商品,则需要通过用户表和订单表的关系(一对多),订单表和订单项表的关系(一对多),订单项表和商品表的关系(一对一)来关联查询商品。
Sql语句:
select user.name,user.addr,orders.orderTime,orders.total,orders.oid,orderitem.itemid,orderitem.count,orderitem.subtotal,product.pid,product.pname,product.pdesc,product.shop_price
from orders,user,orderitem,product where orders.uid = user.uid and orders.oid = orderitem.oid and product.pid = orderitem.pid;
如下是查询结果:
‘’
需求:将查询到的结果集映射到User中输出。
什么意思呢,就是输出映射的pojo类型是User。
分析:由于我们知道用户表对订单表是一对多,要想把订单表信息映射到用户表中,则要在用户表中在添加一个订单表的集合;同理订单表对订单项是一对多,因此在订单表中也要添加订单项表的集合;因为订单项对商品是一对一,所以在订单项表中添加商品的引用,对应到mapper.xml中的association.
User.java:
public class User {
private long uid ;
private String username ;
private String password ;
private String name ;
private String email ;
private String phone ;
private String addr ;
private int state ;
private String code;
//订单表集合
private List<Orders> orders;
//省略setter getter
在Orders中添加orderIiem的集合
// 订单项集合
private List<OrderItem> orderItems;
在orderIiem中添加product的对象(他俩一对一)
orderIiem.java
public class OrderItem {
private long itemid;
private int count;
private double subtotal;
// 商品
private Product product;
//省略setter getter方法
mapper.xml:
<!-- 查询用户购买的商品 -->
<select id="queryUserAndProduct" resultMap="queryUserAndProductResultMap" >
select
user.name,user.addr,orders.orderTime,orders.total,orders.oid,orderitem.itemid,orderitem.count,orderitem.subtotal,product.pid,product.pname,product.pdesc,product.shop_price
from orders,user,orderitem,product where orders.uid = user.uid and
orders.oid = orderitem.oid and product.pid = orderitem.pid;
</select>
<!-- 输出类型是user -->
<resultMap type="com.mybatis.shopping.User" id="queryUserAndProductResultMap">
<id column="uid" property="uid" />
<result column="name" property="name" />
<result column="addr" property="addr" />
<collection property="orders" ofType="com.mybatis.shopping.Orders">
<id column="oid" property="oid" />
<result column="orderTime" property="orderTime" />
<result column="total" property="total" />
<!-- 嵌套collocation -->
<collection property="orderItems" ofType="com.mybatis.shopping.OrderItem">
<id column="itemid" property="itemid" />
<result column="count" property="count" />
<result column="subtotal" property="subtotal" />
<result column="count" property="count" />
<association property="product" javaType="com.mybatis.shopping.Product">
<id column="pid" property="pid" />
<result column="pname" property="pname" />
<result column="pdesc" property="pdesc" />
<result column="shop_price" property="shop_price" />
</association>
</collection>
</collection>
</resultMap>
mapper.java:
public List<User> queryUserAndProduct();
测试:
@Test
public void queryUserAndProductTest() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderPojoDao orderPojoDao = sqlSession.getMapper(OrderPojoDao.class);
List<User> userList = orderPojoDao.queryUserAndProduct();
System.out.println(userList);
}
成功映射