原理分析Java Mybatis中的Mapper

目录
  • 准备
    • 1.pom文件
    • 2.user类-数据库
    • 3.实体类
    • 4.dao 层
    • 5.Mapper 文件
  • 源码分析
    • 1.断点
    • 2.查看源码
  • 总结

准备

1.pom文件

 <dependencies>
        <!--mybatis坐标-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!--mysql驱动坐标-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
            <scope>runtime</scope>
        </dependency>
        <!--单元测试坐标-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--日志坐标-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

2.user类-数据库

3.实体类

@Getter
@Setter
@ToString
@NoArgsConstructor
public class user {
    private int id;
    private String username;
    private String password;
}

4.dao 层

public interface userDao {
    List<user> findAll();
}

5.Mapper 文件

<?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="dao.userDao">
    <select id="findAll" resultType="mode.user">
        select * from user
    </select>
</mapper>

核心配置文件

<?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>
    <!--通过properties标签加载外部properties文件-->
    <properties resource="jdbc.properties"></properties>
    <!--自定义别名-->
    <typeAliases>
        <typeAlias type="mode.user" alias="user"></typeAlias>
    </typeAliases>
    <!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="userMapper.xml"></mapper>
    </mappers>

</configuration>

核心代码

import dao.userDao;
import mode.user;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestMapper {
    public static void main(String[] args) throws IOException {
        //加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //获得sqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new
                SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行sql语句
        userDao mapper = sqlSession.getMapper(userDao.class);
        List<user> userList = mapper.findAll();
        //打印结果
        System.out.println(userList);
        //释放资源
        sqlSession.close();
    }
}

源码分析

1.断点

2.查看源码

DefaultSqlSession:

Configuration:

这是Configuration 类。我们主要看getMapper()方法

MapperRegistry:

关键代码:mapperProxyFactory.newInstance(sqlSession);

MapperProxyFactory:

返回的是MapperProxy 对象

MapperProxy:

源码:

// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.ibatis.binding;
import java.io.Serializable;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import org.apache.ibatis.lang.UsesJava7;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.SqlSession;
public class MapperProxy<T> implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -6424540398559729838L;
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethod> methodCache;
    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }
            if (this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);
    }
    private MapperMethod cachedMapperMethod(Method method) {
        MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
        if (mapperMethod == null) {
            mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
            this.methodCache.put(method, mapperMethod);
        }
        return mapperMethod;
    }
    @UsesJava7
    private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
        Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, Integer.TYPE);
        if (!constructor.isAccessible()) {
            constructor.setAccessible(true);
        }
        Class<?> declaringClass = method.getDeclaringClass();
        return ((Lookup)constructor.newInstance(declaringClass, 15)).unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
    }
    private boolean isDefaultMethod(Method method) {
        return (method.getModifiers() & 1033) == 1 && method.getDeclaringClass().isInterface();
    }
}

在invoke方法中可以看到,如果我们调用的是Object中的方法,不做任何处理,直接调用,否则执行:

mapperMethod.execute(this.sqlSession, args);

MapperMethod:

在MapperMethod 中对SQL语句进行分类反射

