MyBatis
什么是 MyBatis
- MyBatis 是一个半 ORM 框架,内部封装了 JDBC,使得开发时只需要关注 SQL 语句本身,不需要处理加载驱动、创建连接等复杂的过程
- 通过 XML 文件和注解配置,并通过 Java 对象和 statement 的动态参数进行映射,生成最终执行的 SQL 语句
- 最后由 Mybatis 框架执行 SQL 并将结果映射为 Java 对象并返回
ORM 是什么
- ORM,对象关系映射
- 把数据库表和实体类对应,通过操作实体类就实现操作数据库表
为什么说 MyBatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
- MyBatis 在查询关联对象或关联集合对象时,需要手动编写 SQL 来完成
JDBC 编程有哪些不足之处,MyBatis 是如何解决的?
- 数据库连接创建、释放频繁,会造成系统资源浪费
- MyBatis 通过线程池管理数据库连接,实现连接复用
- SQL 语句写在代码中,代码不容易维护
- MyBatis 将 SQL 语句放在配置文件或注解中
- 向 SQL 语句传参麻烦
- MyBatis 通过参数映射功能,将 Java 对象映射到 SQL 语句中
- 结果集解析麻烦
- MyBatis 通过结果集映射功能,将查询结果映射到 Java 对象中
MyBatis 编程步骤是什么样的?
- 读取配置文件,创建 SqlSessionFactory 工厂
- 通过 SqlSessionFactory 工厂创建 SqlSession 对象
- 使用 SqlSession 创建 Dao 接口的代理对象
- 使用代理对象执行方法
- 调用 session.commit() 提交事务
- 调用 session.close() 关闭会话
{}和 ${}的区别是什么?
#{} 预处理语句参数占位符:
- MyBatis 处理#{}时,会将其替换为?号,调用 set 方法赋值
- 可以防止 SQL 注入问题
${}文本替换:
- MyBatis 处理 ${}时,会直接使用字符串替换
- 容易出现 id 的类型不匹配问题和 SQL 注入攻击
当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
- 在 SQL 语句中定义数据库别名
- 通过
<resultMap>来映射字段名和实体类属性名的关系
模糊查询 like 语句该怎么写?
- 在 Java 代码中添加 SQL 通配符
string wildcardname = “%smi%”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like #{value}
</select>
- 在 SQL 语句中拼接通配符%,会引起 SQL 注入
string wildcardname = “smi”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like "%"#{value}"%"
</select>
MyBatis 都有哪些 Executor 执行器?它们之间的区别是什么?
MyBatis 有三种基本的 Executor 执行器,SimpleExecutor、ReuseExecutor、BatchExecutor
- SimpleExecutor :每次开启一个 Statement 对象,用完立刻关闭
- ReuseExecutor :重复使用创建的 Statement 对象
- BatchExecutor :缓存多个 Statement 对象,一起执行批量更新
通常一个 xml 映射文件,都会写一个 Dao 接口与之对应,Dao 接口的工作原理是什么?
- 定义接口: 定义 DAO 接口,其中包含与数据库操作相关的方法,如插入、更新、删除、查询等
- 实现接口: 针对 DAO 接口,创建实现类,这些实现类包含实际的数据库操作逻辑
- 映射文件: 使用 XML 文件,用于定义 Java 对象与数据库表的映射关系
- 配置: 在应用程序启动时,通过依赖注入或配置文件配置,将 DAO 接口与其对应的实现类进行关联
- 使用: 在应用程序中,当需要与数据库交互时,调用 DAO 接口中的方法,而不必关心实际的数据库操作细节。DAO 实现类会根据接口中定义的方法来执行相应的数据库操作,并将结果映射为 Java 对象返回
Dao 接口里的方法,参数不同时,方法能重载吗?
- Dao 接口里的方法可以重载
- 但是 MyBatis 的 XML 里面的 ID 不允许重复
MyBatis 是如何将 SQL 执行结果封装为目标对象并返回的?都有哪些映射形式?
- 使用
<resultMap>标签,自定义数据库列名和对象属性名之间的映射关系 - 使用 SQL 列的别名功能,将列的别名属性对应为对象属性名
在 mapper 中如何传递多个参数?
- 顺序传参法:#{} 里面的数字代表传入参数的顺序
- 注解传参法:#{} 里面的名称对应的是注解@Param 括号里面修饰的名称
- Map 传参:#{} 里面的名称对应的是 Map 里面的 key 名称
- Java Bean 传参法:#{} 里面的名称对应的是 User 类里面的成员属性
MyBatis 动态 SQL 有什么用?执行原理?有哪些动态 SQL?
- MyBatis 的动态 SQL 允许在 XML 映射文件中以标签的形式编写动态 SQL 语句,根据运行时的条件动态生成 SQL 语句,从而使得 SQL 查询更加灵活
- 执行原理是根据表达式的值完成逻辑判断并动态拼接 SQL
- MyBatis 提供了 9 种动态 SQL 标签: 常用的有 if | where | foreach
MyBatis 实现一对多有几种方式,怎么操作的?
有联合查询和嵌套查询
- 联合查询是几个表联合查询,只查询一次,通过在 resultMap 里面的 collection 节点配置一对多的类就可以完成
- 嵌套查询是先查一个表,根据这个表里面的结果的外键 id,去再另外一个表里面查询数据
MyBatis 是否支持延迟加载?如果支持,它的实现原理是什么?
- MyBatis 支持延迟加载
- MyBatis 的延迟加载是通过代理对象和懒加载的技术实现的:
- 代理对象: 当您从数据库查询一个对象时,MyBatis 不直接返回实际的对象,而是返回了一个代理对象。代理对象持有实际对象的引用,并且能够在需要时触发实际数据的加载
- 懒加载触发: 访问代理对象的某个属性时,MyBatis 会检查该属性是否已经加载。如果尚未加载,MyBatis 会发起相应的 SQL 查询以从数据库中获取数据
MyBatis 的一级、二级缓存
MyBatis 提供了两级缓存来优化数据库查询性能:一级缓存和二级缓存
- 一级缓存(本地缓存):
- 一级缓存是 MyBatis 默认开启的
- 在同一个 SqlSession 内部进行数据缓存的
- 在同一个 SqlSession 中,如果执行了相同的 SQL 语句,MyBatis 会将查询结果缓存在一级缓存中,下次访问相同 SQL 时,会直接从缓存中获取数据,而不再去查询数据库
- 一级缓存的生命周期是与 SqlSession 相关的,当 SqlSession 被关闭或者数据发生变更时,缓存会被清空
- 二级缓存(全局缓存):
- 二级缓存是在 SqlSessionFactory 层面进行数据缓存的
- 可以被多个 SqlSession 共享
- 二级缓存通常在应用程序的不同请求之间使用,或用于在不同的 SqlSession 之间共享数据,从而减少数据库访问
- 二级缓存默认是关闭的,需要进行配置开启
什么是 MyBatis 的接口绑定?有哪些实现方式?
MyBatis 的接口绑定是指将一个接口与一个或多个 XML 映射文件关联起来,从而可以通过接口方法来执行 SQL 语句,无需手动编写 SQL
- XML 映射文件
- 注解
- Mapper 接口代理
