MyBatis的知识框架:
Mybatis是一款优秀的持久层框架,一个半 ORM(对象关系映射)框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Mybatis简介和原理介绍
MyBatis的缓存分为一级缓存和二级缓存,一级缓存放在session里面,默认就有,二级缓存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置。
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
Mybatis的配置 congfig mapper sql相关配置
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,支持延迟加载的原理都是一样的
Mybati缓存原理一级缓存和二级缓存
什么时候一级缓存有效:
1相同的SQL语句。2 会话级别的缓存必须是在相同的会话内。3必须是要相同的命令空间namespace。4必须是相同的方法。
5不能在执行clearCache。6不能执行updata insert delete语句。
MyBatis的二级缓存
使用的背景是:在静态表参数表 很少的修改的操作。先查找二级缓存 再来查找一级缓存。二级缓存不是默认开启的。
Mybatis一级缓存和二级缓存原理?
一级缓存:在开始创建一个mapper的时候就会回维护一个sqlsession的一个对象,这个对象就是一级缓存的,缓存的是一个map的键值对的集合。当再一次调用mapper的时候就不会在发送的sql语句了。就会访问mapper中的Sqlsession对象。二级缓存就是在SqlsessionFacatory中的。
Spring中为什么mybatis存在一级缓存失效?
接口的实例化的时候由底端代理对象来进行获取sqlsession对象,在spring对sqlsession的对象进行了屏蔽,对sqlsession这个对象进行了封装。在MyBatis中,使用sqlsessionFactory创建一个sqlsession。一旦有了会话,就可以使用它来执行Mapper的映射语句、提交或回滚连接,最后,当不再需要时,关闭会话。使用mybatis-spring,您不需要直接使用sqlsessionFactory,因为可以向bean注入一个线程安全的sqlsession,它根据spring的事务配置自动提交、回滚和关闭会话。
SQL的防止注入
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库。
1.寻找到SQL注入的位置
2.判断服务器类型和后台数据库类型
3.针对不通的服务器和数据库特点进行SQL注入攻击
解决方案:
1.#{}------ PreparedStatement:
采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
原理:sql注入只对sql语句的准备(编译)过程有破坏作用,而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,
而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.
#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
2.使用正则表达式过滤传入的参数 要引入的包:import java.util.regex.*;
正则表达式:
private String CHECKSQL = “^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$”;
判断是否匹配:
Pattern.matches(CHECKSQL,targerStr);
3.字符串过滤,比较通用的一个方法:(||之间的参数可以根据自己程序的需要添加)
public static boolean sql_inj(String str){
String inj_str = "'|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
String inj_stra[] = split(inj_str,"|");
for (int i=0 ; i < inj_stra.length ; i++ ){
if (str.indexOf(inj_stra[i])>=0){
return true;
}
}
return false;
}
4.jsp中调用该函数检查是否包函非法字符。
5.使用javascript在客户端进行不安全字符屏蔽。
Mybatis的怎么整合Spring的相关问题
1、Mybatis一级缓存的生命周期和SqlSession一致。
2、Mybatis的缓存没有更新缓存和缓存过期的概念,同时只是使用了默认的hashmap,也没有做容量上的限定。
3、Mybatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,有操作数据库写的话,会引起脏数据,建议是把一级缓存的默认级别设定为Statement,即不使用一级缓存。
Spring结合mybatis后,一级缓存作用:
在未开启事务的情况之下,每次查询,spring都会关闭旧的sqlSession而创建新的sqlSession,因此此时的一级缓存是不起作用的
在开启事务的情况之下,spring使用ThreadLocal获取当前资源绑定同一个sqlSession,因此此时一级缓存是有效的。
mybatis的一级缓存是基于session来的,当单独使用mybatis的时候,一级缓存是起作用的,在一个session中查询2遍同样的sql,只会打印一次sql语句。但当mybatis与spring搭配使用后,mybatis的一级缓存就会失效,会打印2次sql。
一级缓存失效原因:mybatis和spring结合使用的时候,将原本的DefaultSqlSession替换成了SqlSessionTemplate,并且在SqlSessionTemplate将sqlSession替换成了sqlSessionProxy代理对象,当我们执行sqlSession的方法的时会调用到SqlSessionInterceptor的invoke()方法, 在invoke()方法的fianlly中调用了SqlSessionUtils.closeSqlSession()方法将SqlSession关闭了,所以一级缓存就会失效了。
也就是说,spring对mybatis的SqlSession的使用是由SqlSessionTemplate控制的,在SqlSessionTemplate类中执行SQL语句的SqlSession都是通过sqlSessionProxy来代理执行的,sqlSessionProxy的生成是在构造函数中赋值。
spring通过mybatis调用数据库的过程如下:
1、需要访问数据
2、spring检查到了这种需求,去申请一个mybatis的sqlsession,并将申请到的sqlsession与当前线程绑定,放入threadlocal里面
3、template从threadlocal获取到sqlsession,去执行查询
4、查询结束,清空threadlocal中与当前线程绑定的sqlsession,释放资源
5、又需要访问数据
6、返回到步骤2
Mybatis中一级缓存的问题和解决方案
在mybatis的二级缓存中有命名空间的范围。当在多表的相关的操作的时候,可能存在和一个命名空间中的修改其他的数据的表,但是数据更新后的时候再去做查询的时候的结果为远端二级缓存的中的数据,会产生与数据的不一致的情况。
解决方案:
1 一张表中的不会在其他的命名空间做操作。也就是不会在做表与表的级联的操作。就可以使用二级缓存的就好。
2如果在设计dao中的可能设计到多表的级联的相关的操作。那就考虑好的处理。