mybatis源码深入学习-02(手撸mybatis框架)

手写 Mybatis,“整整” Mybatis源码 前言 前两天写了一个 手写Spring ioc 框架,“撸撸”Spring 源码我们今天来整整Mybatis。 mybaits 在 ORM 框架中,可算是半壁江山了,由于它是轻量级,半自动加载,灵活性和易拓展性。深受广大公司的喜爱,所以我们程序开发也离不开 mybatis 。 很多朋友对 mybatis 源码没什么了解,或者想看但是不知道怎么看的苦恼吗? 归根结底,我们还是需要知道为什么会有 mybatis ,mybatis 解决了什么问题? 想要知道 mybatis 解决了什么问题,就要知道传统的 阅读详情

mybatis源码深入学习-01

如果自己设计mybatis架构

在这里插入图片描述
首先创建 SqlSessionFactory 实例,SqlSessionFactory 就是创建 SqlSession 的工厂类。
加载配置文件创建 Configuration 对象,配置文件包括数据库相关配置文件以及我们在 XML 文件中写的 SQL。
通过 SqlSessionFactory 创建 SqlSession。
通过 SqlSession 获取 mapper 接口动态代理。
动态代理回调 SqlSession 中某查询方法。
SqlSession 将查询方法转发给 Executor。
Executor 基于 JDBC 访问数据库获取数据,最后还是通过 JDBC 操作数据库。
Executor 通过反射将数据转换成 POJO 并返回给 SqlSession。
将数据返回给调用者。

传统jdbc

加载驱动
创建连接,Connection 对象
根据 Connection 创建 Statement 或者 PreparedStatement 来执行 SQL 语句
返回结果集到 ResultSet 中
手动将 ResultSet 映射到 JavaBean 中

MyBatis 操作数据库总结

使用配置文件构建 SqlSessionFactory
使用 SqlSessionFactory 获得 SqlSession,SqlSession 相当于传统 JDBC 的 Conection
使用 SqlSession 得到 Mapper
用 Mapper 来执行 SQL 语句,并返回结果直接封装到 JavaBean 中
在这里插入图片描述

自己写一个mybatis框架

1)加载配置文件配置信息

import java.util.HashMap;
import java.util.Map;

/**
 * Configuration 总配置类,来保存 db.propeties 里面的属性和 XML 文件的 SQL 信息
 */
public class Configuration {

    private String jdbcDriver;

    private String jdbcUrl;

    private String jdbcPassword;

    private String jdbcUsername;

    private Map<String, MappedStatement> mappedStatement = new HashMap<>();

    public Map<String, MappedStatement> getMappedStatement() {
        return mappedStatement;
    }

    public void setMappedStatement(Map<String, MappedStatement> mappedStatement) {
        this.mappedStatement = mappedStatement;
    }

    public String getJdbcDriver() {
        return jdbcDriver;
    }

    public void setJdbcDriver(String jdbcDriver) {
        this.jdbcDriver = jdbcDriver;
    }

    public String getJdbcUrl() {
        return jdbcUrl;
    }

    public void setJdbcUrl(String jdbcUrl) {
        this.jdbcUrl = jdbcUrl;
    }

    public String getJdbcPassword() {
        return jdbcPassword;
    }

    public void setJdbcPassword(String jdbcPassword) {
        this.jdbcPassword = jdbcPassword;
    }

    public String getJdbcUsername() {
        return jdbcUsername;
    }

    public void setJdbcUsername(String jdbcUsername) {
        this.jdbcUsername = jdbcUsername;
    }
}
import com.java.mybatishandwriting.utis.Configuration;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 加载配置文件配置信息
 */

public class GetProperties {
    private Configuration configuration;

    public GetProperties(Configuration configuration) {
        this.configuration = configuration;
    }

    public GetProperties() {
    }

    // 数据库信息存放的位置
    public Properties loadDBInfo() {
        InputStream db = this.getClass().getClassLoader().getResourceAsStream("application.properties");
        Properties p = new Properties();
        try {
            p.load(db);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("driver:" + p.get("jdbc.driver").toString());
        System.out.println("url:" + p.get("jdbc.url").toString());
        System.out.println("username:" + p.get("jdbc.username").toString());
        System.out.println("password:" + p.get("jdbc.password").toString());
        //将配置信息写入Configuration 对象
        configuration.setJdbcDriver(p.get("jdbc.driver").toString());
        configuration.setJdbcUrl(p.get("jdbc.url").toString());
        configuration.setJdbcUsername(p.get("jdbc.username").toString());
        configuration.setJdbcPassword(p.get("jdbc.password").toString());

        return p;
    }
}

2)解析mapper xml文件

