1.什么是mybatis
MyBatis前身叫ibatis是基于Java的数据持久层框架,它内部封装了JDBC,使开发者只需要关注SQL语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。MyBatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中SQL的动态参数进行映射生成最终执行的SQL语句,最后由MyBatis框架执行SQL并将结果映射为Java对象并返回。MyBatis 的本质就是 Java 对数据库的操作。
MyBatis虽然实现了JPA但是它并不是一个完完全全的ORM组件,而是一个基于SQL开发的半ORM组件。
2.MyBatis的生命周期?
(1)加载mybatis的配置文件—>config.xml(也加载关联的映射文件—>mapping.xml)
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
(2)构建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
(3)创建能执行映射文件的SqlSession
SqlSession sqlSession = factory.openSession();
SqlSession sqlSession = factory.openSession();
(4)创建 SQL Mapper 接口,执行sqlSession.insert等方法
User user = new User("李四", "qqq");
sqlSession.insert("com.mybatis.pojo.User.add", user);
sqlSession.commit(); // 事务提交
sqlSession.close(); // 关闭
SQL Mapper 接口由 SqlSession 所创建,它的生命周期应该小于等于 SqlSession 的生命周期。 Mapper 代表的是一个请求中的业务处理 ,所以它应该在一个请求中,一旦处理完了相关的业务,就应该废弃它。
3.Dao接口的工作原理是什么?
Dao 接口,就是人们常说的 Mapper 接口,接口的全限名,就是映射文件中的 namespace的值,接口的方法名,就是映射。
文件中 MappedStatement 的 id 值,接口方法内的参数,就是传递给 sql 的参数。Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement。
在 Mybatis 中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个 MappedStatement 对象。
4.Dao 接口里的方法参数不同时能重载吗?
不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK 动态代理为 Dao接 口 生 成 代 理 proxy 对 象 , 代 理 对 象 proxy 会 拦 截 接 口 方 法 , 转 而 执 行MappedStatement 所代表的 sql,然后将 sql 执行结果返回。
5.mybatis分页方式
分页一般分为两类,一个是逻辑分页,先查出所有的数据缓存到内存里面,再根据业务相关的一些需求,从内存的数据里面去筛选出合适的数据进行分页。
第二个是物理分页,直接利用数据库里面支持的分页语法来实现,比如mysql的limit关键字
(1)直接在Mybais Mapper的配置文件里面写分页sql,这种方式实现起来比较简单,也比较灵活。
(2) 使用Mybatis提供的RowBounds对象,一次性加载符合查询条件的目标数据,根据分页参数的值,在内存里面去实现分页。但是 在数据量比较大的情况下,JDBC本身会做一些优化,也就是只加载一部分数据,再根据需求去数据库里面加载后续的数据,这种方式在数据量比加大的情况下,可能会频繁访问数据库,给数据库带来比较大的压力。
(3)基与Mybatis里面的Interceptor拦截器,拦截需要分页的select语句,在select语句执行之前,动态拼接分页的关键字。
比如我们经常使用的PageHelper,mybatis-Plus,就是对Mybatis拦截器的一些扩展,去帮我们实现了分页的封装。
6.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执行一对多,一对一的实现方法
单独发送一个SQL去查询关联对象,赋给主对象,然后返回主对象
使用嵌套查询,似JOIN查询,一部分是A对象的属性值,另一部分是关联对 象 B的属性值,好处是只要发送一个属性值,就可以把主对象和关联对象查出来
子查询
Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;
原因就是namespace+id是作为Map<String, MappedStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。
创建mybatis的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<!--数据源的配置:name的值固定 value的值要根据客户自己修改-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai" />
<property name="username" value="root" /> //自己用户
<property name="password" value="root" /> //自己密码
</dataSource>
</environment>
</environments>
</configuration>
创建mybatis和数据库的映射文件
作用: 映射实体和表之间的映射关系
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:命名空间
可以随便起名,但是后期我们要求命名空间的值必须和所对应的dao相同
-->
<mapper namespace="com.user">
<!--查询 根据id查询用户信息
select标签用于查询的标签
id:标签的唯一标识
resultType: 定义返回的类型 把sql查询的结果封装到哪个实体类钟
#{id}===表示占位符等价于? 这是mybatis框架的语法
-->
<select id="findById" resultType="com.dsf.entity.User">
select * from tb_user where userid=#{id}
</select>
</mapper>
测试mybatis
public class Test01 {
public static void main(String[] args) throws Exception {
//1.读取mybatis配置文件的内容----未来不需要写tomcat 解析配置文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
//2. 获取SqlSessionFactory对象
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
//3. 获取SqlSession对象----封装了对数据库操作的各种方法
SqlSession session=factory.openSession();
//调用查询一个结果的接口
//String statement, 命名空间+id----指向sql标签
// Object parameter 需要实参
User user = session.selectOne("com.user.findById", 2);
System.out.println(user);
//4.关闭
session.close();
}
}