MyBatis 源码解析 面试题总结

news2024/11/22 17:09:36

MyBatis源码学习环境下载

文章目录

    • 1、工作原理
      • 1.1 初始化
        • 1.1.1 系统启动的时候,加载解析全局配置文件和相应的映射文件
        • 1.1.2 建造者模式帮助我们解决复杂对象的创建:
      • 1.2 处理SQL请求的流程
        • 1.2.1 通过sqlSession中提供的API方法来操作数据库
        • 1.2.2 获取接口的代码对象-得到的其实是 通过JDBC代理模式获取的一个代理对象
        • 1.2.3 处理完请求之后,需要关闭会话SqlSession
      • 1.3 底层
        • 1.3.1 原理图:
        • 1.3.2 源码结构:
    • 2、MyBatis中的缓存
      • 2.1 缓存的作用
      • 2.2 缓存的设计
        • 2.2.1 架构设计
        • 2.2.2 一级缓存和二级缓存
          • 一级缓存:session级别,默认开启
          • 开启二级缓存:
        • 2.2.3 缓存的处理顺序
          • 2.2.3.1 先在二级缓存中查找
          • 2.2.3.2 Executor.query()先走一级缓存查询,一级缓存也没有的话,则进行DB查询
    • 3、如何扩展MyBatis中的缓存
      • 3.1 架构理解
      • 3.2 实际开发
        • 3.2.1 自定义三级缓存
    • 4、MyBatis中的涉及的设计模式
      • 4.1 从整体架构设计分析
        • 4.1.1 基础模块:
          • cache缓存模块:装饰器模式
          • logging日志模块:适配器模式、策略模式、代理模式
          • reflection反射模块:工程模式、装饰器模式
          • datasource数据源:工程模式
          • transaction事务模块:工厂模式
          • SqlSessionFactory:SqlSessionFactoryBuilder建造者模式
    • 5、谈谈你对SqlSessionFactory的理解
    • 6、谈谈你读SqlSession的理解
      • 6.1 SqlSession
      • 6.2 SqlSession的安全问题
        • 6.2.1 非线程安全:
        • 6.2.2 Spring中是如何解决DefaultSqlSession的数据安全问题?
    • 7、谈谈你对MyBatis的理解
    • 8、谈谈MyBatis中分页的理解
      • 8.1 谈谈分页的理解:
      • 8.2 分页的实现
        • 8.2.1 逻辑分页:RowBounds
        • 8.2.2 物理分页:拦截器实现,执行分页语句的组装
    • 9、谈谈MyBatis中的插件原理
      • 9.1 插件设计的目的:
      • 9.2 实现原理:
        • 9.2.1 创建自定义Java类,通过@Interceptor注解来定义相关的方法签名
        • 9.2.2 在对应的配置文件中通过plugin来注册自定义的拦截器
        • 9.2.3 拦截器的作用
    • 10、不同Mapper中的id是否可以相同?
    • 11、谈谈对MyBatis架构设计的理解
      • 11.1 接口层
      • 11.2 核心层
      • 11.3 基础模块
    • 12、谈谈对传统JDBC开发的不足
    • 13、MyBatis中数据源模块的设计
      • 连接池工作原理
    • 14、MyBatis中事务模块的设计
      • 14.1 事务的理解ACID
      • 14.2 MyBatis中的事务
        • 14.2.1 事务的配置
        • 14.2.2 事务接口的定义:定义了事务的基本行为
        • 14.2.3 在MyBatis中的事务管理有两个选择
        • 14.2.4 如何设置事务管理的方式
        • 14.2.5 在MyBatis中执行DML操作事务的处理逻辑
    • 15、谈谈你对Mapper接口的设计理解
      • 15.1 接口的对应的规则
      • 15.2 接口的设计原理
      • 15.3 代理对象执行的逻辑的本质还是会执行SqlSession中相关的DML操作的方法
      • 15.4 为何要多包一层代理对象
    • 16、谈谈你对Reflector模块的理解
    • 17、MyBatis的类型转换模块
    • 18、整合MyBatis
      • 18.1 单纯Spring整合MyBatis
      • 18.2 SpringBoot整合MyBatis

1、工作原理

1.1 初始化

1.1.1 系统启动的时候,加载解析全局配置文件和相应的映射文件

// 1.获取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

