博客
关于我
深入浅出mybatis
阅读量:424 次
发布时间:2019-03-06

本文共 5960 字,大约阅读时间需要 19 分钟。

MyBatis技术深入解析

MyBatis概述

MyBatis是一款流行的持久层框架,支持定制化SQL、存储过程及高级映射。它通过减少JDBC代码,避免手动设置参数和结果集的操作,为开发者提供了更加简洁高效的数据访问方式。MyBatis可以使用XML或注解配置,支持原生类型、接口及Java POJO与数据库记录的映射。

MyBatis配置与SQL编写

MyBatis配置文件

MyBatis的核心配置通常存储在mybatis-config.xml中,主要包含以下要素:

  • 环境配置:定义默认环境(如开发环境),配置数据源、事务管理器等。
  • 类型别名:定义常用类别的别名,便于在SQL中使用简化的命名。
  • 映射器配置:定义SQL映射,指定参数类型和结果类型。

SQL映射文件

UserMapper.xml是典型的MyBatis SQL映射文件,用于定义具体的数据库操作。例如:

数据库连接与事务管理

MyBatis通过数据源和事务管理器与数据库进行连接,支持多种数据库事务管理方式。默认使用JDBC数据源配置,确保数据库连接的稳定性和高效性。

MyBatis的内部原理

核心类解析

  • SqlSessionFactoryBuilder:负责读取MyBatis配置文件并构建SqlSessionFactory。
  • SqlSession:提供数据库操作的接口,包括查询、插入、更新、删除等操作。
  • DefaultSqlSession:SqlSession的默认实现类,负责执行数据库操作。
  • Executor:执行SQL语句的核心类,负责参数处理和结果集获取。

SQL执行过程

  • 获取映射信息:通过configuration.getMappedStatement(statement)获取对应的SQL映射信息。
  • 参数处理:将参数对象转换为可绑定的参数值,并生成参数占位符(如#{id})。
  • SQL拼接:根据绑定的参数值,动态拼接最终的SQL语句。
  • 结果集处理:根据结果类型(resultType)处理结果集,返回相应的对象或数据集合。
  • MyBatis缓存机制

    MyBatis提供了一级缓存机制,通过CacheKey生成唯一的缓存键。缓存键由以下信息构成:

    • SQL标识符:如<id>
    • 行偏移和限制rowBounds
    • SQL语句boundSql.getSql()
    • 参数值:通过createCacheKey方法处理后的参数值

    缓存机制的作用是减少数据库查询次数,提升应用性能。

    MyBatis源码解析

    SqlSessionFactoryBuilder

    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {    try {        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);        return build(parser.parse());    } catch (Exception e) {        throw ExceptionFactory.wrapException("Error building SqlSession.", e);    }}private SqlSessionFactory build(Configuration configuration) {    return new SqlSessionFactoryImpl(configuration);}
    • XMLConfigBuilder:读取并解析MyBatis配置文件,生成Configuration对象。
    • parse():解析配置文件中的configuration节点,初始化其他配置元素。

    SqlSession.openSession()

    public SqlSession openSession() {    return openSessionFromDataSource(null, null, false);}private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {    try {        Environment environment = this.configuration.getEnvironment();        TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);        Transaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);        Executor executor = this.configuration.newExecutor(tx, execType);        return new DefaultSqlSession(this.configuration, executor, autoCommit);    } catch (Exception e) {        this.closeTransaction(tx);        throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);    }}
    • newExecutor():根据事务管理器创建Executor实例,负责执行SQL语句。
    • DefaultSqlSession:负责管理数据库事务和执行SQL语句。

    SQL查询执行

    public 
    T selectOne(String statement, Object parameter) { List
    list = selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { return null; }}public
    List
    selectList(String statement, Object parameter) { MappedStatement ms = this.configuration.getMappedStatement(statement); List
    list = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); return list;}
    • executor.query():执行实际的数据库查询,返回结果集合。
    • wrapCollection():将参数对象转换为适用于MyBatis执行器的参数集合。

    缓存机制细节

    public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {    CacheKey cacheKey = new CacheKey();    cacheKey.update(ms.getId());    cacheKey.update(rowBounds.getOffset());    cacheKey.update(rowBounds.getLimit());    cacheKey.update(boundSql.getSql());        List
    parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { String propertyName = parameterMapping.getProperty(); Object value = null; if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = this.configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); } } if (this.configuration.getEnvironment() != null) { cacheKey.update(this.configuration.getEnvironment().getId()); } return cacheKey;}
    • cacheKey.update():根据参数值生成唯一的缓存键。
    • 参数映射:处理参数对象,获取对应的字段值,并更新缓存键。

    查询执行过程

    public List
    query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) { Cache cache = ms.getCache(); if (cache != null) { this.flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { this.ensureNoOutParams(ms, parameterObject, boundSql); List
    list = (List
    ) this.tcm.getObject(cache, key); if (list == null) { list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); this.tcm.putObject(cache, key, list); } return list; } } return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);}
    • flushCacheIfRequired():根据缓存策略决定是否清除缓存。
    • ensureNoOutParams():确保没有输出参数(如存储过程返回值),避免缓存问题。
    • delegate.query():委派执行实际的数据库查询操作。

    总结

    通过源码解析,我们可以清晰地看到MyBatis的工作原理。从配置文件读取到SQL执行,再到缓存机制的应用,MyBatis通过高度的抽象化和优化,显著提升了数据库访问的效率和开发体验。如果你对数据库开发感兴趣,掌握MyBatis将是非常有价值的。

    转载地址:http://nmvuz.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现获取文件头的50个字符(附完整源码)
    查看>>
    Objective-C实现随机图生成器算法(附完整源码)
    查看>>
    OJ中常见的一种presentation error解决方法
    查看>>
    OK335xS UART device registe hacking
    查看>>
    ok6410内存初始化
    查看>>
    one_day_one--mkdir
    查看>>
    OpenCV 中的图像转换
    查看>>
    opencv5-图像混合
    查看>>
    opencv9-膨胀和腐蚀
    查看>>
    OpenCV与AI深度学习 | YOLO11介绍及五大任务推理演示(目标检测,图像分割,图像分类,姿态检测,带方向目标检测)
    查看>>
    OpenCV与AI深度学习 | 使用Python和OpenCV实现火焰检测(附源码)
    查看>>
    OpenCV与AI深度学习 | 使用YOLO11实现区域内目标跟踪
    查看>>
    OpenCV与AI深度学习 | 基于PyTorch实现Faster RCNN目标检测
    查看>>
    OpenCV与AI深度学习 | 基于PyTorch语义分割实现洪水识别(数据集 + 源码)
    查看>>
    OpenCV与AI深度学习 | 基于机器视觉的磁瓦表面缺陷检测方案
    查看>>
    Opencv中KNN背景分割器
    查看>>
    OpenCV中基于已知相机方向的透视变形
    查看>>
    opencv保存图片路径包含中文乱码解决方案
    查看>>
    opencv图像分割2-GMM
    查看>>
    OpenCV:概念、历史、应用场景示例、核心模块、安装配置
    查看>>