十三、Mybatis

1、为什么要使用Mybatis,他有什么优点?
(1)传统JDBC开发存在的问题?MyBatis是如何解决这些问题的?
①频繁创建数据库连接对象、释放,容易造成系统资源浪费,影响性能。可以使用连接池解决这个问题。但是使用jdbc需要自己实现连接池。
解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库连接。
②实际项目中sql语句变化的可能性较大,一旦发生变化,需要修改java代码,系统需要重新编译,重新发布。不好维护。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。自动将java对象映射至sql语句
③结果集处理存在重复代码,处理麻烦。如果可以映射成Java对象会比较方便。
解决:Mybatis自动将sql执行结果映射至java对象。

2、请说说MyBatis的工作原理
在这里插入图片描述

3、为什么要预编译?
SQL预编译指的是数据库驱动在发送SQL语句和参数给DBMS之前对SQL语句进行编译,这样DBMS执行SQL时,就不需要重新编译。
预编译阶段可以优化SQL的执行。预编译之后的SQL多数情况下可以直接执行。同时预编译语句对象可以重复利用。把一个SQL预编译后产生的PreparedStatement对象缓存下来,下次对于同一个SQL,可以直接使用这个缓存的PreparedState对象。Mybatis默认情况下,将对所有的SQL进行预编译。

4、Mybatis都有哪些Executor执行器?它们之间的区别是什么?
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
(1)SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
(2)ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<string,statement="">内,供下一次使用。简言之,就是重复使用Statement对象。
(3)BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。

5、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()方法的调用。这就是延迟加载的基本原理。

***6、#{}和KaTeX parse error: Expected 'EOF', got '#' at position 13: {}的区别*** (1)#̲{}是占位符,预编译处理;{}是拼接符,字符串替换,没有预编译处理。
(2)Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值。
(3)Mybatis在处理KaTeX parse error: Expected 'EOF', got '#' at position 12: 时,是原值传入 (4)#̲{}可以有效的防止SQL注入,…{}不能防止SQL注入
(5)#{}的变量替换是在DBMS中;${}的变量替换是在DBMS外

7、Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

8、数据库怎么实现分页查询
分页查询其实就是限制输出和跳过输出的结合 SELECT * FROM table LIMIT M OFFSET N,其中LIMIT M OFFSET N可以写成LIMIT N, M

9、Statement与PreparedStatement的区别,什么是SQL注入,如何防止SQL注入?
1、PreparedStatement支持动态设置参数,Statement不支持。
2、PreparedStatement可避免如类似 单引号 的编码麻烦,Statement不可以。
3、PreparedStatement支持预编译,Statement不支持。
4、在SQL语句出错时PreparedStatement不易检查,而Statement则更便于查错。
5、PreparedStatement可防止SQL助于,更加安全,而Statement不行。
补充说明-什么是SQL注入以及应对策略: 通过SQL语句的拼接达到无参数查询数据库数据目的的方法。如将要执行的SQL语句为 select * from table where name = “+appName+”,利用appName参数值的输入,来生成恶意的SQL语句,如将[‘or’1’=‘1’] 传入可在数据库中执行。因此可以采用PrepareStatement来避免SQL注入,在服务器端接收参数数据后,进行验证,此时PrepareStatement会自动检测,而Statement不行,需要手工检测。

10、mybatis一级缓存和二级缓存
Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中;第二次以后是直接去缓存中取。
一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
二级缓存的使用原则
1.只能在一个命名空间下使用二级缓存
由于二级缓存中的数据是基于namespace的,即不同namespace中的数据互不干扰。在多个namespace中若均存在对同一个表的操作,那么这多个namespace中的数据可能就会出现不一致现象。
2.在单表上使用二级缓存
如果一个表与其它表有关联关系,那么久非常有可能存在多个namespace对同一数据的操作。而不同namespace中的数据互补干扰,所以就有可能出现多个namespace中的数据不一致现象。
3.查询多于修改时使用二级缓存
在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓存,对二级缓存的频繁刷新将降低系统性能。

11、mapper类方法可以重载吗
在mybatis框架中,写dao层的mapper接口时,是不可以进行方法的重载的,下面是截图证明:当mapper接口中有方法的重载时,会出现异常:
每个方法都有唯一的命名时,在xml中进行映射后,就可以执行,不会出现异常。
所以mybatis中mapper.xml是不会准确映射到Java中的重载方法的。最好不要在mapper接口中使用方法重载。

12、MyBatis模糊查询的三种拼接方式

  1. sql中字符串拼接
    SELECT * FROM tableName WHERE name LIKE CONCAT(CONCAT(’%’, #{text}), ‘%’);
  2. 使用 KaTeX parse error: Expected 'EOF', got '#' at position 10: {...} 代替 #̲{...} SELECT * …{text}%’;
    KaTeX parse error: Expected 'EOF', got '#' at position 17: …}解析过来的参数值不带单引号,#̲{}解析传过来参数带单引号。使…{}的拼接存在sql注入攻击的风险,例如例2中查询的是 1’ or 1=1 or '1就会返回所有数据,这只是个最简单的方式,而在java代码中先拼接好字符串然后#{text}传入能避免这个问题。
  3. 程序中拼接
    // or String searchText = “%” + text + “%”;
    String searchText = new StringBuilder("%").append(text).append("%").toString();
    parameterMap.put(“text”, searchText);
    SqlMap.xml
    SELECT * FROM tableName WHERE name LIKE #{text};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值