mybatis 高级映射和spring整合之高级映射
————————————————学习结构———————————————————— 0.0 对订单商品数据模型进行分析 1.0 高级映射 1.1 一对一查询 1.2 一对多查询 1.3 多对多查询 1.4 resultMap总结 1.5 延迟加载 2.0 查询缓存 2.1 一级缓存 2.2 二级缓存(了解mybatis二级缓存使用场景) 3.0 mybatis和spring整合(掌握) 4.0 逆向工程(会用)————————————————学习笔记详细————————————————0.0对订单商品数据模型进行分析 0.1.1每张表记录的数据内容 分模块对每张表记录的内容进行熟悉,相当于学习系统需求(功能)的过程。 0.1.2分析每张表重要字段即非空字段、外键 0.1.3数据库级别表于表之间的关系 外键关系 0.1.4表于表之间的业务关系 在分析表于表之间的业务关系时,一定要建立在某个意义基础上去分析。 0.2数据模型的分析( 可用工具PowerDesigner) 用户表:user 记录了购买商品的用户信息 id:自增主键 订单表:order 记录了用户所创建的订单(购买商品的订单) number:订单号 user_id(外键,用户id) 订单的明细表:orderdetall 记录了订单的详细信息即订单购买商品的信息 id:自增主键 orders_id(外键,订单id) items_di(外键,商品id) 商品表:items 记录了商品信息 id:自增主键 表于表之间的业务关系 在分析表于表之间的业务关系时需要建立在某个业务意义基础上去分析 分析数据库级别之间有关系的表之间的业务关系: user和oders: user--->orders:一个用户可以创建多个订单,一对多 orders--->user:一个订单只由一个用户创建,一对一 orders和orderdetall: orders--->orderdetall:一个订单可以包含多个订单明细,因为一个订单可以购买多个商品,而每个商品的购买信息,在orderdetall记录,一对多关系。 orderdetall--->orders:一个订单明细只能包含在一个订单中,一对一。 orderdetall和items: orderdetall--->items:一个商品明细只对于一个商品信息,一对一。 items--->orderdetall:一个商品信息可以包含在多个订单明细中,一对多。 在分析数据库级别没有关系的表之间是否有业务关系: orders和items: orders和items之间可以根据订单明细表orderdetall,所以是orders和items多对多。 user和items 多对多关系1.0 高级映射 1.1 一对一查询 1.1.1需求 查询订单信息,关联查询创建订单的用户信息。 1.1.2 用resultType实现 1.1.2.1 sql语句 SELECT orders.*,USER.username,USER.sex,USER.address FROM orders,USER WHERE orders.user_id=user.id 确定查询的主表:订单表 确定查询的关联表:用户表 关联查询使用内链接?还是外链接? 由于 orders表有外键(user_id),通过外键关联查询用户表只能查询出一条记录,可以使用内链接。 1.1.2.2创建pojo 将上边sql查询的结果集映射到pojo中,pojo中必须包含所有查询列名。 原始的Orders.java不能映射全部字段,需要新创建一个pojo。 创建一个pojo继承包括查询字段较多的po类。 //通过映射订单和用户查询的结果,让此类结果包括字段较多的pojo类 public class OrdersCustom extends Orders{ //添加用户属性 /**USER.username, USER.sex, USER.address*/ private String username; private String sex; private String address; } 1.1.2.3mapper.xml 1.1.2.4mapper.java public interface OrdersMapperCustom{ //查询订单关联查询用户信息 public ListfindOrdersUser()throws Exception; } 1.1.2.5测试 public void testFindOrdersUser() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); //创建代理对象 OrdersMapperCustom orderMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); //调用mapper的方法 List list = ordersMapperCustom.findOrdersUser(); system.out.println(list); sqlSession.close(); } 1.1.3 用resultMap实现 1.1.3.1 sql语句 同1.2.1 resultType实现的sql 1.1.3.2 使用resultMap映射的思路 使用resultMap将查询结果中的订单信息映射到orders对象中,在orders类中添加User属性 ,将关联查询出来的用户信息映射到orders对象中的user属性中。 需要Orders类中添加User属性 1.1.3.3需要Orders类中添加user属性 public class Orders{ private Integer userId; private String number; private Date createtime; private String note; //用户信息 private User user; } 1.1.3.4 mapper.xml 1.1.3.4.1 定义resultMap: 1.1.3.4.2 statement 的定义 1.2.6 resultMap 的定义 到 1.2.7 mapper.java //查询订单(关联用户)及订单明细 public ListfindOrdersAndOrderDetailResultMap()throws Exception; 1.2.8 测试 @Test public void testfindOrdersAndOrderDetailResultMap()throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); //创建代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class) //调用mapper的方法 List list = ordersMapperCustom.findOrdersAndOrderDetailResultMap(); system.out.println(list); sqlSession.close; } 1.2.9 一对多小结 mybatis 使用resultMap的 collection 对关联查询的多条记录映射到一个list集合属性中。 如果使用resultType实现: 将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。 1.3 多对多查询 1.3.1需求 查询用户及用户所购买的商品信息。 1.3.2 sql 语句 查询的主表:用户表 关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联。所以关联表:orders、orderdetail、items SELECT order.*, USER.username, USER.sex, USER.address, orderdetall.id orderdetall_id, orderdetall.items_di, orderdetall.items_num, orderdetall.order_id, items.name items_name, items.detail items_detail, items.price items_price FROM orders, USER, orderdetall, items WHERE order.user_id = user.id AND orderdetall.order_id = order.id AND orderdetail.items_id = items.id 1.3.3 映射思路 将用户信息映射到user中。 在user中添加订单列表的属性 List orderslist,将用户创建的订单映射到orderlist 在orders中添加订单明细列表属性List orderdetails,将订单的明细映射到orderdetails 在OrderDetail中添加items属性,将订单明细所对应的商品映射到items 1.3.4 mapper.xml 1.3.5 resultMap定义(重点) 1.3.6 mapper.java (接口) //查询用户购买商品信息 public List findUserAndItemsResultMap()throws Exception; 1.3.7 测试 @Test public void testfindUserAndItemsResultMap()throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); //创建代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class) //调用mapper的方法 List list = ordersMapperCustom.findUserAndItemsResultMap(); system.out.println(list); sqlSession.close; } 1.3.8 多对多总结 需求:将查询用户购买的商品信息明细清单(包含用户名、用户地址、购买商品名称、购买商品时间、购买商品数量) 针对上边的需求就使用resultType将查询到的记录映射到一个扩展的pojo中,很简单实现明细清单的功能。 一对多是多对多的特例,如下需求: 查询用户购买的商品信息,用户和商品的关系是多对多关系。 需求1: 查询字段:用户账号、用户名称、用户性别、商品名称、商品价格(常见) 企业开发中常见明细列表,用户购买商品明细列表 使用resultType将上边查询列表映射到pojo输出。 需求2: 查询字段:用户账号、用户名称、购买商品数量、商品明细(鼠标移上去显示明细) 使用resultMap将用户购买的商品明细映射到user对象中。 总结: 使用resultMap是针对那些查询结果有特殊要求的功能,比如特殊要求映射成list中包含多个list。 1.4 resultMap 总结: resultType: 作用: 将查询按照结果sql列名pojo属性名一致性映射到pojo中。 场合: 常见一些明细记录的展示,比如用户购买商品明细,将关联信息全部展示在页面时, 此时,可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。 resultMap: 使用association和collection完成一对一和一对多高级映射(对查询结果有特殊的映射要求)。 association: 作用: 将关联查询信息映射到一个pojo对象中。 场合: 为了方便关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中, 比如:查询订单及关联用户信息。 使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用 resultType还是resultMap。 collection: 作用: 将关联查询信息映射到一个list集合中。 场合: 为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如: 查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中, 将菜单列表映射到模块对象的菜单list属性中,这样做的目的也是方便对查询结果进行 遍历查询。 如果使用resultType无法将查询结果映射到list集合中。 1.5延迟加载 1.5.1 什么是延迟加载 resultMap可以实现高级映射(使用association、collection实现一对一、一对多映射),association、collection具备 延迟加载功能。 需求: 如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。 把对用户信息的按需去查询就是延迟加载。 延迟加载:先从单表查询、需要时再从关联表去查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。 1.5.2 使用association实现延迟加载 1.5.2.1 需求 查询订单并且关联用户信息。 1.5.2.2 mapper.xml 需要定义两个mapper的方法对应的statement。 1、只查询订单信息 SELECT * FROM orders 在查询订单的statement中使用association去延迟加载(执行)下边的statement(关联查询用户信息) 2、查询用户信息 通过上边查询到的订单信息中user_id去关联查询用户信息。 使用UserMapper.xml中的findUserByid 流程:上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过 resultMap的定义将延迟加载执行配置起来。 1.5.2.3 延迟加载resultMap 使用association中的select指定延迟加载去执行的statement的id。 1.5.2.4 mapper.java(接口) //查询订单关联查询用户,用户信息时延迟加载 public List findOrdersUserLazyLoading()throws Exception; 1.5.2.5 测试 测试思路: 1、执行上边mapper方法(findOrdersUserLazyLoading),内部去调用com.demo.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查询orders信息(单表)。 2、在程序中去遍历上一步骤查询出的List ,当我们调用Orders中的getUser方法时,开始进行延迟加载。 3、延迟加载,去掉用UserMapper.xml中findUserById这个方法获取用户信息。 1.5.2.6 延迟加载配置 在mybatis核心配置文件中配置: lazyLoadingEnable、aggressiveLazyLoading 设置项 描述 允许值 默认值 lazyLoadingEnable 全局性设置懒加载。如果设为 true 'false',则所有相关的都会被 false 初始化加载 false aggressiveLazyLoading当设置为’true‘的时候,懒加载true 对象可能被任何懒属性全部加载。 true 否则,每个属性都按需加载 false SqlMapConfig.xml 1.5.2.7 测试代码 OrdersMapperCustomTest.java //查询订单关联查询用户,用户信息使用延迟加载 @test public void testFindOrdersUserLazyLoading() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); //创建代理对象 OrdersMapperCustom orderMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class) //查询订单信息(单表) List list = ordersMapperCustom.findOrdersUserLazyLoading(); //遍历上边的订单列表 for(Orders orders:list) //执行getUser()去查询用户信息,这里实现按需加载 User user = orders.getUser(); System.out.println(user); } 1.5.2.8 延迟加载思考 不使用mybatis提供的association及collection中的延迟加载功能,如果实现延迟加载? 实现方法如下: 定义两个mapper方法: 1、查询订单列表 2、根据用户id查询用户信息 实现思路: 先去查询第一个mapper方法,获取订单信息列表 在程序中(service),按需去调用第二个mapper方法去查询用户信息。 总之: 使用延迟加载的方法,先去查询简单的sql(最好单表,也可以是关联查询),再去按需加载关联查询的其他信息。—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————