mybatis深入浅出--高级知识实战

                        mybatis深入浅出--高级知识实战

 1数据库表分析

 数据模型分析思路

 

1、每张表记录的数据内容

         分模块对每张表记录的内容进行熟悉,相当 于你学习系统 需求(功能)的过程。

2、每张表重要的字段设置

         非空字段、外键字段

3、数据库级别表与表之间的关系

         外键关系

4、表与表之间的业务关系

         在分析表与表之间的业务关系时一定要建立 在某个业务意义基础上去分析

mybatis深入浅出--高级知识实战_第1张图片

用户表user:

         记录了购买商品的用户信息

订单表:orders

         记录了用户所创建的订单(购买商品的订单)

订单明细表:orderdetail:

         记录了订单的详细信息即购买商品的信息

商品表:items

         记录了商品信息

2 一对一查询

  1. resultType

    sql

SELECT

  orders.*,

  USER.username,

  USER.sex,

  USER.address

FROM

  orders,

  USER

WHERE orders.user_id = user.id

pojo

将上边sql查询的结果映射到pojo中,pojo中必须包括所有查询列名。

原始的Orders.java不能映射全部字段,需要新创建的pojo

创建 一个pojo继承包括查询字段较多的po类。

mybatis深入浅出--高级知识实战_第2张图片

mapper.xml

mybatis深入浅出--高级知识实战_第3张图片

mapper.java

2 resultMap

使用resultMap将查询结果中的订单信息映射到Orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中。

pojo

mybatis深入浅出--高级知识实战_第4张图片

mapper.xml


	
		
		
		
		
		
		
		
		
		
		
		
			
			
			
			
			
		
		
	

mybatis深入浅出--高级知识实战_第5张图片

mapper.java

 

     3resultType和resultMap实现一对一查询小结

 

实现一对一查询:

resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。

如果没有查询结果的特殊要求建议使用resultType。

resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。

resultMap可以实现延迟加载,resultType无法实现延迟加载。

3 一对多查询

1 sql

SELECT

  orders.*,

  USER.username,

  USER.sex,

  USER.address,

  orderdetail.id orderdetail_id,

  orderdetail.items_id,

  orderdetail.items_num,

  orderdetail.orders_id

FROM

  orders,

  USER,

  orderdetail

WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id

2存在的问题

使用resultType将上边的 查询结果映射到pojo中,订单信息的就是重复。

mybatis深入浅出--高级知识实战_第6张图片

要求:

对orders映射不能出现重复记录。

在orders.java类中添加List orderDetails属性。

最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中。

mybatis深入浅出--高级知识实战_第7张图片

映射成的orders记录数为两条(orders信息不重复)

每个orders中的orderDetails属性存储了该 订单所对应的订单明细。

3 po

mybatis深入浅出--高级知识实战_第8张图片

4 mapper.xml

mybatis深入浅出--高级知识实战_第9张图片

5 resultMap定义


	
		
		
		
		
		 
		 	
		 	
		 	
		 	
		 	
		 
	

6 mapper.java

7 小结

mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。

 

使用resultType实现:

将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。

4 多对多查询

1 需求

查询用户及用户购买商品信息

查询主表是:用户表

关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关联表:

orders、orderdetail、items

2 sql

SELECT 
  orders.*,
  USER.username,
  USER.sex,
  USER.address,
  orderdetail.id orderdetail_id,
  orderdetail.items_id,
  orderdetail.items_num,
  orderdetail.orders_id,
  items.name items_name,
  items.detail items_detail,
  items.price items_price
FROM
  orders,
  USER,
  orderdetail,
  items
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id

3 映射思路

将用户信息映射到user中。

在user类中添加订单列表属性List orderslist,将用户创建的订单映射到orderslist

在Orders中添加订单明细列表属性Listorderdetials,将订单的明细映射到orderdetials

在OrderDetail中添加Items属性,将订单明细所对应的商品映射到Items

4 mapper.xml

mybatis深入浅出--高级知识实战_第10张图片

5 resultMap定义


	
		
		
		
		
		
		
		
		 
		 	
		 	
			
			
			
			
			 
		  	
		  			
				 	
				 	
				 	
				 	
				 	
		  	 	
		  	 		
		  	 		
		  	 		
		  	 		
		  	 	
				 	
		  	  			  	
			
		 
		
	

6 mapper.java

5 小结

使用resultMap是针对那些对查询结果映射有特殊要求的功能,,比如特殊要求映射成list中包括 多个list。

resultType:

作用:

         将查询结果按照sql列名pojo属性名一致性映射到pojo中。

场合:

         常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。

resultMap:

         使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。

