美文网首页java面试
Mybatis部分(重要)

Mybatis部分(重要)

作者: 久伴_不离 | 来源:发表于2019-05-27 15:58 被阅读0次

    1.mybatis 中 #{}和 ${}的区别是什么?

    1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".

    2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id,  如果传入的值是id,则解析成的sql为order by id.

    3. #方式能够很大程度防止sql注入。

    4.$方式无法防止Sql注入。

    5.$方式一般用于传入数据库对象,例如传入表名.

    6.一般能用#的就别用$.

    但是MyBatis排序时使用order by 动态参数时需要注意,用$而不是#


    2.mybatis 有几种分页方式? mybatis 分页插件的实现原理是什么?

    mybatis框架分页实现,有几种方式,最简单的就是利用原生的sql关键字limit来实现,还有一种就是利用interceptor来拼接sql,实现和limit一样的功能,再一个就是利用PageHelper分页插件来实现。这里讲解这三种常见的实现方式:无论哪种实现方式,我们返回的结果,不能再使用List了,需要一个自定义对象Pager。

    分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数


    3. Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

    第一种是使用<resultMap>标签,逐一定义数据库列名和对象属性名之间的映射关系。

    第二种是使用sql列的别名功能,将列的别名书写为对象属性名。

    有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。


    4.mybatis 逻辑分页和物理分页的区别是什么?

    Mybatis可以通过传递RowBounds对象,来进行数据库数据的分页操作,然而遗憾的是,该分页操作是对ResultSet结果集进行分页,这就是逻辑分页

    物理分页性能是最好的。下面就是物理分页的结果

    1. Sql中带有offset,limit参数,自己控制参数值,直接查询分页结果。

    2. 使用第三方开发的Mybatis分页插件。

    3. 修改Mybatis源码,给Sql追加自己的物理分页Subsql。

    1:逻辑分页 内存开销比较大,在数据量比较小的情况下效率比物理分页高;在数据量很大的情况下,内存开销过大,容易内存溢出,不建议使用

    2:物理分页 内存开销比较小,在数据量比较小的情况下效率比逻辑分页还是低,在数据量很大的情况下,建议使用物理分页


    5.mybatis 是否支持延迟加载?延迟加载的原理是什么?

    在mybatis 中默认没有使用延迟加载

    Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。

    它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

    当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。


    6.说一下 mybatis 的一级缓存和二级缓存?

    一级缓存:一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。

    二级缓存:二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。UserMapper有一个二级缓存区域(按namespace分),其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。对于查询多commit少且用户对查询结果实时性要求不高,此时采用mybatis二级缓存技术降低数据库访问量,提高访问速度。

    二级缓存性能不佳会造成问题:

        1)对该表的操作与查询都在同一个namespace下,其他的namespace如果有操作,就会发生数据的脏读。

        2)对关联表的查询,关联的所有表的操作都必须在同一个namespace。

    所以一般情况下 mybatis的二级缓存默认关闭不太使用


    7.mybatis 和 hibernate 的区别有哪些?

    相同点:屏蔽jdbc api的底层访问细节,使用我们不用与jdbc api打交道,就可以访问数据。jdbc api编程流程固定,还将sql语句与java代码混杂在了一起,经常需要拼凑sql语句,细节很繁琐。

    mybatis的好处:屏蔽jdbc api的底层访问细节;将sql语句与java代码进行分离;提供了将结果集自动封装称为实体对象和对象的集合的功能,queryForList返回对象集合,用queryForObject返回单个对象;提供了自动将实体对象的属性传递给sql语句的参数。

    Hibernate是一个全自动的orm映射工具,它可以自动生成sql语句,mybatis需要我们自己在xml配置文件中写sql语句,hibernate要比mybatis功能负责和强大很多。因为hibernate自动生成sql语句,我们无法控制该语句,我们就无法去写特定的高效率的sql。对于一些不太复杂的sql查询,hibernate可以很好帮我们完成,但是,对于特别复杂的查询,hibernate就很难适应了,这时候用mybatis就是不错的选择,因为mybatis还是由我们自己写sql语句。


    8.mybatis 有哪些执行器(Executor)?

    SimpleExecutor、ReuseExecutor、BatchExecutor。

    SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。

    ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。

    BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

    作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。


    9. MyBatis实现一对一有几种方式?具体怎么操作的? MyBatis实现一对多有几种方式,怎么操作的?

    一对一:

    有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置association节点配置一对一的类就可以完成;嵌套查询是先查一个表,根据这个表里面的结果的 外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。

    一对多:

    有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在resultMap里面的collection节点配置一对多的类就可以完成;嵌套查询是先查一个表,根据这个表里面的 结果的外键id,去再另外一个表里面查询数据,也是通过配置collection,但另外一个表的查询通过select节点配置。


    10.mybatis 如何编写一个自定义插件?

    1. 编写Interceptor的实现类 2. 使用@Intercepts注解完成插件签名 说明插件的拦截四大对象之一的哪一个对象的哪一个方法 3. 将写好的插件注册到全局配置文件中4大对象。

    1.Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)          --执行sql

    2.ParameterHandler (getParameterObject, setParameters)                     --获取、设置参数

    3.ResultSetHandler (handleResultSets, handleOutputParameters)          --处理结果集

    4.StatementHandler (prepare, parameterize, batch, update, query)          --记录sql


    11.简单介绍下你对MyBatis的理解?MyBatis中如何使用事务?MyBatis如何做对象关联? 

    1. MyBatis是一个数据持久层(ORM)框架。把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现。需要开发人员自己来写sql语句,程序更灵活,在一定程度上可以作为ORM的一种补充。数据库移植性差。便于统一管理与维护,降低了程序的耦合度

    2. Mybatis对于事务的支持不太好。需要手动开启JDBC事务进行事务管理。在整个请求处理之前,创建事务工厂,基于同一个SqlSession对象获得事务对象,期间执行多次数据库更新操作,最后捕捉异常,进行事务回滚或关闭。

    3. Mybatis的对象关联,分成:集合、关联

      一对多,多对多统称为集合。多对一,一对一统称为关联。

    不管是集合还是关联,都有两种实现方式:

    嵌套查询:分别编写两个查询sql,通过自定义resultMap中association或者collection标签的select引用,将查询嵌套起来

    嵌套结果:编写联表查询sql,查询出需要的多表中的数据,分别通过不同的resultMap进行映射,并在主resultMap的association或者collection标签的resultMap中,将结果映射嵌套起来

    嵌套查询可能会出现1+N次查询的问题,可以通过延迟加载来尽量减少性能的影响。嵌套结果会使查询数据过多,并且不能延迟加载。所以通常使用嵌套查询更多些。


    12.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?

    ① 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

    解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。

    ② Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

    解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

    ③ 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

    解决: Mybatis自动将java对象映射至sql语句。

    ④ 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

    解决:Mybatis自动将sql执行结果映射至java对象。


    13.MyBatis编程步骤是什么样的?

    ① 创建SqlSessionFactory

    ②通过SqlSessionFactory创建SqlSession

    ③ 通过sqlsession执行数据库操作

    ④ 调用session.commit()提交事务

    ⑤ 调用session.close()关闭会话


    14.使用MyBatis的mapper接口调用时有哪些要求?

    ①  Mapper接口方法名和mapper.xml中定义的每个sql的id相同

    ②  Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同

    ③  Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

    ④  Mapper.xml文件中的namespace即是mapper接口的类路径。


    16.SqlMapConfig.xml中配置有哪些内容?

    SqlMapConfig.xml中配置的内容和顺序如下: 

    properties(属性)

    settings(配置)

    typeAliases(类型别名)

    typeHandlers(类型处理器)

    objectFactory(对象工厂)

    plugins(插件)

    environments(环境集合属性对象)

    environment(环境子属性对象)

    transactionManager(事务管理)

    dataSource(数据源)

    mappers(映射器)


    17.Mapper编写有哪几种方式?

    ①接口实现类继承SqlSessionDaoSupport

            使用此种方法需要编写mapper接口,mapper接口实现类、mapper.xml文件

        1、在sqlMapConfig.xml中配置mapper.xml的位置

                <mappers>

                          <mapper resource="mapper.xml文件的地址" />

                           <mapper resource="mapper.xml文件的地址" />

                </mappers>

        2、定义mapper接口

        3、实现类集成SqlSessionDaoSupport

                mapper方法中可以this.getSqlSession()进行数据增删改查。

        4、spring 配置

            <bean id=" " class="mapper接口的实现">

                    <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>

             </bean>

    ②使用org.mybatis.spring.mapper.MapperFactoryBean

    1、在sqlMapConfig.xml中配置mapper.xml的位置

    如果mapper.xml和mappre接口的名称相同且在同一个目录,这里可以不用配置

    <mappers>

        <mapper resource="mapper.xml文件的地址" />

        <mapper resource="mapper.xml文件的地址" />

    </mappers>

    2、定义mapper接口

    注意

    1、mapper.xml中的namespace为mapper接口的地址

    2、mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致

    3、 Spring中定义

    <bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">

        <property name="mapperInterface"   value="mapper接口地址" />  

        <property name="sqlSessionFactory" ref="sqlSessionFactory" />  

    </bean>

    ③使用mapper扫描器

    1、mapper.xml文件编写,

    注意:

    mapper.xml中的namespace为mapper接口的地址

    mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致

    如果将mapper.xml和mapper接口的名称保持一致则不用在sqlMapConfig.xml中进行配置 

    2、定义mapper接口

    注意mapper.xml的文件名和mapper的接口名称保持一致,且放在同一个目录

    3、配置mapper扫描器

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

        <property name="basePackage" value="mapper接口包地址"></property>

        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 

    </bean>

    4、使用扫描器后从spring容器中获取mapper的实现对象

    扫描器将接口通过代理方法生成实现对象,要spring容器中自动注册,名称为mapper 接口的名称。


    18.Mybaits动态查询(动态SQL)

    有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。如果直接写静态的SQL语句,可能会引起SQL语句的报错,比如在where条件语句后面多了个,拼接等等,这时候就需要采用动态sql标签来拼接动态的SQl语句执行查询。Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。

    If条件:<if>元素被用来有条件地嵌入SQL片段,如果测试条件被赋值为true, 则相应地SQL片段将会被添加到SQL语句中。

    choose,when 和 otherwise 条件:有点类似于Java中的switch选择结构,我们【需要只使用其中一种】查询类别。

    Where 条件:所有的查询条件应该是可选的。在需要使用至少一种查询条件的情况下,我们应该使用WHERE子句。并且如果有多个条件,我们需要在条件中添加AND或OR。 MyBatis提供了<where>元素支持这种类型的动态SQL语句。

    <trim>条件:<trim>元素和<where>元素类似,但是<trim>提供了在添加前缀/后缀或者移除前缀/后缀方面提供更大的灵活性。

    foreach 循环:另外一个强大的动态SQL语句构造标签即是<foreach>。它可以迭代遍历一个数组或者列表,构造AND/OR条件或一个IN子句。

    set 条件:<set>元素和<where>元素类似,如果其内部条件判断有任何内容返回时,他会插入SET SQL 片段。


    19.如何获取自动生成的(主)键值?

    insert 方法总是返回一个int值 ,这个值代表的是插入的行数。

    如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。


    20.在mapper中如何传递多个参数?

    未完待续。。。。将不定时更新

    相关文章

      网友评论

        本文标题:Mybatis部分(重要)

        本文链接:https://www.haomeiwen.com/subject/wxmhtctx.html