Mybatis执行流程、缓存机制、插件

目录

一.传统的JDBC连接数据库

二.Mybatis(ORM框架)

1.什么是ORM框架

2.Mybatis特性

三.MyBatis缓存机制

1.一级缓存

2.二级缓存

3.一二级缓存很鸡肋

四.Mybayis插件

插件的工作流程

多个插件的顺序

五.Mybatis执行流程

1.初始化解析配置文件

2.创建sqlSession会话

3.获取mapper代理对象

4.调用mapper中的方法


一.传统的JDBC连接数据库

流程:

  • 注册驱动
  • 获取连接创建Statement对象
  • execute方法执行SQL
  • 把结果集转换成POJO对象
  • 关闭资源

缺点:

  •  需要手动管理资源
  • 代码重复
  • 业务逻辑与数据操作的代码耦合
  • 结果集需要手动处理
public class JdbcTest {
    @Test
    public void testJdbc() throws IOException {
        Connection conn = null;
        Statement stmt = null;
        Student student = new Student();

        try {
            // 注册 JDBC 驱动
//             Class.forName("com.mysql.jdbc.Driver");

            // 打开连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/springdb", "root", "root");

            // 执行查询
            stmt = conn.createStatement();
            String sql = "SELECT id, name, age clazz_no FROM student where id = 1";
            ResultSet rs = stmt.executeQuery(sql);

            // 获取结果集
            while (rs.next()) {
                Integer id = rs.getInt("id");
                String name = rs.getString("name");
                Integer age = rs.getInt("age");
                Integer clazzNo = rs.getInt("clazz_no");
                Student.setClazzNo(clazzNo);
                Student.setId(id);
                Student.setName(name);
                Student.setAge(age);
            }
            System.out.println(student);

            rs.close();
            stmt.close();
            conn.close();
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException se2) {
            }
            try {
                if (conn != null) conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
    }

二.Mybatis(ORM框架)

1.什么是ORM框架

O:对象        M:映射        R:关系型数据库

数据库中的一条数据对应Java中的一个对象

2.Mybatis特性:

  1. 使用连接池对连接进行管理
  2. SQL和代码分离,集中管理
  3. 参数映射和动态SQL
  4. 结果集映射
  5. 缓存管理
  6. 重复SQL的提取
  7. 插件机制

三.MyBatis缓存机制

一级缓存和二级缓存在主配置文件中默认都是开启的

<setting name="localCacheScope" value="SESSION"/>

在主配置文件设置一级缓存的作用域 默认就是SESION,如果value设为STATEMENT则相当于关闭了一级缓存

二级缓存有两个开关。总开关在主配置文件中,value改为false则关闭二级缓存

<setting name="cacheEnabled" value="true"/> 

第二个开关在mapper.xml中

<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
       size="1024"
       eviction="LRU"
       flushInterval="120000"
       readOnly="false"/>

每个方法也有个控制的开关useCache,flushCache="true"清处二级缓存相应的数据

1.一级缓存

localCache 作用域:session 也就是同一个SqlSession

 一级缓存存在的问题:

当我们对数据做修改操作时,这条数据如果在一级缓存中就会被删除。

那么如果有两个SqlSession,一个是sqlSession1另一个是sqlSession2.假如在sqlSession1的一级缓存中已经存在了id=1的缓存数据,然后sqlSession2对id=1的这条数据进行修改,因为每个sqlSession有自己的Executor,所以sqlSession2的修改并不会影响sqlSession1中的缓存,所以sqlSession1的一级缓存中存放的是过时的数据,这时候二级缓存就发挥了作用

2.二级缓存

作用域:namespace也就是一同个mapper接口

如果开启了二级缓存的功能,就会给我们的Excutor加上装饰CachingExecutor


二级缓存应该工作在一级缓存之前还是之后?  二级先
思考:基于作用范围,应该在什么对象中维护?

只有当事务提交后才会把数据保存到二级缓存,而且相对应的实体类要实现可序列化接口

3.一二级缓存很鸡肋

单机没有问题 但是服务都是分布式的
我们mybatis的缓存放在内存里面(如果没有引入redis的话)
但是引入redis,有点画蛇添足
redis 是db之外的缓存

四.Mybayis插件

MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

插件的工作流程

以pageHelper为例,他会拦截我们的query()方法

他会先生成Executor的代理类,然后拦截query执行代理类的invoke方法,然后会走到pageHelper实现Mybayis的Interceptor实现类(PageInterceptor)的interceptor方法 ,然后会执行PageHelper的分页逻辑,最后再执行method.invoke,也就是被代理类的方法。

多个插件的顺序

取决于我们配置在主配置文件中的插件定义顺序

五.Mybatis执行流程

1.初始化解析配置文件

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

SqlSessionFactory factory =

new SqlSessionFactoryBuilder().build(in);

  1. 会先解析我们的主配置文件,XMLConfigBuild会解析标签封装成一个Configuration对象;
  2. XMLMapperBuild会解析我的mapper.xml文件,解析mapper节点,得到mapper节点的namespace赋值给currentNamespace
  3. 把mapper.xml中的sql语句解析然后封装成MapperedStatement(存放解析的select,delete.insert,update)。key是namespqce+id.
  4. 根据nameSpace拿到接口信息
  5. mapperRegistry把接口信息注册到knownMappers中,key为mapper接口的class,value为mapperProxyFactory工厂
  6. 最后new 了一个DefaultSqlSessionFactory工厂

2.创建sqlSession会话

 SqlSession sqlSession = factory.openSession();

  • 创建事务
  • 创建Executor基本类型(SIMPLE/REUSE/BATCH)
  • 二级缓存包装CachingExecutor(executor)
  • 拦截器包装Executor
  • new DefaultSqlSession

3.获取mapper代理对象

StudentDao studentMapper = sqlSession.getMapper(StudentDao.class);

  • configuration.getMapper(type, this);
  • mapperRegistry.getMapper(type, sqlSession);
  • knownMappers.get(type )->获取相应的mapperProxyFactory
  • mapperProxyFactory.newInstance 先new 一个mapperProxy。mapperProxy继承了InvocationHandler然后再进行了JDK动态代理

4.调用mapper中的方法

  • 会执行mapperProxy对象的invoke方法
  • 根据接口以及方法名,获取mappedStatement
  • 先找二级缓存
  • 没命中再一级缓存
  • 在没命中就JDBC执行sql操作
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w7486

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值