6 延迟加载

1 什么是延迟加载

resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。

需求:

如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。

2 使用association实现延迟加载

 1 需求

查询订单并且关联查询用户信息

 2 mapper.xml

需要定义两个mapper的方法对应的statement。

1、只查询订单信息

SELECT * FROM orders

在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)

2、关联查询用户信息

         通过上边查询到的订单信息中user_id去关联查询用户信息

         使用UserMapper.xml中的findUserById

上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。

3 延迟加载resultMap

使用association中的select指定延迟加载去执行的statement的id。


	
			
			
			
			
			
			
			
			
			
		
			
			
	

4 mapper.java

5 测试

1、执行上边mapper方法(findOrdersUserLazyLoading),内部去调用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查询orders信息(单表)。

2、在程序中去遍历上一步骤查询出的List,当我们调用Orders中的getUser方法时,开始进行延迟加载。

3、延迟加载,去调用UserMapper.xml中findUserbyId这个方法获取用户信息。

6 延迟加载配置

mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。

在mybatis核心配置文件中配置:

lazyLoadingEnabled、aggressiveLazyLoading

设置项

描述

允许值

默认值

lazyLoadingEnabled

全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。

true | false

false

aggressiveLazyLoading

当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。

true | false

true

在SqlMapConfig.xml中配置:

mybatis深入浅出--高级知识实战_第11张图片

7 测试代码

mybatis深入浅出--高级知识实战_第12张图片

7 查询缓存

1 什么是查询缓存

mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。

mybaits提供一级缓存,和二级缓存。

mybatis深入浅出--高级知识实战_第13张图片

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

 

二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

 

为什么要用缓存?

如果缓存中有数据就不用从数据库中获取,大大提高系统性能。

2 一级缓存

1 一级缓存工作原理

mybatis深入浅出--高级知识实战_第14张图片

第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。

得到用户信息,将用户信息存储到一级缓存中。

如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

2一级缓存测试

mybatis默认支持一级缓存,不需要在配置文件去配置。

按照上边一级缓存原理步骤去测试。

@Test
	public void testCache1() throws Exception{
		SqlSession sqlSession = sqlSessionFactory.openSession();//创建代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		//下边查询使用一个SqlSession
		//第一次发起请求,查询id为1的用户
		User user1 = userMapper.findUserById(1);
		System.out.println(user1);
		
//		如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
		
		//更新user1的信息
		user1.setUsername("测试用户22");
		userMapper.updateUser(user1);
		//执行commit操作去清空缓存
		sqlSession.commit();
		
		//第二次发起请求,查询id为1的用户
		User user2 = userMapper.findUserById(1);
		System.out.println(user2);
		
		sqlSession.close();
		
	}

3一级缓存应用

正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括 很多mapper方法调用。

service{
	//开始执行时,开启事务,创建SqlSession对象
	//第一次调用mapper的方法findUserById(1)
	
	//第二次调用mapper的方法findUserById(1),从一级缓存中取数据
	//方法结束,sqlSession关闭
}

如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。

3 二级缓存

 1 图解

mybatis深入浅出--高级知识实战_第15张图片

首先开启mybatis的二级缓存。

sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。

如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。

sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。

二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。

UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。

每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。

2 开启二级缓存

mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。

在核心配置文件SqlMapConfig.xml中加入

<setting name="cacheEnabled" value="true"/>

 

 

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache 进行全局性开/关设置。

true false

true

在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。

3 调用pojo类实现序列化接口

mybatis深入浅出--高级知识实战_第16张图片

为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。

4 测试方法

// 二级缓存测试
	@Test
	public void testCache2() throws Exception {
		SqlSession sqlSession1 = sqlSessionFactory.openSession();
		SqlSession sqlSession2 = sqlSessionFactory.openSession();
		SqlSession sqlSession3 = sqlSessionFactory.openSession();
		// 创建代理对象
		UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
		// 第一次发起请求,查询id为1的用户
		User user1 = userMapper1.findUserById(1);
		System.out.println(user1);
		
		//这里执行关闭操作,将sqlsession中的数据写到二级缓存区域
		sqlSession1.close();
		
		
		//使用sqlSession3执行commit()操作
		UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
		User user  = userMapper3.findUserById(1);
		user.setUsername("张明明");
		userMapper3.updateUser(user);
		//执行提交,清空UserMapper下边的二级缓存
		sqlSession3.commit();
		sqlSession3.close();
		
		

		UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
		// 第二次发起请求,查询id为1的用户
		User user2 = userMapper2.findUserById(1);
		System.out.println(user2);

		sqlSession2.close();

	}

5 useCache配置

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。