mybatis原理

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();
 
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值