1、什么是MyBatis?
(1)MyBatis是一个对象关系映射框架,内部封装了JDBC,开发时只需要注意SQL语句本身,不需要花费精力去处理加载启动、创建连接、创建statement等繁杂的过程。
(2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据中的记录,避免了几乎所有 JDBC 代码和手动设置参数以及获取结果集。
(3)MyBatis 可以使用 XML 或注解的方式将要执行的各种 statement 配置起来,并通过Java对象和 statement 中sql的动态参数进行映射生产最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。
2、说说MyBatis的优点和缺点
(1)优点
- 基于 SQL 语句编程,SQL 写在 XML 里,解除SQL 与程序代码的耦合,便于统一管理;提供 XML 标签,支持编写动态SQL,并重用。
- 简化 JDBC 配置和代码量,消除大量冗余的代码。
- 兼容性好,由于Mybatis通过JDBC连接数据库,主要是JDBC支持的数据库。
- 与Spring很好的集成。
- 提供映射标签,支持对象与数据库的对象字段关系映射,提供对象关系映射标签,支持对象关系组件维护。
(2)缺点 - SQL编写量大。
- SQL依赖于数据库,导致数据库移植性差,不能随意更换数据库。
3、#{}和${}的区别是什么?
- #{}: 预编译处理,会将sql中的#{}替换为 ?号,调用PreparedStatement的set方法赋值,使用#{}有助于防止SQL注入,提高系统安全性。
- ${}: 字符串替换,将${}替换成变量的值。
4、当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
第 1 种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
<select id=”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
</select>
第 2 种: 通过来映射字段名和实体类属性名的一一对应的关系。
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<id property=”id” column=”order_id”>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
5、Mybatis是如何进行分页的?分页插件的原理是什么?
MyBatis使用 RowBounds
对象进行分页,是针对 ResultSet 结果集执行的内存分页,而非物理分页。可以在 SQL 内直接拼写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页,例如:使用 limit 关键字分页。
分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect,添加对应的物理分页语句和物理分页参数。
6、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
(1)使用标签: 逐一定义数据库列名和对象属性名之间的映射关系。
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<id property=”id” column=”order_id”>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
(2)使用sql列的别名功能,将列的别名书写为对象属性名
<select id=”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
</select>
注意:没有映射关系的属性,无法完成对象赋值
7、如何执行批量插入?
第 1 种: Java程序循环执行插入方法
第 2 种: mapper 中添加<foreach> 标签,但要开启提交事务保证安全性。
8、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
XML映射文件中的标签有:
- select
- insert
- update
- delete
- if
- foreach
- sql(复用sql片段)
- set
- when
- otherwise(就是switch)
- choose(可以用where)
- trim(截断添加)
- prefix: 在前面添加内容
- suffix: 在后面添加内容
- prefixOverrides: 去掉前面内容
- suffixOverrides: 去掉后面内容
- bind(模糊查询,可以用CONCAT()函数)
- name: 参数名
- value: 模糊参数规则
9、MyBatis实现一对一有几种方式?具体怎么操作的?
有 联合查询 和 嵌套查询。
联合查询: 几个表联合查询,只查询一次,通过在resultMap里面配置association节点配置一对一的类就可以完成。
嵌套查询: 先查询一个表,根据这个表里面的结果的 外键Id,去另一个表里查询数据,也是通过 association 配置,但另外一个表的查询通过select属性配置。
10、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
Mybatis仅支持 association 关联对象和 collection 关联集合对象的延迟加载。
association 指的是一对一。
collection指的是一对多查询。
配置延迟加载: lazyLoadingEnabled=true | false
实现原理: 使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName(),拦截器 invoke() 发现 a.getB() 是 null ,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象、b属性都有值了,接着完成 a.getB().getName() 的调用。
11、说说Mybatis的缓存机制
Mybatis有二级缓存
(1)一级缓存LocalCache: 当我们使用相同SQL进行查询,MyBatis就会使用LocalCache进行缓存查询结果,当再次使用相同SQL,会先从一级缓存拉取结果,提高了性能。
特点:
- MyBatis 一级缓存的生命周期和 SqlSession一致(与会话存活相关)。
- MyBatis 一级缓存内部设计简单,是一个无限制大小的HashMap。
- MyBatis 的一级缓存最大范围是 SqlSession 内部,有多个 SqlSession 或者分布式的环境下,可能会引起在脏数据,建议设定缓存级别为 Statement。
(2)二级缓存共享缓存: 由于需要处理多SqlSession之间的共享数据,则需要耳机缓存,开启二级缓存后,会使用 CachingExecutor 修饰的 Executor,进入一级缓存的查询流程前,先进行二级缓存的查询。
注意:同一个 namespace 下的所有操作语句,都会影响同一个 Cache。
特定:
- 二级缓存更专注共享缓存数据,同时粒度更细,能够到 namespace 级别,通过Cache 接口实现类不同的组合,对 Cache 的可控性更强。
- 实现安全的二级缓存的条件比较苛刻。
- 在分布式环境下,Mybatis Cache 实现都是基于本地的,必然会出现读取到脏数据,徐还要使用 集中式缓存 将 Cache 接口实现,有一定的开发成本,直接使用 Redis、Memcached 等分布式缓存可能成本更低,安全性也更高。
12、JDBC 编程有哪些步骤?
(1)反射机制加载驱动
Class.forName("com.mysql.jdbc.Driver");
(2)建立 JDBC 和数据库之间的 Connection 链接
Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test/characterEncoding=UTF-8", "root", "123456");
(3)常见 Statement 或着 PreparedStatement 接口,执行SQL
(4)处理和现实结果
(5)释放资源
13、MyBatis 中见过什么设计模式?
- 建造者模式: SqlSessionFactoryBuilder,XMLConfigBuilder,XMLmAPPERBuilder,XMLStatementBuilder,CacheBuilder
- 单例模式: ErrorContext,LogFactory
- 代理模式: MyBatis实现的核心,比如MapperProxy,ConnectionLogger,用的JDK动态代理
- 组合模式: SqlNode和各子类ChooseSqlNode
- 模版方法模式: BaseExecutor 和 SimpleExecutor,还有BaseTypeHandler和所有子类
- 适配器模式: Log的Mybatis接口和对JDBC、log4j等各种日志框架的适配实现。
- 装饰者模式: Cache包中的cache.decorators自爆中各个装饰者的实现。
- 迭代器模式: PropertyTokenizer
- 工厂模式: SqlSessionFactory,ObjectFactory,MapperProxyFactory
14、MyBatis 中比如 UserMapper.java 是接口,为什么没有实现类还能调用?
使用了JDK动态代理+MapperProxy,本质上调用的是MapperProxy的invoke()。