Mybatis 映射器接口代理对象的方式 运行过程debug分析

查询一张表的所有数据。

环境:

使用工具IntelliJ IDEA 2018.2版本。

创建Maven工程不用骨架

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6
 7     <groupId>com.jxjdemo</groupId>
 8     <artifactId>day34_mybatis1_curd_dao</artifactId>
 9     <version>1.0-SNAPSHOT</version>
10
11     <properties><!--锁定编译版本与字符集-->
12         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13         <maven.compiler.source>1.8</maven.compiler.source>
14         <maven.compiler.target>1.8</maven.compiler.target>
15     </properties>
16
17     <dependencies>
18         <dependency><!--导入mysql依赖-->
19             <groupId>mysql</groupId>
20             <artifactId>mysql-connector-java</artifactId>
21             <version>5.1.47</version>
22         </dependency>
23
24         <dependency> <!--导入mybatis依赖-->
25             <groupId>org.mybatis</groupId>
26             <artifactId>mybatis</artifactId>
27             <version>3.5.2</version>
28         </dependency>
29
30         <dependency> <!--导入日志依赖-->
31             <groupId>log4j</groupId>
32             <artifactId>log4j</artifactId>
33             <version>1.2.17</version>
34         </dependency>
35
36         <dependency>
37             <groupId>junit</groupId>
38             <artifactId>junit</artifactId>
39             <version>4.12</version>
40         </dependency>
41     </dependencies>
42 </project>
  1. 表User
 1 package com.jxjdemo.domain;
 2 import java.util.Date;
 3
 4 public class User {
 5     private Integer id;
 6     private String username;
 7     private Date birthday; //框架会帮我们自动转
 8     private String sex;
 9     private String address;
10
11     @Override
12     public String toString() {
13         return "User{" +
14                 "id=" + id +
15                 ", username=‘" + username + ‘\‘‘ +
16                 ", birthday=" + birthday +
17                 ", sex=‘" + sex + ‘\‘‘ +
18                 ", address=‘" + address + ‘\‘‘ +
19                 ‘}‘;
20     }
21 //省略Get与Set方法

2.映射器XML

1 <?xml version="1.0" encoding="utf-8"?><!--引入约束-->
2 <!DOCTYPE mapper
3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5         <mapper namespace="com.jxjdemo.dao.UserDao"><!--mapper:映射器配置/namespace:映射器的全限定类名-->
6
7         <select id="queryAll" resultType="com.jxjdemo.domain.User"><!--查询所有-->
8                 select * from user
9         </select>

3.映射器配置文件

<?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">
        <mapper namespace="com.jxjdemo.dao.UserDao"><!--mapper:映射器配置/namespace:映射器的全限定类名-->

        <select id="queryAll" resultType="com.jxjdemo.domain.User">
                select * from user
        </select>
        </mapper>