总结

  • MapperProxyFactory中,使用JDK的动态代理生成Mapper接口的代理代理类
  • 由动态处理器MapperProxy中调用MapperMethod中的方法处理执行SQL
  • 最后,在MapperMethod中根据执行的方法返回值决定调用SqlSession中的对应方法执行SQL

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • mybatis映射文件mapper.xml的具体写法

    Mapper映射文件是一个xml格式文件,必须遵循相应的dtd文件规范 在学习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&q

  • Mybatis中Mapper映射文件使用详解

    紧接上文所述,在这篇文章中我将对Mapper映射文件进行详细的说明. Mapper映射文件是一个xml格式文件,必须遵循相应的dtd文件规范,如ibatis-3-mapper.dtd.我们先大体上看看支持哪些配置?如下所示,从Eclipse里截了个屏: 从上图可以看出,映射文件是以<mapper>作为根节点,在根节点中支持9个元素,分别为insert.update.delete.select(增删改查);cache.cache-ref.resultMap.parameterMap.sql. 下

  • mybatis-plus中BaseMapper入门使用

    目录 入门使用BaseMapper完成增删改查 BaseMapper各方法详解 Insert Delete Update Select 具体教程参考官网文档: baomidou.com/ 入门使用BaseMapper完成增删改查 根据数据库表制作相应实体类 @TableName(value = "user") public class User implements Serializable { private static final long serialVersionUID =

  • MyBatis中Mapper的注入问题详解

    在 SpringBoot 体系中,MyBatis 对 Mapper 的注入常见的方式我知道的有 2 种: 1.@MapperScan MapperScan 类是 mybatis-spring 包里面的. 通过在启动类上使用 @MapperScan,然后通过 basePackages 属性指定 Mapper 文件所在的目录来进行扫描装载,默认情况下指定目录下的所有.java文件都会被当做 Mapper 来加载处理. @MapperScan(basePackages = "com.test.spri

  • mybatis实现mapper代理模式的方式

    今晚继续复习mybtis 以根据id值查询单条数据为例 编写SqlMapConfig.xml文件 <configuration> <!-- 使用mybatis需要的数据源和事务配置,后续如果整合spring之后,将不再需要 --> <environments default="development"> <!-- 配置数据源和事务 --> <environment id="development"> <

  • Mybatis-Plus BaseMapper的用法详解

    1.如何使用BaseMapper进行数据库的操作. 2.使用BaseMapper进行插入实体时如何让UUID的主键自动生成. Student实体类,其中id属性主键为UUID package com.huixiaoer.ant.api.model.bean; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; public class Stud

  • 原理分析Java Mybatis中的Mapper

    目录 准备 1.pom文件 2.user类-数据库 3.实体类 4.dao 层 5.Mapper 文件 源码分析 1.断点 2.查看源码 总结 准备 1.pom文件 <dependencies> <!--mybatis坐标--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5&

  • MyBatis 中使用 Mapper 简化代码的方法

    前面文章所写的增删改查是存在问题的.每执行一次 SQL,都要开启一次会话,并且需要提交并关闭,主要问题就是冗余代码过多,模板化代码过多. 例如,我想开发一个 UserDao,可能是下面这样: 简化前的 UserDao public class UserDao { private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getInstance(); public User getUserById(Integer id

  • 分析java并发中的wait notify notifyAll

    一.前言 java 面试是否有被问到过,sleep 和 wait 方法的区别,关于这个问题其实不用多说,大多数人都能回答出最主要的两点区别: sleep 是线程的方法, wait / notify / notifyAll 是 Object 类的方法: sleep 不会释放当前线程持有的锁,到时间后程序会继续执行,wait 会释放线程持有的锁并挂起,直到通过 notify 或者 notifyAll 重新获得锁. 另外还有一些参数.异常等区别,不细说了.本文重点记录一下 wait / notify

  • 解决mybatis中的mapper命名问题

    mybatis mapper命名问题 mapper文件中id命名最好首字母小写,避免让mybatis认为是一个类 <!--获取供应商列表--> <resultMap id="ProviderList" type="Provider"> <result property="id" column="id"/> <result property="proCode" col

  • Java Mybatis中的 ${ } 和 #{ }的区别使用详解

    好了,真正做开发也差不多一年了.一直都是看别人的博客,自己懒得写,而且也不会写博客,今天就开始慢慢的练习一下写博客吧.前段时间刚好在公司遇到这样的问题. 一.举例说明 select * from user where name = "dato"; select * from user where name = #{name}; select * from user where name = '${name}'; 一般情况下,我们都不会注意到这里面有什么不一样的地方.因为这些sql都可以

  • 在mybatis中使用mapper进行if条件判断

    目的: 在使用mybatis框架中mapper文件有自动生成,但有时需要自己添加sql语句进行开发,当遇到需要使用 if进行条件判断的时候该怎么写? 查询sql语句如下: <select id="queryData" parameterType="com.pojo.QueryDetailReq" resultType="com.pojo.MxDataInfo"> select * from db_trd.tb_trd_secu_ord

  • Mybatis中的mapper模糊查询语句LIKE

    目录 Mybatis mapper模糊查询语句LIKE mapper 模糊查询语句报错 Mybatis mapper模糊查询语句LIKE 最近做学校安排的课程设计作业,用到SSM框架,在自己写mapper代码是遇到了模糊查询的问题 困扰好久 下面是我解决这个问题的方法,其他网上好多方法我尝试过却没有实现 下面试sql语句 select * from goodsinfo where goodsname like '%' #{goodsname} '%' 注意代码中的空格 空格 空格 #{ } 方式

  • mybatis中的mapper.xml使用循环语句

    目录 mapper.xml使用循环语句 mapper.java,传的参数是map mapper.xml 参数,数组,list都行 mybatis xml循环语句 首先创建DAO方法 除了批量插入,使用SQL in查询多个用户时也会使用 mapper.xml使用循环语句 mapper.java,传的参数是map List<实体类> getList(Map<String,Object> paraMap); mapper.xml <!--select:对应sql的select语句,

  • 实例分析java对象中浅克隆和深克隆

    引言: 在Object基类中,有一个方法叫clone,产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,有深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆会将此属性完全拷贝一份,而浅克隆仅仅是拷贝一份此属性的引用.首先看一下容易犯的几个小问题 clone方法是Object类的,并不是Cloneable接口的,Cloneable只是一个标记接口,标记接口是用用户标记实现该接口的类具有某种该接口标记的功能,常见的标记接口有三个:Serializable.Cloneable

  • PHP中实现中文字符进制转换原理分析

    一,中文字符转十进制原理分析 GBK编码中一个汉字由二个字符组成,获取汉字字符串的方法如下 复制代码 代码如下: $string = "不要迷恋哥"; $length = strlen($string); for($i=0;$i<$length;$i++){ if(ord($string[$i])>127){ $result[] = ord($string[$i]).' '.ord($string[++$i]); } } var_dump($result); 由于一个汉字为

随机推荐