走进Mybatis--02.Mybatis中Dao层实现类逻辑分析(SqlSession如何执行查询)

上期文章
走进Mybatis–01.简单模拟实现Mybatis

上一篇文章中,简单的使用了Mybatis来进行了一个数据查询的实现,发现我们只需要声明Dao接口,创建Mapper.xml文件,并不需要我们自己来实现Dao接口的逻辑,就可以实现数据的查询操作。

1. 自定义Dao接口的实现类

当然也可以手动编写Dao接口的实现类来进行数据的CRUD操作。
首先创建Maven项目,在pom文件中加入mybatis和数据库连接的依赖。
首先回顾之前的方式来进行数据查询

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

创建mybatis-config.xml

<?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"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://xxxx:3306/demo?useUnicode=true"/>
                <property name="username" value="xxxx"/>
                <property name="password" value="xxxx"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/DemoMapper.xml"/> <!--1.加载MapperXML-->
    </mappers>
</configuration>

编写 DemoMapper java接口

package com.iBatis.test.dao;

import com.iBatis.test.entity.Demo;

import java.util.List;

public interface DemoMapper {

    List<Demo> queryDemo();
}

编写DemoMapper.xml 文件

<?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">
<!--指定dao -->
<mapper namespace="com.iBatis.test.dao.DemoMapper">
	<!--查询-->
	<select id="queryDemo"
			useCache="true"
			resultType="com.iBatis.test.entity.Demo">
		SELECT
			id,
			name,
			age,
			salary,
			birthDay
		FROM
			demo
	</select>
</mapper>

编写Main方法进行测试

package com.iBatis.test;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.iBatis.test.dao.DemoMapper;

import java.io.InputStream;

public class MyBatisTest {

    public static void main(String[] args) throws Exception {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        DemoMapper mapper = sqlSession.getMapper(DemoMapper.class);
        System.out.println("mapper QueryList结果="+ mapper.queryDemo());
    }
}

正常查询出来结果,此处sqlSession.getMapper(DemoMapper.class); 拿出来的DemoMapper 是使用了Mybatis进行代理的实现类,这个等会再说,此时我们发现并没有创建DemoMapper的实现类,也可以进行查询操作,我们来创建DemoMapper的实现类来进行查询

定义DemoMapperImpl实现类,来实现DemoMapper接口。在上一篇文章中来看,实际上是通过sqlSession来进行的查询,我们的实现类就可以这样写

package com.iBatis.test.dao.impl;

import com.iBatis.test.dao.DemoMapper;
import com.iBatis.test.entity.Demo;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class DemoMapperImpl implements DemoMapper {

    private SqlSession sqlSession;

    public DemoMapperImpl(SqlSession sqlSession){
        this.sqlSession = sqlSession;
    }

    @Override
    public List<Demo> queryDemo() {
    	System.out.println("执行DemoMapperImpl queryDemo查询方法。");
        List<Demo> result = sqlSession.selectList("com.iBatis.test.dao.DemoMapper.queryDemo");
        return result;
    }
}

修改测试类的Main方法来调用DemoMapperImpl进行查询

package com.iBatis.test;

import com.iBatis.test.dao.impl.DemoMapperImpl;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.iBatis.test.dao.DemoMapper;

import java.io.InputStream;

public class MyBatisTest {

    public static void main(String[] args) throws Exception {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
//        DemoMapper mapper = sqlSession.getMapper(DemoMapper.class);
//        System.out.println("mapper QueryList结果="+ mapper.queryDemo());
        DemoMapper mapper = new DemoMapperImpl(sqlSession);
        System.out.println("mapperImpl queryList结果="+ mapper.queryDemo());

    }
}

同样可以查询出来结果
在这里插入图片描述

2. Dao接口实现类的执行逻辑分析

实现类中,通过sqlSession.selectList("")方法进行了数据查询。。

看代码发现org.apache.ibatis.session.SqlSession有两个实现类,断点执行发现走的是DefaultSqlSession
在这里插入图片描述
进入DefaultSqlSession 找到selectList方法
在这里插入图片描述

MappedStatement ms = this.configuration.getMappedStatement(statement);
这个就类似上一篇文章中,通过类全名+方法名从Configuration获取到要执行的sql语句返回结果类型,入参类型等信息的数据

this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
这里面执行了executor的query方法,接下来看看executor是什么东西

发现org.apache.ibatis.executor.Executor是一个接口,它有这么多实现类
在这里插入图片描述
打断点发现,此时的executor是叫CachingExecutor
进入CachingExecutor的query方法
在这里插入图片描述

发现又走到了
delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
这个delegate是什么呢?

在这里插入图片描述
发现这个delegate 是一个SimpleExecutor 实现类的Executor
然后进入SimpleExecutor类找query方法,发现并没有query方法
在这里插入图片描述
发现它(SimpleExecutor)是继承自BaseExecutor,我们看BaseExecutor,
在这里插入图片描述

执行断点,走到了,看名字意思是,从数据库查询,好像快找到最后了
this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);

在queryFromDatabase方法中,发现它调用了this.doQuery()方法,这个方法在BaseBaseExecutor是一个抽象方法,在SimpleExecutor中进行了实现

protected abstract List doQuery(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, BoundSql var5) throws SQLException;

于是我们就清楚了,CachingExecutor中调用了delegate.query()查询先执行了SimpleExecutor父类的query()方法,在这个方法里面调用了 被子类(SimpleExecutor)实现的doQuery方法

在这里插入图片描述
在这里插入图片描述
终于我们看到了我们熟悉的PreparedStatement对象,

此处执行了StatementHandler.query(), 继续看StatementHandler的类结构
在这里插入图片描述
上面的handler就是RoutingStatementHandler的实例,进入RoutingStatementHandler看代码
在这里插入图片描述
发现从RoutingStatementHandler里面又使用PreparedStatementHandler的query方法
在这里插入图片描述
在PreparedStatementHandler的query方法中终于发现了我们最开始写jdbc时,使用PreparedStatement来执行sql语句的代码了,突然就觉得亲切了好多

在接着看

this.resultSetHandler.handleResultSets(ps);

resultSetHandler类是一个接口,它只有一个默认实现类DefaultResultSetHandler
在这里插入图片描述
在这个方法里面对查询出来的数据做解析
在这里插入图片描述

3. SqlSession查询执行逻辑总结

  1. 首先执行
    defaultSqlSession.selectList("");

  2. 最终调用的为三个参数的selectList方法
    defaultSqlSession.selectList("",params,RowBounds);

  3. 在selectList方法里面先获取了MappedStatement对象,然后调用了executor.query方法
    executor.query(); //实际是 cachingExecutor.query();

  4. cachingExecutor的query方法中调用了delegate.query()方法
    delegate.query(); // delegate为SimpleExecutor实例,实际调用simpleExecutor.query();该query方法在抽象父类BaseExecutor实现

  5. baseExecutor.query方法中调用了自己的baseExecutor.queryFromDatabase()方法

  6. queryFromDatabase() 调用了抽象方法doQuery();该方法在SimpleExecutor实现

  7. 在SimpleExecutor.doQquer()方法执行了handler.query()方法;
    handler.query();// 实际是RoutingStatementHandler.query();

  8. RoutingStatementHandler.query()又调用了PreparedStatementHandler的query()方法

  9. 在PreparedStatementHandler的query()执行了preparedStatement.execute();

  10. 最后执行resultSetHandler.handleResultSets(ps);在DefaultResultSetHandler对结果集进行封装

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值