4.实现类

 1 package com.jxjdemo.dao.impl;
 2 import com.jxjdemo.dao.UserDao;
 3 import com.jxjdemo.domain.User;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import java.util.List;
 7
 8 public class UserDaoImpl implements UserDao {//执行SQL语句用实现类做,不用代理对象。
 9     //从工厂里面获取sqlsession对象
10     private SqlSessionFactory factory;//以后由sping整合sping创建,现在去测试类里面创建
11
12     public UserDaoImpl(SqlSessionFactory factory) {
13         this.factory = factory;
14     }
15
16     @Override
17     public List<User> queryAll() {
18         SqlSession session = factory.openSession();
19         List<User> list = session.selectList("com.jxjdemo.dao.UserDao.queryAll");//返回的是Object但实际得到的是(UserDao)
20         session.close();//session关闭流,释放资源
21         return list;
22     }

5.测试类

 1 package com.jxjtest.test;
 2
 3 import com.jxjdemo.dao.UserDao;
 4 import com.jxjdemo.dao.impl.UserDaoImpl;
 5 import com.jxjdemo.domain.User;
 6 import org.apache.ibatis.io.Resources;
 7 import org.apache.ibatis.session.SqlSessionFactory;
 8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 9 import org.junit.After;
10 import org.junit.Before;
11 import org.junit.Test;
12
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.Date;
16 import java.util.List;
17
18 public class MybatisCurdTest {
19     private SqlSessionFactory factory;
20     private InputStream is;
21     private UserDao userDao;
22
23     @Test
24     public void testQueryAll(){ //查询全部
25         //读取配置文件,获取sqlsession对象工厂,获取映射器提取
26         List<User> userList = userDao.queryAll();
27         for (User user : userList){
28             System.out.println(user);
29         }
30     }
31 @Before
32     public void init() throws IOException { //重复执行的代码,单独提取出来
33         is = Resources.getResourceAsStream("sqlMapConfig.xml");//提取成员变量后
34
35         // SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //获取sqlsession对象,通过工厂构建一个,提取成员变量
36         factory = new SqlSessionFactoryBuilder().build(is);
37         userDao = new UserDaoImpl(factory);//提取成员变量
38     }
39     @After
40     public void destroy() throws IOException {  //关流
41         is.close();
42     }
43 }

6.数据库核心配置文件XML

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE configuration
 3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <!--mybatis的核心配置文件,主要配置数据库连接信息-->
 6 <configuration><!--根标签-->
 7     <!--enxironments 可以配置多个数据库环境-->
 8     <environments default="mysql"><!--default 默认使用的数据库-->
 9         <environment id="mysql"><!--environment每一个数据库连接(配置)信息-->
10             <transactionManager type="JDBC" /><!--事物管理方式-->
11             <dataSource type="POOLED"><!--数据源。不使用UN连接池POOLED,POOLED使用连接池,JNDI查找数据源配置文件-->
12                 <property name="driver" value="com.mysql.jdbc.Driver" />
13                 <property name="url" value="jdbc:mysql://localhost:端口号/库名"/>
14                 <property name="username" value="账号"/>
15                 <property name="password" value="密码"/>
16             </dataSource>
17         </environment>
18     </environments>
19
20     <mappers>
21         <mapper resource="com/jxjdemo/dao/UserDao.xml" />
22     </mappers>
23 </configuration>

  7.省略log4j日志配置文件,目录结构。

8.在测试类打断点,开始deBug跟踪,从这里开始。

相册里面有步骤截图,可以配合一起看。

1 List<User> userList = userDao.queryAll();

9.到实现类,获取session

1 SqlSession session = factory.openSession();

10.跟踪这行代码做了什么事情,进入这个方法。

1 List<User> list = session.selectList("com.jxjdemo.dao.UserDao.queryAll");

11.到了DefaultSqlSession.java类里面,在selectList调了selectList,方法的重载。

1 @Override
2   public <E> List<E> selectList(String statement) {
3     return this.selectList(statement, null);
4   }
5
6   @Override
7   public <E> List<E> selectList(String statement, Object parameter) {
8     return this.selectList(statement, parameter, RowBounds.DEFAULT);
9   }

12.到了ms,获取数据库,配置文件信息,与SQL类型。关键在于executor.query执行查询。

 1 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
 2     try {
 3       MappedStatement ms = configuration.getMappedStatement(statement);
 4       return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
 5     } catch (Exception e) {
 6       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
 7     } finally {
 8       ErrorContext.instance().reset();
 9     }
10   }

13.先对wrspCollection(parameter)包装一下。回到12.

1 if (object instanceof Collection) {这里省略}

14.进入CachingExecutor.java.这个类自己不执行。

1  @Override
2   public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
3     BoundSql boundSql = ms.getBoundSql(parameterObject);

15.这里第一步,从ms.getBoundSql获取到了绑定的SQL语句。

CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);//缓存相关忽略

16.继续调query方法重载。

return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

17.到了query方法。

1 @Override
2   public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
3       throws SQLException {
4     Cache cache = ms.getCache();

18.找缓存。

1 if (cache != null) {

19.缓存里面没有,CachingExecutor.java.这个类自己不执行,就调了delegate委托者。

 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

20.CachingExecutor.java.这个类是从父类继承的,所以到了BaseExecutor.java.

@Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());

21.往下走。

if (closed) {//1.
if (queryStack == 0 && ms.isFlushCacheRequired()) {//2.
queryStack++;//3.
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;//4.
if (list != null) {//5.

22.到了queryFromDatabase开始到库里面查询。

list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);

23.BaseExecutor.java.执行了doQuery方法

localCache.putObject(key, EXECUTION_PLACEHOLDER);//1
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);//2.

24.进入doQuery查看,到了SimpleExecutor.java

1 public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
2     Statement stmt = null;//1
3 Configuration configuration = ms.getConfiguration();//2.configuration所有的配置信息
4 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);//3.
5 stmt = prepareStatement(handler, ms.getStatementLog());//4.准备得到一个
6 return handler.query(stmt, resultHandler);//5.handler.query开始真正执行了

25.进入query到了RoutingStatementHandler.java

return delegate.query(statement, resultHandler);//调了delegate

26.调了delegate到了PreparedStatementHandler.java

1 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
2     PreparedStatement ps = (PreparedStatement) statement;PreparedStatement预编译对象
3     ps.execute();//2.获取预编译对象,执行任意语句
4     return resultSetHandler.handleResultSets(ps);//
5   }