全局配置文件:mybatis-config.xml

映射文件:mapper/*.xml

// 2.加载解析配置文件并获取 SqlSessionFactory 对象
// SqlSessionFactory 的实例我们没有通过 DefaulSqlSessionFactory 直接来获取
// 而是通过一个 Builder 对象来建造的
// SqlSessionFactory 生产 SqlSession 对象的 SqlSessionFactory 应该是单例
// 全局配置文件和映射文件 也只需要在 系统启动的时候完成加载操作
// 通过建造者模式来 构建复杂的对象: 1.完成配置文件的加载解析  2.完成 SqlSessionFactory 的创建
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

加载解析的相关信息存储在SqlSessionFactory对象的Configuration属性里,

1.1.2 建造者模式帮助我们解决复杂对象的创建:

  1. 完成配置文件的加载解析
  2. 完成 SqlSessionFactory 的创建

1.2 处理SQL请求的流程

通过工厂得到SqlSession对象

// 3.根据 SqlSessionFactory 对象获取 SqlSession 对象
SqlSession sqlSession = factory.openSession();

1.2.1 通过sqlSession中提供的API方法来操作数据库

// 4.通过sqlSession中提供的API方法来操作数据库
List<User> list = sqlSession.selectList("com.boge.mapper.UserMapper.selectUserList");

1.2.2 获取接口的代码对象-得到的其实是 通过JDBC代理模式获取的一个代理对象

// 获取接口的代码对象-得到的其实是 通过JDBC代理模式获取的一个代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

1.2.3 处理完请求之后,需要关闭会话SqlSession

//5.关闭会话
sqlSession.close();//关闭session  清空一级缓存

1.3 底层

全局配置文件的加载解析:Configuration

映射文件的加载解析:Configuration.mappedStatements

/**
     * MappedStatement 映射
     *
     * KEY:`${namespace}.${id}`
     */
    protected final Map<String, MappedStatement> mappedStatements = new StrictMap<>("Mapped Statements collection");

生产了DefaultSqlsession实例对象,完成了Executor对象的创建,以及二级缓存CachingExecutor的装饰,同时完成了插件逻辑的植入。

selectOne():二级缓存->一级缓存->数据库插入

    // 1. 读取配置文件,读成字节输入流,注意:现在还没解析
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

    // 2. 解析配置文件,封装Configuration对象   创建DefaultSqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

    // 3. 生产了DefaultSqlsession实例对象   设置了事务不自动提交  完成了executor对象的创建
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 4.(1)根据statementid来从Configuration中map集合中获取到了指定的MappedStatement对象
       //(2)将查询任务委派了executor执行器
    User user =  sqlSession.selectOne("com.lagou.mapper.IUserMapper.findById",1);
    System.out.println(user);

    User user2 =  sqlSession.selectOne("com.lagou.mapper.IUserMapper.findById",1);
    System.out.println(user2);

    // 5.释放资源
    sqlSession.close();

1.3.1 原理图:

在这里插入图片描述

1.3.2 源码结构:

在这里插入图片描述

2、MyBatis中的缓存

2.1 缓存的作用

降低数据源的访问频率,从而提高数据源的处理能力,提高服务器的响应速度。

2.2 缓存的设计

2.2.1 架构设计

在这里插入图片描述

通过装饰者模式对Cache接口的工作做增强

在这里插入图片描述

装饰者作用
BlockingCache阻塞的 Cache 实现类
FifoCache基于先进先出的淘汰机制的 Cache 实现类
LoggingCache支持打印日志的 Cache 实现类
LruCache基于最少使用的淘汰机制的 Cache 实现类
ScheduledCache定时清空整个容器的 Cache 实现类
SerializedCache支持序列化值的 Cache 实现类
SoftCache软引用缓存装饰器
SynchronizedCache同步的 Cache 实现类
TransactionalCache支持事务的 Cache 实现类,主要用于二级缓存中
WeakCache弱引用缓存装饰器

2.2.2 一级缓存和二级缓存

一级缓存:session级别,默认开启
<!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 -->
<setting name="localCacheScope" value="STATEMENT"/>

二级缓存:SqlSessionFactory级别(工厂/进程级别)

