阶段六-Day05-MyBatis3

一、多表查询(面试题)

1. 介绍

多表查询是在企业中必不可少的,无论多么简单的项目里通常会出现多表查询的操作。因为只要是关系型数据库,在设计表时都需要按照范式进行设计,为了减少数据冗余,都会拆成多个表。当需要多张表中数据时,需要进行联合查询。

在MySQL学习时,知道表之间关系分为:一对一、一对多、多对多。这三种关系又细分为单向和双向。

如果学习的是Hibernate框架,必须要严格区分开表之间的关系,然后才能使用Hibernate框架。但是在MyBatis框架中只有两种情况:当前表对应另外表是一行数据还是多行数据。转换到实体类上:当前实体类包含其它实体类一个对象还是多个对象。

转换到MyBatis的映射文件上:在标签里面使用还是标签就可以。

所以:在学习MyBatis多表查询时其实就是在学习标签和标签。

  1. 如果一个实体类关联另一个实体类的一个对象使用

  2. 如果一个实体类关联一个实体类的List集合对象,需要使用

  3. 所以分析的思路是:先分析需求->分析数据库设计对应关系->创建实体类->根据实体类关联属性类型决定使用哪个标签。

这两个标签根据编写的SQL,分为N+1查询和联合查询两种方式。

两种方式优缺点:

  • 联合查询方式:

优点:一次查询。

缺点:SQL相对复杂。不支持延迟加载。



    
    
        
        
        
        
        
        
        
        
        
        
        
            
            
        
    


  • 业务装配

    优点:手动实现,灵活度高。

    缺点:代码复杂。

一般不使用

  • N+1方式:

优点:SQL简单。支持延迟加载。

缺点:多做N次查询。


    
    
        
        
    
    


    
    

    
    
        
        
        
        
        
        
        
        
    
    

 

二、延迟加载(面试题)

延迟加载只能出现在多表联合查询的N+1方式

表示当执行当前方法时,是否立即执行关联方法的SQL。

1. 测试默认情况下效果

以EmpMapper接口的queryAllN1()方法进行举例:当前方法的作用是查询全部Emp信息,并且调用DeptMapper的queryById方法,同时查询Dept的内容。

2. 启用延迟加载

配置延迟加载有两种方式:

全局配置。整个项目所有N+1位置都生效。

局部配置。只配置某个N+1位置。

两种方式需要选择其中一种,如果两种方式都使用了,局部配置方式生效。

2.1 全局配置方式

官方文档全局设置属性说明:

属性名 解释说明 可取值 默认值
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false

全局设置: 

 
        
        
        
        
    

局部设置:

局部配置方式需要在collection或association标签中配置fetchType属性。fetchType可取值:lazy(延迟加载)和earge(立即加载)。

当配置了fetchType属性后,全局settings的配置被覆盖,对于当前标签以fetchType属性值为准。


    
    
    

三、缓存(面试题)

1. 缓存介绍

缓存是一种临时存储少量数据至内存或者是磁盘的一种技术。减少数据的加载次数,可以降低工作量,提高程序响应速度,缓存的重要性是不言而喻的。

MyBatis的缓存将相同查询条件的SQL语句执行一遍后所得到的结果存在内存或者某种缓存介质当中,当下次遇到一模一样的查询SQL时候不在执行SQL与数据库交互,而是直接从缓存中获取结果,不再查询数据库,提升了性能;尤其是在查询多、缓存命中率越高的情况下,使用缓存对性能的提高更明显。

MyBatis分为一级缓存和二级缓存,同时也可配置关于缓存设置。

  1. 一级存储是SqlSession上的缓存。

  2. 二级缓存是在SqlSessionFactory(namespace)上的缓存。

  3. 默认情况下,MyBatis开启一级缓存,没有开启二级缓存。当数据量大的时候可以借助一些第三方缓存框架或Redis缓存来协助保存Mybatis的二级缓存数据。

2. 一级缓存

一级缓存是SqlSession级缓存。只要是同一个SqlSession对象(必须是同一个)调用同一个完全相同的SQL不会走同一个缓存),将直接使用缓存数据,而不会访问数据库。

重要提示:

一级缓存想要生效,必须同时满足3个条件:

1. 同一个SqlSession对象

2. 同一个select标签。本质为底层同一个JDBC的Statemen对象。

3. 完全相同的SQL,包含SQL的参数值也必须相同。

4. insert、delete、update操作会清空一级缓存数据。

5. close(),commit也会清空一级缓存

2.1 一级缓存流程图

命中缓存:从Map中查询是否存在指定key。如果存在表示命中缓存,如果不存在这个key,需要访问数据库。

更新到缓存:把查询结果put到map中。

阶段六-Day05-MyBatis3_第1张图片

MyBatis中的缓存机制:
一级缓存执行流程: 默认开启
    1.根据调用的接口中的方法 + select语句 + ... + 建立了缓存的key
    2.从一级缓存(localCache的集合)中获取key对应的数据
        如果
        没有:从数据库中查询,将查询结果存储到一级缓存中
        (key,数据),返回查询到的数据
        有:直接返回一级缓存中获取到的数据
    3.一级缓存基于SqlSession,使用同一个SqlSession一级缓存生效
    也就是说多个用户访问时就不好使了

    注意:
        哪些操作可以清除一级缓存
        防止出现脏读,幻读,可重复读的问题
        1.commit() rollback()
        2.insert() update() delete()
        3.close()

3. 二级缓存

二级缓存是以namespace为标记的缓存,可能要借助磁盘,磁盘上的缓存,可以由一个SqlSessionFactory(单例设计模式,多个用户可以使用缓存)创建的SqlSession之间共享缓存数据,默认并不开启。下面的代码中创建了两个SqlSession,执行相同的SQL语句,尝试让第二个SqlSession使用第一个SqlSession查询后缓存的数据。

阶段六-Day05-MyBatis3_第2张图片

二级缓存生效条件:

  1. 同一个SqlSessionFactory对象。

  2. 同一个方法(