到了这里就是最终的结果,剩余处理结果集,封装的事情了。

结果:Mybatis封装的再深底层还是JDBC。



原文地址:https://www.cnblogs.com/jxearlier/p/11625253.html

时间: 2024-10-09 01:44:03

Mybatis 映射器接口代理对象的方式 运行过程debug分析的相关文章

MyBatis映射器总结

Mybatis映射器xml配置包含如下标签: select 查询语句,自定义参数返回结果集 insert 插入语句 update 更新语句 delete 删除语句 parameterMap 定义参数映射关系,不建议使用 sql 定义一段SQL,可以再其他部分引用 resultMap 结果集,提供映射规则 cache 给定命名空间的缓存配置 cache-ref 其他命名空间缓存配置的引用 1.select 1.1 select标签包含如下属性: 属性 说明 备注 id 它和Mybatis的命名空间

MyBatis映射器(一)--多参数传递方式

参考自:https://www.cnblogs.com/hellowhy/p/9678245.html 在mybatis映射器的接口中,一般在查询时需要传递一些参数作为查询条件,有时候是一个,有时候是多个.当只有一个参数时,我们只要在sql中使用接口中的参数名称即可,但是如果是多个呢,就不能直接用参数名称了,mybatis中有以下四种 第一种:使用map传递 1??定义接口 1 // 使用map传递多个参数进行查询 2 public List<Product> getByMap(Map<

Mybatis映射器select

Mybatis映射器select 简单的select元素的应用 id 配合Mapper的全限定名,联合成为一个唯一的标示 parameterType 表示这条SQL接受的参数类型 resultType表示这条SQL返回的结果类型 #{firstName} 是被传递进去的参数 <select id="countUserByFirstName" parameterType="string" resultType="int"> select

mybatis 映射器

1 映射器 Mapper 是由java接口和 XML 文件共同组成.它的作用如下 1)定义参数类型 2)描述缓存 3)描述 SQL 语句 4)定义查询结果和POJO的映射关系 2 SqlSessionFactoryBuilder 主要作用是用来生成 SqlSessionFactory,生成以后就不用了,所以它的生命周期只存在于方法局部. 3 SqlSessionFactory 的作用是创建SqlSession,而 SqlSession 就是一个会话,相当于是JDBC的 Connection 对象

接口代理对象

为什么要接口代理? 在不改变原来代码,对已有方法增强 1 创建一个卖电脑接口 public interface SaleComputer { public String sale(double money); public void show(); } 2 创建一个类,实现接口 public class Lenovo implements SaleComputer { @Override public String sale(double money) { System.out.println(

Mybatis映射器(一)

XML查询参数: parameterType:可以给出类别名,全名等. resultType:查询结果,可以为 int,float,map等不可以与resultMap同时使用. resultMap: 映射集的引用可以配置映射规则,级联,typeHandler等,是mybatis最复杂的元素. 本文返回是resultType. 查询方法可以在parameterType设置为单个参数XML设置为int,string等,多个参数可以设置为map <select id="getRoleUseRes

SQL映射器Mapper接口(MyBatis)

SQL映射器Mapper接口 MyBatis基于代理机制,可以让我们无需再写Dao的实现.直接把以前的dao接口定义成符合规则的Mapper. 注意事项: 1.接口必须以Mapper结尾,名字是DomainMapper 2.mapper.xml文件要和Mapper接口建立关系,通过namespace:要能连接到Mapper接口   3.mapper.xml中写查询语句的标签的传入参数类型(parameterType).返回结果类型(resultType)必须和mapper接口中对应方法的传入参数

Java Persistence with MyBatis 3(中文版) 第四章 使用注解配置SQL映射器

在上一章,我们看到了我们是怎样在映射器Mapper XML配置文件中配置映射语句的.MyBatis也支持使用注解来配置映射语句.当我们使用基于注解的映射器接口时,我们不再需要在XML配置文件中配置了.如果你愿意,你也可以同时使用基于XML和基于注解的映射语句. 本章将涵盖以下话题: l 在映射器Mapper接口上使用注解 l 映射语句 @Insert,@Update,@Delete,@SeelctStatements l 结果映射 一对一映射 一对多映射 l 动态SQL @SelectProvi

Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

关系型数据库和SQL是经受时间考验和验证的数据存储机制.和其他的ORM 框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务器所提供的SQL语句的巨大威力.与此同时,MyBaits消除了书写大量冗余代码的痛苦,它使使用SQL更容易. 在代码里直接嵌套SQL语句是很差的编码实践,并且维护起来困难.MyBaits使用了映射器配置文件或注解来配置SQL语句.在本章中,我们会看到具体怎样使用映射器配置文件来配置映射SQL语句.