【深入理解MyBatis】- 01从数据库中读取数据过程

初始化项目

  1. 执行命令从github上面拉取代码:git clone git@github.com:dengjili/mybatis-3-mybatis-3.4.6.git
    代码结构
    在这里插入图片描述
  2. 执行mysql数据库脚本:mybatis-3-mybatis-3.4.6/src/test/java/priv/mybatis/example01/sql/role.sql
  3. 更改mysql数据库配置:/mybatis-3-mybatis-3.4.6/src/test/resources/priv/mybatis/example01/mybatis-config.xml
<property name="url" value="jdbc:mysql://127.0.0.1/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
  1. 测试类:mybatis-3-mybatis-3.4.6/src/test/java/priv/mybatis/example01/MysqlTest.java
public class MysqlTest {
	
	private static final Logger log = LoggerFactory.getLogger(MysqlTest.class);;

	public static void main(String[] args) throws IOException {
		String resource = "priv/mybatis/example01/mybatis-config.xml";
		Reader reader = Resources.getResourceAsReader(resource);
		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
		SqlSessionFactory sqlSessionFactory = builder.build(reader);
		log.info("create sqlSessionFactory : {}.", sqlSessionFactory);
		
		SqlSession openSession = sqlSessionFactory.openSession();
		RoleMapper mapper = openSession.getMapper(RoleMapper.class);
		Role role = mapper.selectRole(1);
		log.info("print role: {}.", role);
	}
}

测试结果

DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
 INFO [main] - create sqlSessionFactory : org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@768debd.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 2137589296.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7f690630]
DEBUG [main] - ==>  Preparing: select * from Role where id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
 INFO [main] - print role: Role [id=1, name=name, desc=test].

分析MysqlTest.java执行逻辑,主要分为两部分,第一部分为加载配置文件mybatis-config.xml,创建出SqlSessionFactory对象。第二部分是通过SqlSession获取到RoleMapper对象,再通过RoleMapper对象执行方法mapper.selectRole(1),从数据库中数据库中查询表Role数据
在这里插入图片描述
接下来将着重分析一下从数据库中读取数据过程

RoleMapper mapper = openSession.getMapper(RoleMapper.class);
Role role = mapper.selectRole(1);

从数据库中读取数据过程分析

分析代码

RoleMapper mapper = openSession.getMapper(RoleMapper.class);

获取接口RoleMapper 流程分析
在这里插入图片描述

  1. RoleMapper 获取接口的实例依赖于SqlSession接口
  2. 图中①作用是通过Configuration转换入参RoleMapper.class为对应的的MapperProxyFactory对象,这个步骤依赖于配置文件的解析,这里我们可以先忽略,配置文件章节以后再讨论
  3. 图中②作用是为接口RoleMapper创建一个子类,子类MapperProxy为一个代理类,创建MapperProxy对象如下。

MapperProxyFactory创建MapperProxy关键代码

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
  
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
  1. MapperProxy对象实现接口InvocationHandler,采用JDK的动态代码。即RoleMapper调用子类方法,实际是执行代理类MapperProxyinvoke方法
    在这里插入图片描述

总结这句代码,简化为以下两点

RoleMapper mapper = openSession.getMapper(RoleMapper.class);
  • 获取子类对象:RoleMapper mapper = new MapperProxy()
  • 调用子类方法:RoleMapper.selectRole = MapperProxy.invoke

分析代码

Role role = mapper.selectRole(1);

执行方法mapper.selectRole(1)流程分析

RoleMapper调用子类方法selectRole,实际是执行代理类MapperProxyinvoke方法。查看一些核心代码

MapperProxy # invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
}

MapperMethod # execute

public Object execute(SqlSession sqlSession, Object[] args) {
	Object param = method.convertArgsToSqlCommandParam(args);
    return result = sqlSession.selectOne(command.getName(), param);
}

代理最终执行的SqlSession接口的方法,那么接下来我们将梳理,SqlSession是如何访问数据库的
在这里插入图片描述
图中分为①②两部分,第①部分是我们访问数据库的Mybatis核心组件,第②部分是与XML配置相关,第一部分执行访问数据库,实际执行的是XML配置SQL。

  • Executor MyBatis执行器,执行SQL功能的汇总
  • StatementHandler 执行SQL语句的对象封装,可以理解为执行一次SQL,并返回执行SQL后的结果
  • ParameterHandler 帮助StatementHandler封装SQL,主要负责对用户传递的参数转换成SQL所需要的参数
  • ResultSetHandler 帮助StatementHandler返回执行SQL后的结果,主要是对JDBC ResultSet结果集转换
  • TypeHandler参数映射的转换,ParameterHandlerResultSetHandler 的实际工作的类
  • PreparedStatement JDBC用于执行静态 SQL 语句并返回它所生成结果的对象

JDBC实现与Mybatis组件的映射关系如下
在这里插入图片描述

综合上述,我们大概了解了MyBatis从数据库中读取数据过程,也对MyBatis工作的原理有了初步的认识,后续文章,我们将对MyBatis的组件各自单独描述。

拓展

SqlSession openSession = sqlSessionFactory.openSession();
RoleMapper mapper = openSession.getMapper(RoleMapper.class);
Role role = mapper.selectRole(1);

从上述分析我们可以知道,mapper.selectRole(1)最终也是执行SqlSession 接口方法,那我们是否可以不获取RoleMapper ,直接通过SqlSession 从数据库中读取数据,答案是可以的,代码如下

SqlSession openSession = sqlSessionFactory.openSession();
Role role = openSession.selectOne("priv.mybatis.example01.dao.RoleMapper.selectRole", 1);

那我们思考一下,这样做有哪些缺点?或者说第一种方式有什么好处?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值