/**
 * 加载写 SQL 语句的 XML 文件,上面我们说过要注意四个点,namespace、id、resultType、SQL 语句,我们写对应的属性来保存它
 */
public final class MappedStatement {

    private String namespace;

    private String id;

    private String resultType;

    private String sql;

    public String getNamespace() {
        return namespace;
    }

    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getResultType() {
        return resultType;
    }

    public void setResultType(String resultType) {
        this.resultType = resultType;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

}
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.java.mybatishandwriting.utis.Configuration;
import com.java.mybatishandwriting.utis.MappedStatement;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 解析mapper  xml文件
 */
public class GetMapperInfo {
    // xml 文件存放的位置
    private static final String MAPPER_CONFIG_LOCATION = "mappers";
    private Configuration configuration;

    public GetMapperInfo(Configuration configuration) {
        this.configuration = configuration;
    }

    public GetMapperInfo() {
    }

    //解析并加载xml文件
    public void loadMapperInfo() {
        URL resources = null;
        resources = this.getClass().getClassLoader().getResource(MAPPER_CONFIG_LOCATION);
        File mappers = new File(resources.getFile());
        //读取文件夹下面的文件信息
        if (mappers.isDirectory()) {
            File[] files = mappers.listFiles();
            for (File file : files) {
                loadMapperInfo(file);
            }
        }
    }

    public void loadMapperInfo(File file) {
        SAXReader reader = new SAXReader();
        //通过read方法读取一个文件转换成Document 对象
        Document document = null;
        try {
            document = reader.read(file);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        //获取根结点元素对象<mapper>
        Element e = document.getRootElement();
        //获取命名空间namespace
        String namespace = e.attribute("namespace").getData().toString();
        //获取select,insert,update,delete子节点列表
        List<Element> selects = e.elements("select");
        List<Element> inserts = e.elements("insert");
        List<Element> updates = e.elements("update");
        List<Element> deletes = e.elements("delete");

        List<Element> all = new ArrayList<>();
        all.addAll(selects);
        all.addAll(inserts);
        all.addAll(updates);
        all.addAll(deletes);
        for (Element ele : all) {
            String id = ele.attribute("id").getData().toString();
            String resultType = ele.attribute("resultType").getData().toString();
            String sql = ele.getData().toString();

            System.out.println("id:" + id);
            System.out.println("resultType:" + resultType);
            System.out.println("sql:" + sql);
            MappedStatement mappedStatement = new MappedStatement();

            mappedStatement.setId(namespace + "." + id);
            mappedStatement.setResultType(resultType);
            mappedStatement.setNamespace(namespace);
            mappedStatement.setSql(sql);
            // xml 文件中的每个 sql 方法都组装成 mappedStatement 对象,以 namespace+"."+id 为 key, 放入
            // configuration 配置类中。
            configuration.getMappedStatement().put(namespace + "." + id, mappedStatement);

        }
    }

}

3)构建 SqlSessionFactory

public interface SqlSessionFactory {
    SqlSession openSession();
}
import com.java.mybatishandwriting.utis.Configuration;

/**
 * 构建 SqlSessionFactory
 */
public class DefaultSqlSessionFactory implements SqlSessionFactory {

    private final Configuration configuration = new Configuration();

    // xml 文件存放的位置
    private static final String MAPPER_CONFIG_LOCATION = "mappers";

    // 数据库信息存放的位置
    private static final String DB_CONFIG_FILE = "db.properties";


    public DefaultSqlSessionFactory() {
        loadDBInfo();
        loadMapperInfo();
    }

    private void loadDBInfo() {
        GetProperties getProperties = new GetProperties(configuration);
        getProperties.loadDBInfo();
    }

    //解析并加载xml文件
    private void loadMapperInfo() {
        GetMapperInfo getMapperInfo = new GetMapperInfo(configuration);
        getMapperInfo.loadMapperInfo();

    }

    @Override
    public SqlSession openSession() {
        // openSession 方法创建一个 DefaultSqlSession,configuration 配置类作为 构造函数参数传入
        return new DefaultSqlSession(configuration);
    }
}

4)通过SqlSessionFactory 获得 SqlSession