开启二级缓存:
  • 在mybatis配置文件中配置cacheEnabled为true

    <!-- 控制全局二级缓存,默认ture-->
    <setting name="cacheEnabled" value="true"/>
    <!-- 延迟加载的全局开关。开启时,所有关联对象都会延迟加载。默认false -->
    <setting name="lazyLoadingEnabled" value="true"/>
    
  • 在映射文件中添加cache标签,可以在cache标签中更细致的增加配置

    <!--二级缓存开启-->
    <cache />
    
  • 命名空间下的所有标签放开二级缓存

  • 可以通过在标签中添加 useCache=false 指定api不走二级缓存

mybatis-config.xml

在这里插入图片描述

2.2.3 缓存的处理顺序

  • 获取mapper映射文件中cache标签里的配置MappedStatement.getCache()
  • 如果cache配置不为空,从二级缓存中查找(List) TransactionalCacheManager.getObject(cache, key);
  • 如果没有值,则执行查询, Executor.query()这个查询实际也是先走一级缓存查询,
  • 一级缓存也没有的话,则进行DB查询
  • 先将查询到的结果放入缓存TransactionalCacheManager.putObject(cache, key, list),再返回结果
2.2.3.1 先在二级缓存中查找

原因:找到概率更高,性能角度。

一级缓存二级缓存
作用域SqlSession级别SqlSessionFactory级别
找到概率5%90%
    @Override
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
            throws SQLException {

        // 从 MappedStatement 中获取 Cache,注意这里的 Cache 是从MappedStatement中获取的
        // 也就是我们上面解析Mapper中<cache/>标签中创建的,它保存在Configration中
        // 我们在初始化解析xml时分析过每一个MappedStatement都有一个Cache对象,就是这里
        Cache cache = ms.getCache();

        // 如果配置文件中没有配置 <cache>,则 cache 为空
        if (cache != null) {
            //如果需要刷新缓存的话就刷新:flushCache="true"
            flushCacheIfRequired(ms);
            if (ms.isUseCache() && resultHandler == null) {
                // 暂时忽略,存储过程相关
                ensureNoOutParams(ms, boundSql);
                @SuppressWarnings("unchecked")
                // 从二级缓存中,获取结果
                List<E> list = (List<E>) tcm.getObject(cache, key);
                if (list == null) {
                    // 如果没有值,则执行查询,这个查询实际也是先走一级缓存查询,一级缓存也没有的话,则进行DB查询
                    list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                    // 缓存查询结果
                    tcm.putObject(cache, key, list); // issue #578 and #116
                }
                // 如果存在,则直接返回结果
                return list;
            }
        }
        // 不使用缓存,则从数据库中查询(会查一级缓存)
        return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
2.2.3.2 Executor.query()先走一级缓存查询,一级缓存也没有的话,则进行DB查询
    /**
     * 记录嵌套查询的层级
     */
    protected int queryStack;
    /**
     * 本地缓存,即一级缓存
     */
    protected PerpetualCache localCache;

    @SuppressWarnings("unchecked")
    @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());
        // 已经关闭,则抛出 ExecutorException 异常
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        // 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。
        if (queryStack == 0 && ms.isFlushCacheRequired()) {
            clearLocalCache();
        }
        List<E> list;
        try {
            // queryStack + 1
            queryStack++;
            // 从一级缓存中,获取查询结果
            list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
            // 获取到,则进行处理
            if (list != null) {
                handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
            // 获得不到,则从数据库中查询
            } else {
                list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
            }
        } finally {
            // queryStack - 1
            queryStack--;
        }
        if (queryStack == 0) {
            // 执行延迟加载
            for (DeferredLoad deferredLoad : deferredLoads) {
                deferredLoad.load();
            }
            // issue #601
            // 清空 deferredLoads
            deferredLoads.clear();
            // 如果缓存级别是 LocalCacheScope.STATEMENT ,则进行清理
            if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                // issue #482
                clearLocalCache();
            }
        }
        return list;
    }

3、如何扩展MyBatis中的缓存

3.1 架构理解

3.2 实际开发

/**
 * 永不过期的 Cache 实现类,基于 HashMap 实现类
 *
 * @author Clinton Begin
 */
public class PerpetualCache implements Cache {
    /**
     * 缓存容器
     */
    private Map<Object, Object> cache = new HashMap<>();
        @Override
    public void putObject(Object key, Object value) {
        cache.put(key, value);
    }
}

3.2.1 自定义三级缓存

