概述
ORM框架
ORM对象关系映射,是指完成数据库中的数据到程序对象的映射。原生的JDBC代码太臃肿,比如每次执行一个SQL语句需要链接和断开链接。查询出来的结果要手动映射到对象上等等,往往要写一大堆无用的代码,而ORM框架就是为了简化这些操作,ORM是对JDBC的封装。
常见的ORM框架
- Mybatis
- Hibernate
- Spring Data JPA等等
Mybatis和Hibernate
Hibernate和Mybatis都是ORM框架,Mybatis是一个半自动的ORM框架,Hibernate是一个全自动的ORM框架。HIbernate中是完全面向对象的,sql语句是根据对象和数据库映射生成的。而Mybatis中sql语句需要自己写,它主要是帮我们完成查询结果集的映射等。
为什么用Mybatis
mybatis整体更小巧拿来就可以用上手难度相对要低并且SQL语句更灵活
Hibernate移植性要比Mybatis更好
因为Hibernate面向的是对象来进行增删改查的,而Mybatis需要手写SQL可能会出现SQL语句中带有方言(只在特定的数据库中使用的语法)。
Mybatis和Hibernate的缓存
两者都是分两级缓存的,但Hibernate对查询语句有良好的管理机制用户无需关心SQL语句,出现脏读时也会即时报错。而Mybatis中很有可能出现脏读(其他Mapper中执行了一些增删改的操作导致Mapper中的数据变脏)
面试题
面试题:#{} 和${}的区别
${}是直接将数据拼接在SQL中而#{}是将数据做为字符串传入SQL中,采用的是预编译实现的。${}几乎没有办法防止SQL注入,而#{}可以很大程度上防止SQL注入。能使用#{}时优先使用#{}。${}一般用来传动态的表名和数据库名(传入前需要做相应的校验)
工作原理和流程
- 读取mybatis的config文件,配置mybatis对应的环境信息,比如数据库链接信息、是否开启驼峰命名、日志等等
- 读取各个mapper.xml映射文件,这里会为每个xml或者注解中的sql语句生成一个mappedstatement对象(这里面封装了sql语句、参数映射、结果映射等信息)
- 构建会话工厂sqlsessionfactory,mybatis根据配置信息构建出一个sqlsession的会话工厂
- 创建一个sqlsession会话对象。这个对象执行sql。sqlsession用来和数据进行交互,是一次和数据库的交互会话
- mybatis底层通过一个Executor执行器对mappedstatement进行解析,设置sql参数最后执行sql语句
- StatementHandler
- ParameterHandler
- ResultSetHandler
- 将结果映射为java中的map,list,实体类等存储结构
一级和二级缓存
mybatis的缓存使用顺序是:二级缓存—>一级缓存—>数据库
一级缓存
一级缓存是sqlsession级别的缓存,sqlsession在没有关闭和提交事务时会将查到的数据缓存起来。sqlsession之间的缓存是互不干扰的。
Spring在集成mybatis后通过动态代理对mybatis的sqlsession进行了增强,默认每次操作结束后都会执行commit。所以Spring+mybatis的情况下如果不开启事务,每次mapper的操作sqlsession都会直接提交。一级缓存就没有作用,在Spring中一级缓存只有在开启事务时才有用
二级缓存
二级缓存是Mapper级别的缓存,只要在同一个命名空间,sqlsession之间可以公用二级缓存。二级缓存默认是关闭的。二级缓存是在sqlsession提交后才会将数据同步到二级缓存中,未提交时数据会放入一个暂存区中,当sqlsession提交时才会将暂存区中的数据放入二级缓存中。
一个命名空间中因为使用了暂存区,所以不会出现数据脏读的问题。但由于多个命名空间之间是隔离的,mapper之间是存在脏读问题的
解决办法:在命名空间中将二级缓存指向另一个命名空间的二级缓存
只需要在对应的Mapper文件中,将该Mapper的命名空间引用另外一个Mapper的命名空间就可以使两个Mapper共用一个缓存空间!
<cache-ref namespace="xxx.xxx.xxx.UserMapper2"></cache-ref>
或者避免在不同的命名空间中对同一部分数据进行修改
Mybatis二级缓存脏读解决办法
- mapper中尽量单表操作
延迟加载的实现
延迟加载就是指mybatis会根据我们的需要来决定是否执行查询,比如一个用户持有多个账户,我们在没有使用他账户信息时就没有必要去把用户的账户查出来,当我们真正需要这部分数据时才去执行查询。一般使用在1对多或者多对多的情况下。
注意
在使用resultMap的情况下,并且配置了
实现原理
mybatis通过动态代理,创建目标对象的代理对象,拦截延迟加载的对象,当对象使用