import java.util.List;

public interface SqlSession {
    /**
     * 根据传入的条件查询单一结果
     *
     * @param statement namespace+id,可以用做 key,去 configuration 里面获取 sql 语句,resultType
     * @param parameter 要传入 sql 语句中的查询参数
     * @param <T>       返回指定的结果对象
     * @return
     */
    <T> T selectOne(String statement, Object parameter);

    <T> List<T> selectList(String statement, Object parameter);

    <T> T getMapper(Class<T> type);
}
import com.java.mybatishandwriting.utis.Configuration;
import com.java.mybatishandwriting.utis.MappedStatement;

import java.util.List;

import java.lang.reflect.Proxy;

public class DefaultSqlSession implements SqlSession {

    private final Configuration configuration;

    private Executor executor;

    public DefaultSqlSession(Configuration configuration) {
        super();
        this.configuration = configuration;
        executor = new SimpleExecutor(configuration);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        List<T> selectList = this.selectList(statement, parameter);
        if (selectList == null || selectList.size() == 0) {
            return null;
        }
        if (selectList.size() == 1) {
            return (T) selectList.get(0);
        } else {
            throw new RuntimeException("too many result");
        }
    }

    @Override
    public <T> List<T> selectList(String statement, Object parameter) {
        MappedStatement ms = configuration.getMappedStatement().get(statement);
        // 我们的查询方法最终还是交给了 Executor 去执行,Executor 里面封装了 JDBC 操作。传入参数包含了 sql 语句和 sql 语句需要的参数。
        return executor.query(ms, parameter);
    }

    @Override
    public <T> T getMapper(Class<T> type) {
        //通过动态代理生成了一个实现类,我们重点关注,动态代理的实现,它是一个 InvocationHandler,传入参数是 this,就是 sqlSession 的一个实例。
        MapperProxy mp = new MapperProxy(this);
        //给我一个接口,还你一个实现类
        return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, mp);
    }
}

5)定义了数据库操作的最基本的方法

import com.java.mybatishandwriting.utis.MappedStatement;

import java.util.List;

/**
 * mybatis 核心接口之一,定义了数据库操作的最基本的方法,JDBC,sqlSession的所有功能都是基于它来实现的
 */