创建Cache接口的实现,重写putObject和getObject方法

在mapper映射文件中的cache标签里增加type属性,关联自定义的Cache接口的实现

<cache type="org.mybatis.caches.ehcache.EhcacheCache" />

如果未添加type,会默认读取 PERETUAL (二级缓存)

4、MyBatis中的涉及的设计模式

4.1 从整体架构设计分析

4.1.1 基础模块:

cache缓存模块:装饰器模式

Cache接口 定义了缓存的基本行为

PerpetualCache基于Cache实现,针对于缓存的功能 1.缓存数据淘汰;2.缓存数据的存放机制;3.缓存数据添加是否同步【阻塞】;4.缓存对象是否同步处理…做了增强处理–>代理模式

以及很多装饰类,灵活增强出适用于不同业务场景的Cache实现

logging日志模块:适配器模式、策略模式、代理模式

帮助我们适配不同的日志框架

Log接口针对不同日志框架,有不同的实现类,做增强处理

reflection反射模块:工程模式、装饰器模式
datasource数据源:工程模式
transaction事务模块:工厂模式
SqlSessionFactory:SqlSessionFactoryBuilder建造者模式

5、谈谈你对SqlSessionFactory的理解

  • 目的:创建SqlSession对象
  • 单例,在应用程序(服务)中只保存唯一的一份
  • SqlSessionFactory对象的创建是通过SqlSessionFactoryBuilder,
  • 同时也完成了全局配置文件Configuration和相关映射文件Mapper的加载和解析操作。
  • 涉及到了工厂模式和建造者模式
    /**
     * 构造 SqlSessionFactory 对象
     *
     * @param reader Reader 对象
     * @param environment 环境
     * @param properties Properties 变量
     * @return SqlSessionFactory 对象
     */
    @SuppressWarnings("Duplicates")
    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        try {
            // 创建 XMLConfigBuilder 对象
            XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
            // 执行 XML 解析
            // 创建 DefaultSqlSessionFactory 对象
            return build(parser.parse());
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
            ErrorContext.instance().reset();
            try {
                reader.close();
            } catch (IOException e) {
                // Intentionally ignore. Prefer previous error.
            }
        }
    }

    /**
    * 1.我们最初调用的build
    */
    public SqlSessionFactory build(InputStream inputStream) {
        //调用了重载方法
        return build(inputStream, null, null);
    }

    /**
     * 解析 XML
     *
     * 具体 MyBatis 有哪些 XML 标签,参见 《XML 映射配置文件》http://www.mybatis.org/mybatis-3/zh/configuration.html
     *
     * @param root 根节点
     */
    private void parseConfiguration(XNode root) {
        try {
            //issue #117 read properties first
            // 解析 <properties /> 标签
            propertiesElement(root.evalNode("properties"));
            // 解析 <settings /> 标签
            Properties settings = settingsAsProperties(root.evalNode("settings"));
            // 加载自定义的 VFS 实现类
            loadCustomVfs(settings);
            // 解析 <typeAliases /> 标签
            typeAliasesElement(root.evalNode("typeAliases"));
            // 解析 <plugins /> 标签
            pluginElement(root.evalNode("plugins"));
            // 解析 <objectFactory /> 标签
            objectFactoryElement(root.evalNode("objectFactory"));
            // 解析 <objectWrapperFactory /> 标签
            objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            // 解析 <reflectorFactory /> 标签
            reflectorFactoryElement(root.evalNode("reflectorFactory"));
            // 赋值 <settings /> 到 Configuration 属性
            settingsElement(settings);
            // read it after objectFactory and objectWrapperFactory issue #631
            // 解析 <environments /> 标签
            environmentsElement(root.evalNode("environments"));
            // 解析 <databaseIdProvider /> 标签
            databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            // 解析 <typeHandlers /> 标签
            typeHandlerElement(root.evalNode("typeHandlers"));
            // 解析 <mappers /> 标签
            mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
    }

6、谈谈你读SqlSession的理解

6.1 SqlSession

  • 作用:通过相关API来实现对应的数据的操作

  • SqlSession对象的获取需要通SqlSessionFactory来实现,

  • 作用域是会话级别,当一个新的会话到来的时候,需要新建一个SqlSession对象;当一个会话结束后,需要关闭相关会话资源

  • 处理请求的方式:

    1.通过相关crud的API直接处理

    2.通过getMapper(xx.xml)来获取相关mapper接口的代理对象来处理

6.2 SqlSession的安全问题

6.2.1 非线程安全:

在这里插入图片描述

6.2.2 Spring中是如何解决DefaultSqlSession的数据安全问题?

  • DefaultSqlSession是非线程安全的,也就意味着我们不能把DefaultSqlSession声明在成员变量中。
  • 每个线程都应该有自己的SqlSession实例。
  • 最佳作用域是请求或方法作用域
  • 决不能将SqlSession实例引用放在一个类的静态域,甚至一个类的实例变量也不行。
  • 应该将SqlSession放在一个和HTTP请求相似的作用域中,每次请求打开一个SqlSession,返回一个响应后就关闭他,关闭操作放在finally块中。

在这里插入图片描述

  • Spring中提供了SqlSessionTemplate来实现SqlSession的相关定义。
  • 其中每一个方法都通过SqlSessionProxy来操作,这是一个动态代理对象。
  • 在动态代理对象中通过方法级别的DefaultSqlSession来实现相关的数据库操作。

7、谈谈你对MyBatis的理解

  • 使用频率最高的ORM框架、持久层框架
  • 提供了非常方便的API实现CRUD
  • 支持灵活的缓存处理方案,一级缓存、二级缓存、三级缓存
  • 支持相关的延迟数据加载处理
  • 还提供了非常多的灵活标签,来实现复杂的业务处理,if forech where trim set bind…
  • 相比Hibernate(全自动化)会更加灵活

8、谈谈MyBatis中分页的理解

8.1 谈谈分页的理解:

  • 数据库层面SQL:

    MySQL:LIMIT

    Oracle:rowid

8.2 分页的实现

8.2.1 逻辑分页:RowBounds

8.2.2 物理分页:拦截器实现,执行分页语句的组装

在这里插入图片描述

9、谈谈MyBatis中的插件原理

9.1 插件设计的目的:

方便开发人员实现对MyBatis功能的增强

设计中MyBatis允许映射语句执行过程中的某一点进行拦截调用,允许使用插件拦截的方法包括:

在这里插入图片描述

9.2 实现原理:

9.2.1 创建自定义Java类,通过@Interceptor注解来定义相关的方法签名

在这里插入图片描述

9.2.2 在对应的配置文件中通过plugin来注册自定义的拦截器

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>

9.2.3 拦截器的作用

  • 检查执行的SQL
  • 对执行SQL的参数做处理
  • 对查询的结果做装饰处理
  • 对查询SQL做分表处理

10、不同Mapper中的id是否可以相同?

可以相同,每一个映射文件的namespace都会设置为对应的mapper接口的全类路径名称

保证了每个Mapper映射文件的namespace是唯一的。

11、谈谈对MyBatis架构设计的理解

11.1 接口层

面向开发者,提供相关API

11.2 核心层

核心功能的实现:增删改查操作

11.3 基础模块

支撑核心层来完成核心的功能

在这里插入图片描述

12、谈谈对传统JDBC开发的不足

JDBCMyBatis
资源频繁的创建和释放数据库的连接对象,造成系统资源的浪费通过全局配置文件设置相关的数据连接池
sql维护sql语句直接写在了代码中,维护成本高,动态性要求较高sql语句写在Mapper映射文件中的标签里
参数向SQL中传递参数麻烦,where条件不一定,占位符和参数需要一一对应自动完成Java对象和SQL中参数的映射
结果集映射麻烦,需要循环封装,SQL本身的变化会导致解析的难度通过ResultHandler自动将结果集映射到Java对象
拓展不支持事务、缓存、延迟加载等功能提供了相关实现
性能运行性能更高开发效率更高

13、MyBatis中数据源模块的设计

在这里插入图片描述

完成相关标签的解析,存储在configuration中

    private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            // environment 属性非空,从 default 属性获得
            if (environment == null) {
                environment = context.getStringAttribute("default");
            }
            // 遍历 XNode 节点
            for (XNode child : context.getChildren()) {
                // 判断 environment 是否匹配
                String id = child.getStringAttribute("id");
                if (isSpecifiedEnvironment(id)) {
                    // 解析 `<transactionManager />` 标签,返回 TransactionFactory 对象
                    TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
                    // 解析 `<dataSource />` 标签,返回 DataSourceFactory 对象
                    DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
                    DataSource dataSource = dsFactory.getDataSource();
                    // 创建 Environment.Builder 对象
                    Environment.Builder environmentBuilder = new Environment.Builder(id)
                            .transactionFactory(txFactory)
                            .dataSource(dataSource);
                    // 构造 Environment 对象,并设置到 configuration 中
                    configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }
    }

在这里插入图片描述

  • UnpooledDataSource:非数据库连接池的实现
  • PooledDataSource:数据库连接池的实现
  • 从连接池中获取连接对象:如果有空闲连接直接返回,活跃连接数是否超过了最大连接数,是否有连接超时的连接
  • 数据库连接池关闭连接,如果空闲连接没有超过最大连接数那么就返回空闲队列中。
  • 否则关闭真实的连接。

连接池工作原理

在这里插入图片描述

14、MyBatis中事务模块的设计

14.1 事务的理解ACID

14.2 MyBatis中的事务

14.2.1 事务的配置

在这里插入图片描述

14.2.2 事务接口的定义:定义了事务的基本行为

在这里插入图片描述

14.2.3 在MyBatis中的事务管理有两个选择

JDBC:在MyBatis中自己处理事务的管理

Managed:在MyBatis中没有处理任何的事务操作,这种情况下事务的处理会交给Spring容器来管理

14.2.4 如何设置事务管理的方式

在这里插入图片描述

14.2.5 在MyBatis中执行DML操作事务的处理逻辑

SqlSession.commit()

15、谈谈你对Mapper接口的设计理解

15.1 接口的对应的规则

名称需要对应

15.2 接口的设计原理

代理模式的使用

在这里插入图片描述

创建动态代理对象

在这里插入图片描述

15.3 代理对象执行的逻辑的本质还是会执行SqlSession中相关的DML操作的方法

在这里插入图片描述

15.4 为何要多包一层代理对象

每调用一个mapper接口都需要在命名空间中指向接口路径

在这里插入图片描述

16、谈谈你对Reflector模块的理解

  • Reflector是MyBatis中提供的一个针对反射封装简化的模块:简化反射的相关操作。
  • 表结构的数据和Java对象中数据的映射,不可避免的会存在非常多的反射操作。
  • Reflector是一个独立的模块,可以把这个模块单独抽取出来,直接使用的。
  • 反射器,每个 Reflector 对应一个类。

在这里插入图片描述

反射模块的具体设计:

在这里插入图片描述

17、MyBatis的类型转换模块

MyBatis是如何解决Java中的类型和数据库中的字段类型的映射

在这里插入图片描述

类型处理器:

  • 写:Java类型 --> JDBC类型

  • 读:JDBC类型 --> Java类型

  • SQL操作:读 写

  • 本质上执行的JDBC操作:

    String sql = "SELECT id,user_name,phone from user where id = ? and user_name = ?";
    ps = conn.prepareStatement(sql);
    ps.setInt(1,2);
    ps.setString(2,"张三");
    

TypeHandler --> BaseTypeHandler —> 具体的TypeHandler

18、整合MyBatis

18.1 单纯Spring整合MyBatis

  • 添加mybatis-spring依赖

            <!-- mybatis 中间件 -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.2.2</version>
            </dependency>
    
  • 在spring配置文件spring-context.xml中添加数据源信息和sqlSessionFactory,将sqlSessionFactory注入容器

    	<!-- 数据源配置, 使用 BoneCP 数据库连接池 -->
    	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    	    <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
    	    <property name="driverClassName" value="${jdbc.driver}" />
    		<!-- 基本属性 url、user、password -->
    		<property name="url" value="${jdbc.url}" />
    		<property name="username" value="${jdbc.username}" />
    		<property name="password" value="${jdbc.password}" />
    		<!-- 配置初始化大小、最小、最大 -->
    		<property name="initialSize" value="${jdbc.pool.init}" />
    		<property name="minIdle" value="${jdbc.pool.minIdle}" />
    		<property name="maxActive" value="${jdbc.pool.maxActive}" />
    		<!-- 配置获取连接等待超时的时间 -->
    		<property name="maxWait" value="300000" />
    		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    		<property name="timeBetweenEvictionRunsMillis" value="60000" />
    		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    		<property name="minEvictableIdleTimeMillis" value="300000" />
    	</bean>
     	<!-- MyBatis begin -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!--关联数据源-->
            <property name="dataSource" ref="dataSource"/>
            <!--添加别名设置-->
            <property name="typeAliasesPackage" value="com.hlframe"/>
            <property name="typeAliasesSuperType" value="com.hlframe.common.persistence.BaseEntity"/>
            <!--映射文件和接口文件不在同一个目录下的时候,配置映射文件位置-->
            <property name="mapperLocations" value="classpath:/mappings/**/*.xml"/>
            <!--关联MyBatis的配置文件-->
    		<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
        </bean>
    

18.2 SpringBoot整合MyBatis

  • 添加mybatis-plus-boot-starter依赖

            <!--mybatis-plus-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
                <scope>provided </scope>
            </dependency>
    
  • 将sqlSessionFactory注入容器

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/417392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UOS内核替换kylin内核

一、替换UOS内核 如果可以获取UOS的的ROOT权限, 跳过步骤一和二。 步骤一、配置环境 如果有UOS系统的机器,则不需要安装,跳到步骤二 。 如果没有UOS系统则需要下载, 下载UOS镜像:统信UOS生态社区 - 打造操作系统创新生态 ,下载专业版需要用户注册大概1~3天可以通过,…

HTML-form表单和提交

网络请求 在浏览器的URL中写入地址&#xff0c;点击回车访问时 浏览器会发送数据过去&#xff0c;本质上发送的是字符串 浏览器向后端发送请求时 GET请求【URL方法/表单提交】 现象&#xff1a;向后台传入数据&#xff0c;数据会拼接在URL上 搜索百度时&#xff1a; http…

十四、Pytorch实现RNN Classifier

一、项目需求 数据集&#xff1a;姓名和对应的国籍 要求&#xff1a;输入一个姓名&#xff0c;通过模型可以得到TA所属的国籍 数据集下载&#xff1a;name_country_datasets 二、思路步骤分析 ①准备数据集 将下载好的数据集解压&#xff0c;放到一个指定的位置&#xff0c…

文心一格小程序,AI绘画产品

文章目录AIGC什么是AI作画&#xff1f;Prompt文心一格文心一格小程序使用方法使用小程序进行AI绘图AIGC的未来发展结语AIGC AIGC&#xff08;AI Generated Content&#xff09;是指利用人工智能生成内容。是利用人工智能来生成你所需要的内容&#xff0c;GC的意思是创作内容。与…

samba介绍和使用

一. 介绍 Samba是一套使用SMB(Server Message Block)协议的应用程序, 通过支持这个协议, Samba允许Linux服务器与Windows系统之间进行通信,使跨平台的互访成为可能。 Samba采用C/S模式, 其工作机制是让NetBIOS( Windows 网上邻居的通信协议)和SMB两个协议运行于TCP/IP通…

【Obsidian】基础使用手册(包括如何将Obsidian页面设置为中文)

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于工具类软件的笔记 &#x1f236;本篇是Obsidian的基础使用 Obsidian的基础使用将页面设置为中文常用的默认快捷键常用的格式标题代码块表格字体样式列表任务列表官方下载地址&am…

中国电子学会2022年12月份青少年软件编程Python等级考试试卷六级真题(含答案)

一、单选题(共25题&#xff0c;共50分) 1.数据文件“abc.txt”中包含若干个英文单词&#xff0c;如图所示&#xff1a; 读取文件“abc.txt”中数据的Python程序段如下&#xff1a; file abc.txt word_b [] for word in open(file):if word[0:1] a and len(word)>4:wor…

ASP学生公寓管理系统的设计与实现

学生公寓是每一位在校学生生活、学习、相互交流的主要场所&#xff0c;如何提供一个良好的学生公寓的管理体系&#xff0c;对学校和同学而言至关重要。以往的学生公寓管理基本上还处于人工操作的阶段&#xff0c;随着计算机技术和网络技术的日益广泛应用&#xff0c;采用计算机…

Oracle基础部分三(视图、物化视图、序列、同义词、索引)

Oracle基础部分三(视图、物化视图、序列、索引&#xff09;1 视图1.1概述1.2 创建普通视图1.2.1 创建普通视图1.2.2 创建带检查约束的视图1.2.3 创建只读视图的创建与使用1.2.4 强制创建视图1.2.5 创建复杂视图1.2.5.1 多表关联1.2.5.2 分组聚合统计的复杂视图1.3 创建物化视图…

强化学习简介

1.强化学习简介 **强化学习&#xff08;Reinforcement Learning&#xff0c;RL&#xff09;**是机器学习中的一个领域&#xff0c;是学习“做什么&#xff08;即如何把当前的情景映射成动作&#xff09;才能使得数值化的收益信号最大化”。学习者不会被告知应该采取什么动作&a…

CDN(内容分发网络)技术原理

1. 前言 Internet的高速发展&#xff0c;给人们的工作和生活带来了极大的便利&#xff0c;对Internet的服务品质和访问速度要求越来越高&#xff0c;虽然带宽不断增加&#xff0c; 用户数量也在不断增加&#xff0c;受Web服务器的负荷和传输距离等因数的影响&#xff0c;响应速…

认证 (authentication) 和授权 (authorization) 的区别

以前一直傻傻分不清各种网际应用中 authentication 和 authorization, 其实很简单: 这两个术语通常在安全性方面相互结合使用&#xff0c;尤其是在获得对系统的访问权限时。两者都是非常重要的主题&#xff0c;通常与网络相关联&#xff0c;作为其服务基础架构的关键部分。然而…

vite+vue3+pinia+vuex4动态路由解决刷新页面丢失

目录 了解如何添加动态路由 使用pinia持久化数据 解决方案 404找不页面问题 目前解决思路 完整路由配置 动态路由使用的数据 了解如何添加动态路由 vue官网-动态添加路由 使用pinia持久化数据 pinia的使用 解决方案 asyncRoutes()方法从pinia获取到动态菜单数据登陆成…

SpringMVC 01 -SpringMVC入门

高效学习习惯啊 坚持&#xff0c;比如这样经常更新博客&#xff0c;保持学习哈哈哈 SpringMVC-SpringMVC引入1 SpringMVC引入1.1 引言1.2 MVC架构1.2.1 概念1.2.2 好处1.2.3 执行流程【重点】2 快速入门2.1 导入依赖2.2 配置核心(前端)控制器2.3 springmvc核心配置文件2.4 创建…

开心档之C++ 修饰符类型

C 修饰符类型 目录 C 修饰符类型 实例 C 中的类型限定符 C 允许在 char、int 和 double 数据类型前放置修饰符。修饰符用于改变基本类型的含义&#xff0c;所以它更能满足各种情境的需求。 下面列出了数据类型修饰符&#xff1a; signedunsignedlongshort 修饰符 signed、…

Gitlab中Pipeline语法六

Gitlab中Pipeline语法 needs/include/extends nodes 阶段并行 - 可以无序执行作业,无序按照阶段顺序运行某些作业,可以让多个阶段同时运行. - 如果nedds:设置为指向因only/except规则而未实例化的作业,或者不存在,则创建管道时会出现yaml错误. stages:- build- test- depl…

Moviepy模块之视频添加字幕(二)

文章目录前言一、素材1.1 原视频1.2 字幕文件二、视频添加字幕2.1 引入库2.2 加载视频文件2.3 设置字幕的字体、大小、颜色2.4 加载字幕文件2.5 设置字幕位置2.6 将字幕添加到视频中2.7 保存带有字幕的视频文件三、新视频效果总结前言 大家好&#xff0c;我是空空star&#xff…

2023蓝桥杯C++A组题解(第十四届)

面向爆零选手 水平有限&#xff0c;将就着看&#xff0c;有空再补充后5题 目录 &#x1f92f;吐槽 &#x1f61f;A&#xff0c;2067: [蓝桥杯2023初赛] 幸运数 &#x1f61f;B&#xff0c;2068: [蓝桥杯2023初赛] 有奖问答 &#x1f33c;AC DFS &#x1f33c;AC DP &a…

Apache 配置与应用

目录构建虚拟 Web 主机基于域名的虚拟主机1&#xff0e;为虚拟主机提供域名解析2.为虚拟主机准备网页文档3.添加虚拟主机配置4.设置访问控制5.加载独立的配置文件6.在客户机中访问虚拟 Web 主机基于IP地址的虚拟主机基于端口的虚拟主机Apache 连接保持构建Web虚拟目录与用户授权…

基于html+css的盒子展示3

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…