企业网站有什么,建设部领导干部官方网站,电话营销网站建设,免费网络推广及优化一、多表查询#xff08;面试题#xff09;
1. 介绍
多表查询是在企业中必不可少的#xff0c;无论多么简单的项目里通常会出现多表查询的操作。因为只要是关系型数据库#xff0c;在设计表时都需要按照范式进行设计#xff0c;为了减少数据冗余#xff0c;都会拆成多个…一、多表查询面试题
1. 介绍
多表查询是在企业中必不可少的无论多么简单的项目里通常会出现多表查询的操作。因为只要是关系型数据库在设计表时都需要按照范式进行设计为了减少数据冗余都会拆成多个表。当需要多张表中数据时需要进行联合查询。
在MySQL学习时知道表之间关系分为一对一、一对多、多对多。这三种关系又细分为单向和双向。
如果学习的是Hibernate框架必须要严格区分开表之间的关系然后才能使用Hibernate框架。但是在MyBatis框架中只有两种情况当前表对应另外表是一行数据还是多行数据。转换到实体类上当前实体类包含其它实体类一个对象还是多个对象。
转换到MyBatis的映射文件上在resultMap标签里面使用association还是collection标签就可以。
所以在学习MyBatis多表查询时其实就是在学习association标签和collection标签。 如果一个实体类关联另一个实体类的一个对象使用association。 如果一个实体类关联一个实体类的List集合对象需要使用collection。 所以分析的思路是先分析需求-分析数据库设计对应关系-创建实体类-根据实体类关联属性类型决定使用哪个标签。
这两个标签根据编写的SQL分为N1查询和联合查询两种方式。
两种方式优缺点 联合查询方式
优点一次查询。
缺点SQL相对复杂。不支持延迟加载。
!-- 配置SQL映射的文件 --
mapper namespacecom.sh.mapper.EmpMapper !-- 联合查询 使用resultMap --resultMap ida typeEmp!-- 员工映射 --!-- 使用联合查询时,默认可以映射的也要进行手动映射--id columnid propertyid/result columnname propertyname/result columnaddr propertyaddr/result columndid propertydid/!-- 部门映射 --!--propertydept 哪个属性名javaType 联合查询返回的类型--!-- 除了集合的引用类型使用association --!-- 集合使用collection --association propertydept javaTypeDeptid columndept_id propertydept_id/result columndname propertydname//association/resultMap
select idqueryAll resultMapaselect id,name,addr,did,dept_id,dname from emp join dept wheredid dept_id
/select 业务装配 优点手动实现灵活度高。 缺点代码复杂。
一般不使用 N1方式
优点SQL简单。支持延迟加载。
缺点多做N次查询。
mapper namespacecom.sh.mapper.DeptMapper!-- 先根据部门id查询该部门的所有员工 --resultMap idb typeDeptid columndept_id propertydept_id/result columndname propertydname//resultMapselect idqueryById resultMapbselect * from dept where dept_id#{id}/select/mapper
!-- N1 查询 --!-- 那边DeptMapper要设置好--!-- 再正常查询 --resultMap idc typeEmpid columnid propertyid/result columnname propertyname/result columnaddr propertyaddr/result columndid propertydid/!-- 再使用association --!--select 连接的mapper映射文件column 相当于外键其实就是将两个mapper练了起来,按顺序执行--association propertydept javaTypeDept selectcom.sh.mapper.DeptMapper.queryById columndid/association/resultMapselect idqueryAll1 resultMapcselect * from emp/select/mapper 二、延迟加载面试题
延迟加载只能出现在多表联合查询的N1方式中。
表示当执行当前方法时是否立即执行关联方法的SQL。
1. 测试默认情况下效果
以EmpMapper接口的queryAllN1()方法进行举例当前方法的作用是查询全部Emp信息并且调用DeptMapper的queryById方法同时查询Dept的内容。
2. 启用延迟加载
配置延迟加载有两种方式
全局配置。整个项目所有N1位置都生效。
局部配置。只配置某个N1位置。
两种方式需要选择其中一种如果两种方式都使用了局部配置方式生效。
2.1 全局配置方式
官方文档全局设置属性说明
属性名解释说明可取值默认值lazyLoadingEnabled延迟加载的全局开关。当开启时所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
全局设置: settings!-- 开启驼峰转换 --setting namemapUnderscoreToCamelCase valuetrue/!--全局方式设置延迟加载全局设置后所有的能延迟加载的都会延迟加载即所有的N1都会使用延迟加载局部设置就是指定哪些不使用延迟加载--setting namelazyLoadingEnabled valuetrue//settings
局部设置:
局部配置方式需要在collection或association标签中配置fetchType属性。fetchType可取值lazy延迟加载和earge(立即加载)。
当配置了fetchType属性后全局settings的配置被覆盖对于当前标签以fetchType属性值为准。
resultMap idempMap2 typeEmpid columne_id propertyid/result columne_name propertyname/association propertydept javaTypeDeptselectcom.sh.mapper.DeptMapper.selectById columne_d_idfetchTypelazy/association
/resultMap
select idselectAllN1 resultMapempMap2select e_id,e_name,e_d_id from emp
/select
三、缓存面试题
1. 缓存介绍
缓存是一种临时存储少量数据至内存或者是磁盘的一种技术。减少数据的加载次数可以降低工作量提高程序响应速度缓存的重要性是不言而喻的。
MyBatis的缓存将相同查询条件的SQL语句执行一遍后所得到的结果存在内存或者某种缓存介质当中当下次遇到一模一样的查询SQL时候不在执行SQL与数据库交互而是直接从缓存中获取结果不再查询数据库提升了性能尤其是在查询多、缓存命中率越高的情况下使用缓存对性能的提高更明显。
MyBatis分为一级缓存和二级缓存同时也可配置关于缓存设置。 一级存储是SqlSession上的缓存。 二级缓存是在SqlSessionFactory(namespace)上的缓存。 默认情况下MyBatis开启一级缓存没有开启二级缓存。当数据量大的时候可以借助一些第三方缓存框架或Redis缓存来协助保存Mybatis的二级缓存数据。
2. 一级缓存
一级缓存是SqlSession级缓存。只要是同一个SqlSession对象必须是同一个调用同一个select标签相同参数值时不同select完全相同的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中。 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查询后缓存的数据。 二级缓存生效条件 同一个SqlSessionFactory对象。 同一个方法(select)。 SQL完全相同。
重要提示
二级缓存默认不开启需要手动开启。
只有当SqlSession执行commit或close时才会存储到二级缓存中。
下面演示配置二级缓存生效的步骤 全局开关在mybatis.xml文件中的settings标签配置开启二级缓存
settingssetting namecacheEnabled valuetrue/
/settings 2. 分开关在要开启二级缓存的mapper文件中开启缓存
使用cache/配置时注解的查询无法缓存。
mapper namespacecom.sh.mapper.EmpMappercache/
/mapper 3.二级缓存未必完全使用内存有可能占用硬盘存储缓存中存储的JavaBean对象必须实现序列化接口 二级缓存执行流程: 需要手动开启 全局设置: 在在mybatis.xml文件中的settings标签配置开启二级缓存 settings setting namecacheEnabled valuetrue/ /settings 局部配置: 在映射文件中通过cache/开启 标签中设置useCachefalse设置指定select标签不使用二级缓存 每一个映射文件对应着一个映射文件的二级缓存 有效范围同一个映射文件中的sql 1.根据调用的接口中的方法 select语句 ... 建立了缓存的 key 2.先从当前映射文件的二级缓存(真正存储二级缓存数据的集合:Cache接口实现类PerpetualCache的cache属性) [本质为map集合]中根据key获取对应数据 如果 没有: 1. 从一级缓存(localCache)中获取key对应的数据 没有:从数据库查询,将查询结果放入一级缓存中, 再添加到二级缓存的临时存储缓存数据的集合: Cache接口实现类TransactionalCache的entriesToAddOnCommit属性[本质为map集合]中,返回数据 有:返回一级缓存中的数据,并再二级缓存中添加,和上面一样 有:直接返回二级缓存中的数据 只有在执行了commit()close() 才会将临时缓存map集合(entriesToAddOnCommit中数据存储到真正存储缓存map集合(cache)中 注意 清除二级缓存的操作 防止出现脏读,幻读,可重复读的问题 添加修改删除
四、四大核心接口介绍及执行流程面试题
1. 四大核心接口介绍
MyBatis执行过程中涉及到非常重要的四个接口这四个接口为MyBatis的四大核心接口 Executor执行器执行器负责整个SQL执行过程的总体控制。默认SimpleExecutor执行器。 StatementHandler语句处理器语句处理器负责和JDBC层具体交互包括prepare语句执行语句以及调用ParameterHandler.parameterize()。默认是PreparedStatementHandler。 ParameterHandler参数处理器参数处理器负责PreparedStatement入参的具体设置。默认使用DefaultParameterHandler。 ResultSetHandler结果集处理器结果处理器负责将JDBC查询结果映射到java对象。默认使用DefaultResultSetHandler。
2. 四大核心接口对应的JDBC代码
对应的JDBC代码 3. 四大核心接口执行顺序按照下图进行执行 4. 通过断点测试执行流程
可以通过对四大核心接口的实现类中核心方法添加断点。
SimpleExecutor - doQuery() 方法必须以查询作为测试其他类型SQL使用不同方法
DefaultParameterHandler - setParameters
PreparedStatementHandler - query
DefaultResultHandler - handleResult
里面需要注意的是会在SimpleExecutor先实例化Statement对象然后调用DefaultParameterHandler 的setParameters再然后调用PreparedStatementHandler的query。
5. 完整执行流程文字说明
1使用执行器Executor控制整个执行流程
2实例化StatementHandler进行SQL预处理
3使用ParameterHandler设置参数
4使用StatementHandler执行SQL
5使用ResultSetHandler处理结果集
五、执行器类型面试题
MyBatis的执行器都实现了Executor接口。作用是控制SQL执行的流程。 BaseExecutor主要是使用了模板设计模式共性被封装在 BaseExecutor 中容易变化的内容被分离到了子类中 。 SimpleExecutor默认的执行器类型。每次执行query和updateDML都会重新创建Statement对象。 ReuseExecutor执行器会重用预处理语句。不会每一次调用都去创建一个新的 Statement 对象而是会重复利用以前创建好的如果SQL相同的话。 BatchExecutor用在updateDML操作中。所有SQL一次性提交。适用于批量操作。 CachingExecutor处理缓存的执行器。无论使用上面三种执行器中的哪个。都是会执行CachingExecutor。 在项目可以通过factory.openSession()方法参数设置执行器类型。通过枚举类型ExecutorType进行设置。
执行器主要控制的就是Statement对SQL如何进行操作。
有效范围同一个SqlSession对象。
1. SimpleExecutor
SimpleExecutor 是MyBatis默认的执行器类型。
2. ReuseExecutor
ReuseExecutor主要用在执行时重用预编译SQL。在同一个SqlSession对象中下次调用已经预编译的SQL直接设置参数。
3. BatchExecutor
BatchExecutor底层使用JDBC的批量操作。每一条SQL都不会立即执行而是放到了ListStatement中最终统一提交。
由于底层的批量操作只支持DML操作所以BatchExecutor也主要用在批量新增、批量删除、批量修改中。
六、MyBatis执行原理详解较常见面试题
对于MyBatis执行原理来说不同的情况有不同的执行过程大致可以分下面几种情况
1接口绑定方式、使用SqlSession执行方法。
2是否有插件。
3不同的执行器。
为了演示一个较为详细的执行流程。整个讲解过程中以SimpleExecutor作为执行器包含接口和映射文件的接口绑定方案同时带有自定义插件。其实就是上面自定义插件的代码。
MyBatis项目不能自动运行测试代码如下每一行都进入源码进行观察。
public class Test {public static void main(String[] args) throws IOException {InputStream is Resources.getResourceAsStream(mybatis.cfg.xml);SqlSessionFactory factory new SqlSessionFactoryBuilder().build(is);SqlSession session factory.openSession();EmpMapper empMapper session.getMapper(EmpMapper.class);MyPageHelper.startPage(0,2);ListEmp list empMapper.selectAllpage();System.out.println(list);//session.commit();session.close();}
}
8. MyBatis执行原理文字说明
首先加载全局配置文件为输入流交给XPathParser解析器解析为Document文档对象然后使用DOM解析Document文档对象把解析结果存放在Configuration配置类中。
通过DefaultSqlSessionFactory实例化工厂实例SqlSession的对象。创建了SqlSession接口的实现类DefaultSqlSession对象在创建过程中会同时创建Transaction事务对象、Executor执行器对象。如果当前项目有Interceptor拦截器创建执行器时会执行拦截器。
通过JDK提供的Proxy创建接口的动态代理对象。
可以通过接口的代理对象调用方法。在调用方法时MyBatis会根据方法的类型判断调用SqlSession的哪个方法。例如selectList、selectOne、update、insert等。
确定好具体调用SqlSession的哪个方法后会按照执行器类型执行MyBatis四大核心接口执行时也会触发拦截器Interceptor。最终会返回SQL的执行结果。
执行完方法后需要提交事务提交时清空缓存、清除存储的Statement对象。
最后关闭SqlSession对象释放资源。
以上就是MyBatis执行原理。