public interface Executor {
    /**
     * 查询接口
     *
     * @param ms        封装sql 语句的 mappedStatemnet 对象,里面包含了 sql 语句,resultType 等。
     * @param parameter 传入sql 参数
     * @param <E>       将数据对象转换成指定对象结果集返回
     * @return
     */
    <E> List<E> query(MappedStatement ms, Object parameter);
}
import com.java.mybatishandwriting.utis.Configuration;
import com.java.mybatishandwriting.utis.MappedStatement;
import com.java.mybatishandwriting.utis.ReflectionUtil;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {

    private final Configuration configuration;

    public SimpleExecutor(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter) {
        System.out.println(ms.getSql().toString());

        List<E> ret = new ArrayList<>(); //返回结果集
        try {
            Class.forName(configuration.getJdbcDriver());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = DriverManager.getConnection(configuration.getJdbcUrl(), configuration.getJdbcUsername(), configuration.getJdbcPassword());
            String regex = "#\\{([^}])*\\}";
            // 将 sql 语句中的 #{userId} 替换为 ?
            String sql = ms.getSql().replaceAll(regex, "");
            preparedStatement = connection.prepareStatement(sql);
            //处理占位符,把占位符用传入的参数替换
            parametersize(preparedStatement, parameter);
            resultSet = preparedStatement.executeQuery();
            handlerResultSet(resultSet, ret, ms.getResultType());
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                resultSet.close();
                preparedStatement.close();
                connection.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return ret;
    }


    private void parametersize(PreparedStatement preparedStatement, Object parameter) throws SQLException {
        if (parameter instanceof Integer) {
            preparedStatement.setInt(1, (int) parameter);
        } else if (parameter instanceof Long) {
            preparedStatement.setLong(1, (Long) parameter);
        } else if (parameter instanceof String) {
            preparedStatement.setString(1, (String) parameter);
        }
    }

    private <E> void handlerResultSet(ResultSet resultSet, List<E> ret, String className) {
        Class<E> clazz = null;
        //通过反射获取类对象
        try {
            clazz = (Class<E>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            while (resultSet.next()) {
                Object entity = clazz.newInstance();
                //通过反射工具 将 resultset 中的数据填充到 entity 中
                ReflectionUtil.setPropToBeanFromResultSet(entity, resultSet);
                ret.add((E) entity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

6)将请求转发给 sqlSession

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;

/**
 * 将请求转发给 sqlSession
 */
public class MapperProxy implements InvocationHandler {

    private SqlSession sqlSession;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getDeclaringClass().getName() + "." + method.getName());
        //最终还是将执行方法转给 sqlSession,因为 sqlSession 里面封装了 Executor
        //根据调用方法的类名和方法名以及参数,传给 sqlSession 对应的方法
        if (Collection.class.isAssignableFrom(method.getReturnType())) {
            return sqlSession.selectList(method.getDeclaringClass().getName() + "." + method.getName(), args == null ? null : args[0]);
        } else {
            return sqlSession.selectOne(method.getDeclaringClass().getName() + "." + method.getName(), args == null ? null : args[0]);
        }
    }
}

7)反射,返回结果直接封装到 JavaBean 中

import com.java.mybatishandwriting.pojo.User;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 反射工具类
 *
 * @author ys
 */
public class ReflectionUtil {
    /**
     * 为指定的beanpropName属性的值设置为value
     *
     * @param bean    目标对象
     * @param proName 对象的属性名
     * @param value   值
     */
    public static void   setPropToBean(Object bean, String proName, Object value) {
        Field f;
        try {
            //获取对象指定的属性
            f = bean.getClass().getDeclaredField(proName);
            //将字段设置为可通过反射访问
            f.setAccessible(true);
            //为属性赋值
            f.set(bean, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 从resultSet中读取一行数据,并填充到指定的实体bean
     *
     * @param entity    待填充的实体bean
     * @param resultSet 从数据库中加载的数据
     * @throws SQLException
     */
    public static void setPropToBeanFromResultSet(Object entity, ResultSet resultSet) throws SQLException {
        //通过反射获取对象的所有字段
        Field[] declaredFields = entity.getClass().getDeclaredFields();
        //遍历所有的字段,从resultSet中读取相应的电话机,并填充至对象的属性中
        for (int i = 0; i < declaredFields.length; i++) {
            //如果是字符串类型的数据
            if (declaredFields[i].getType().getSimpleName().equals("String")) {
                setPropToBean(entity, declaredFields[i].getName(), resultSet.getString(declaredFields[i].getName()));
                //如果是int类型
            } else if (declaredFields[i].getType().getSimpleName().equals("Integer")) {
                setPropToBean(entity, declaredFields[i].getName(), resultSet.getInt(declaredFields[i].getName()));
                //如果是long类型数据
            } else if (declaredFields[i].getType().getSimpleName().equals("Long")) {
                setPropToBean(entity, declaredFields[i].getName(), resultSet.getLong(declaredFields[i].getName()));
            }
        }
    }


    //测试
    public static void main(String[] args) {
        User user = new User();
        ReflectionUtil.setPropToBean(user, "userName", "ys");
        System.out.println(user.getUserName());
    }
}

8)测试

import org.junit.Test;

import java.util.Arrays;
import java.util.List;

public class MybatisTest {

    @Test
    public void loadProperties() {
//        getPropertiestest();
//        getMapperInfo();
        SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory();

        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        List<User> users = mapper.selectUserList();

        System.out.println(Arrays.asList(users));
    }

    private void getMapperInfo() {
        GetMapperInfo getMapperInfo = new GetMapperInfo();
        getMapperInfo.loadMapperInfo();
    }

    private void getPropertiestest() {
        GetProperties getProperties = new GetProperties();
        getProperties.loadDBInfo();
    }
}

参考文章
https://www.cnblogs.com/paulwang92115/p/12130224.html

PCL 计算点云包围球【2025最新版】 包围球通常用于简单排斥,因为与球体相交的方程很简单,同样重要的是,旋转一个球体并不会改变其范围。因此,当包围球用于简单排斥时,如果球体中心是对象的原点,则可以忽略对象的方向。 阅读详情

相关推荐

劳特巴赫 Trace32 调试使用教程

详细介绍如何使用trace32进行调试

m0_56208280的博客 4万+

Mybatis手撸(一)Mybatis简介和整体架构

热衷学习,热衷生活!😄 沉淀、分享、成长,让自己和他人都能有所收获!😄 一、Mybatis简介 MyBatis 官方文档 Mybatis是一款旨在帮助开发人员屏蔽底层重复性的JDBC代码的持久层框架,支持通过配置文件或者注解将ResultSet映射成Java对象。相对于其它ORM框架,Mybatis更为轻量级,支持定制化SQL和动态SQL,方便优化查询性能,同时包含了良好的缓存机制。 二、Mybatis整体架构 Mybatis整体架构如下图: 接口层 SqlSession接口层定义了暴露给应用程序调.

qq_34222160的博客 916

0009 用VisualStudio设计Max工具

这次分享个独家专利^)^:在Visual Studio中设计3dsMax脚本工具界面。 某次做原型设计时,需求改来改去,实在懒得搞GUI;虽然也尝试在Axure RP里画原型,但还是Visual Studio更顺手,也更容易测试一些交互,就直接在VS里做了。后来突发奇想,想实验一把能否直接用到Max里去,结果没想到成功了,效果还挺好。发现了新大陆,记录一下。   开始: 在VS里新建W...

whwst的专栏 769

手撸Mybatis(四)——连接数据库进行简单查询

这里将和结果相关的解析,抽取到parseResult方法中,此外,因为数据库是字段是下划线格式,类的属性是驼峰格式,因此,这里引入了Guava依赖,方便使用它的CaseFormat类进行格式转化。首先,我们修改DefaultMybatisSqlSession中,在该类中,执行我们的sql语句,其中,执行sql和对sql查询结果进行处理的内容,收敛在execute方法中。首先,我们修改MybatisSqlStatement,添加resultType字段。

weixin_55850954的博客 1378

Java云上香云祭祀线上祭祀系统小程序源码

云上香云祭祀线上祭祀系统”,不仅是一种祭祀方式的创新,更是对传统文化的一次深情致敬。它让我们明白,无论时代如何变迁,对亲人的怀念与尊重永远不会改变。在这个特别的平台上,让我们共同守护那份跨越时空的爱与思念,让心灵得以安放,让生命之树常青。🌳。

2401_84413757的博客 802

Plot3d 网格数据格式

PLOT3D是一个计算机图形程序,旨在可视化计算流体力学的网格和解决方案。PLOT3D文件可以是ASCII, 也可是Fortran unformatted 或 C binary形式。PLOT3D文件分为网格文件(XYZ 文件), 空气动力学结果文件 (Q 文件)和通用结果文件(函数文件 + 函数名称文件)。网格文件中可加入所谓的IBlank参数。

weixin_62592231的博客 3720

手撸Mybatis源码-基础版

放假闲来无事,重新看了一遍Mybatis,有感而发,记录下来。 What is Mybatis? 按照官方文档的说法: MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates alm...

码仔谢的博客 903

ESP8266+ITR8307实战:如何用反射式光电管实现5cm远距离检测(附避坑指南)

本文详细介绍了如何利用ESP8266的ADC功能与ITR8307反射式光电管,通过调制解调、硬件电路优化及软件同步采样策略,实现5cm稳定远距离检测。文章提供了完整的硬件设计、代码实现与调优避坑指南,有效解决了环境光干扰与信号衰减难题,适用于智能车、自动化等需要可靠非接触检测的项目。

rgv234567的博客 263

手撸一个mybatis自定义持久框架 [ 实现简单的单表 crud ]

自定持久框架 mybatis 前言 JDBC操作数据库和Mybatis操作数据库,为什么使用Mybatis框架,而不去使用原生过的JDBC操作数据库呢? 带着这么几个问题,我们先来看看原生的JDBC操作数据步骤! JDBC操作数据库步骤 1 加载驱动 2 创建连接 3 编译sql语句 4 设置参数 5 执行sql语句 6 获取结果返回集 7 关闭连接 JDBC操作数据库存在的几个痛点: 1 首先第一步加载驱动,这个我们完全可以通过反射来解决,更换不同的数据库驱动; 2 创建连接,每一次操作数据库都要去

. 763

炼金术士的试炼:2026年企业信用信息公示系统极验五维反爬下的Python数据博弈与破局之道

企业信用信息公示系统(以下简称“公示系统”)作为国家市场监督管理总局权威发布平台,承载着全国亿万市场主体的登记、许可、处罚等核心信用数据。对于金融风控、市场分析、商业尽职调查等领域,这些数据具有不可替代的黄金价值。然而,公示系统在2025年至2026年间进行了数次史诗级的安全加固,构建了包含动态令牌、极致混淆的JavaScript混淆、无感行为指纹、智能语义验证码以及WebAssembly防护在内的“五维反爬长城”。

2201_76125261的博客 348

如何用 Claude Code 做大型项目重构与架构优化

本文介绍了如何利用Claude Code参与大型项目重构。文章指出,大型项目重构的最大难点在于理解系统结构和控制风险,而非单纯修改代码。作者提出了五步重构法:首先分析项目结构,其次梳理模块依赖关系,然后发现架构问题,接着设计分阶段重构方案,最后逐步实施。重点强调了Claude Code的核心价值在于帮助开发者理解复杂系统、分析模块依赖、发现结构问题、评估改动风险,而非仅作为代码生成工具。文章建议将Claude Code作为架构助手,通过分阶段小范围重构来降低风险,而非一次性全面重构。

sg_knight的专栏 1571

手撸Mybatis(一)——代理mapper

在使用mybatis的时候,我们一般只需要定义mapper的接口,并添加相应的@Mapper注解,然后实现对应的xml文件即可,而不需要对mapper接口进行具体的实现。其实本质上,这些mapper接口是有实现的,但不是我们手动通过implement来实现,而是通过代理的方式进行实现。因此,对于Mybatis的手撸,首先要关注的,就是如何对mapper进行代理。像上述的这种方法,我们每次要获取一个Mapper,就要new一个对应的MapperProxyFactory,这样不太方便。然后创建对应的测试方法。

weixin_55850954的博客 586

微信公众号 - 超详细 H5 网页接入微信支付功能,开发网站微信支付最详细的教程示例代码(微信公众号前端支付 JS-SDK / JSAPI 微信H5授权登录支付,唤起微信支付)最新超级详细教程

H5页面接入微信支付功能,前端网页端怎么做微信JSAPI支付,vue网站接入微信JSSDK支付,vueH5项目如何做使用微信支付,端h5调用微信支付jsapi方法,前端vue开发的H5网站怎么微信支付最详细的教程示例代码,vue怎么调取微信支付流程,将H5接入微信支付退款,vue网站怎么搞微信支付,H5前端开发网站在微信环境内H5调起微信支付,react项目h5如何调用微信支付的方法,nuxt.js项目vueH5集成微信JS支付,网站怎么做出H5微信公众号支付,请问vue.js这个框

🏆 前端领域优质创作者 8124

手撸Spring系列11:MyBatis(理论篇)

说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。 手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为 IOC/DI 思想、 Spring MVC、 AOP 思想、 Spring JDBC 四个模块,并且每个模块都会分为 理论篇、 源码篇.

云丶言的博客 1492

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

《Mybatis 手撸专栏》第1章:开篇介绍,我要带你撸 Mybatis 啦

《Mybatis 手撸专栏》正式启动,此次内容会我们之前完成手写 Spring一样,拆解功能、简化流程、渐进实现,让读者能够更容易的学习到最有价值的知识。

bugstack虫洞栈 3293

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

面试官让我现场手写MyBatis框架,我10分钟就搞定了!!(全程实战,建议收藏)

很多小伙伴不知道像MyBatis和Hibernate这种ORM框架是如何实现的,今天,我们就手撸一个ORM框架,看看ORM框架到底是如何实现的!全程实战,建议收藏!

冰河的专栏 1万+

手撸Spring系列12:MyBatis(源码篇)

说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。 手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为 IOC/DI 思想、 Spring MVC、 AOP 思想、 Spring JDBC 四个模块,并且每个模块都会分为 理论篇、 源码篇.

云丶言的博客 1500

基于Mybatis手撸一个分表插件

大家好,我是摸鱼失败的阿星背景事情是酱紫的,阿星的上级leader负责记录信息的业务,每日预估数据量是15万左右,所以引入sharding-jdbc做分表。上级leader完成业务的开发后,走了一波自测,git push后,就忙其他的事情去了。项目的框架是SpringBoot+Mybaits出问题了阿星负责的业务也开发完了,熟练的git pull,准备自测,单元测试run一下,上个厕所回来收工,就是这么自信。回来后,看下控制台,人都傻了,一片红,内心不禁感叹“如果这是股票基金该多好”。出了问题就要解决,随着

程序猿阿星 3462

手撸MyBatis(一)源码解析

概述 MyBatis是大家最熟悉的ORM框架,大家基本都会用,那如果面试官问到MyBatis的实现原理该如何回答呢?本文将带大家过一下MyBatis的源码,好对MyBatis有一个更深刻的认识。 MyBatis的基本操作 先带大家过一下MyBatis的使用过程,这里是没有整合Spring,就是纯粹的MyBatis。 1)创建表: drop table if exists user; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT,

恒哥的博客 731

拜托别再问我Mybatis-66个类手撸一个Mybatis

之前出了一套《吃透Mybatis源码》,本篇文章是整体性的概括一下Mybatis的底层实现流程,以《66个类手撸Mybatis》为基础进行讲解,代码已经上传到Gitee,希望对你有所帮助相比Spring来说Mybatis的源码是相对简单的,你可以通过上面的源码去深入理解Mybatis核心机制,当然这里的源码只是实现了简单的单个对象查询,时间关系其中很多细节是没有去实现的,但是毫不影响你对Mybatis的理解或者用于面试吊打面试官了。建议你对着图多看几遍。

墨家巨子@俏如来 1406

基于 MyBatis 手撸一个分表插件

*** @Description 分表策略日期*/@Component@Override} else {*** @Author 张三* @Description 分表策略id*/@Component@Override//可以加入本地缓存优化Mapper接口/*** @Author 张三*//*** 查询列表-根据日期分表*//*** 单插入-根据日期分表*//*** @Author 张三*//*** 根据id查询-根据id分片*/

程序员高级码农的博客 1031

手撸Spring系列博客目录

说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。 手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为 IOC/DI 思想、 Spring MVC、 AOP 思想、 Spring JDBC 四个模块,并且每个模块都会分为 理论篇、 源码篇.

云丶言的博客 1474

手撸Spring系列13:MyBatis(实战篇)

说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。 手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为 IOC/DI 思想、 Spring MVC、 AOP 思想、 Spring JDBC 四个模块,并且每个模块都会分为 理论篇、 源码篇.

云丶言的博客 1286

【撸源码】【mybatis-plus】乐观锁和逻辑删除是如何工作的——上篇

至此,mp将所有表数据缓存的逻辑已经全部完成了。回想2.1.1中所说,这里一定会有值,那么这里一定是全部的表吗?整合一下这个方法的调用链简简单单,又是一篇,至此,逻辑删除的全部工作原理已经完全清晰。逻辑删除很有用,并且拥有较为强大的能力,但一些细节的处理不足,还有一些特殊的要求是无法满足的,此时就需要屏幕前的你大展拳脚给增强一下了。基础组件的升级需要谨慎谨慎再谨慎,一不小心,整个公司的系统都会被你全部干瘫痪了。感悟读源码到底有没有用处?我理解的源码好处是。

Rubik Blog 1173

《Mybatis 手撸专栏》第8章:把反射用到出神入化

在 Mybatis 中一块内容把反射包装使用的非常强大,也正因为有了这块反射框架的包装,才让 Mybatis 中一些处理对象元素值变得更加方便。PS:也是你看不懂的地方!

bugstack虫洞栈 1577

Mybatis学习(四):Mybatis源码深度分析

Mybatis学习(四):Mybatis源码深度分析前言一、Mybatis的架构设计二、Mybatis的源码分析三、Mybatis框架之设计模式 前言 接上篇:Mybatis学习(三):Mybatis注解开发、缓存使用和插件使用的深度分析 本篇笔者将深入学习下Mybatis的架构设计、源码分析、Mybatis框架所用到的Java设计模式 一、Mybatis的架构设计 二、Mybatis的源码分析 三、Mybatis框架之设计模式 ...

RabbitInTheGrass的博客 3860

框架源码学习要从Mybatis开始!

Mybatis虽然小,但是五脏俱全,而且设计精湛。 这个黑盒背后是怎样一个设计,下面讲讲我的理解 一、容器Configuration Configuration像是Mybatis的总管,Mybatis的所有配置信息都存放在这里,此外,它还提供了设置这些配置信息的方法。Configuration可以从配置文件里获取属性值,也可以通过程序直接设置。 用一句话概述Configuration,他类似Spring中的容器概念,而且是中央容器级别,存储的Mybatis运行所需要的大部分东西。 二、动态SQL.

Java圈全能架构师的博客 543
上一篇: IDEA日常使用记录
下一篇: java自定义注解深入学习
沐果果
博客等级 码龄10年 19粉丝 85原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值