成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

建行二面:Mybatis 是如何工作的?

開發 數據庫
本文,我們通過核心源碼分析了 MyBatis, 它是一個輕量級的 ORM框架,它通過配置文件和注解將 Java 對象與數據庫記錄映射起來。

MyBatis 是一款優秀的持久層框架,它通過簡化 JDBC操作和提供靈活的 SQL映射方式,使 Java 開發人員能夠更高效地進行數據庫操作。那么,MyBatis的執行原理是什么?這篇文章我們將深入地分析。

一、MyBatis 配置解析

MyBatis 的配置文件通常包括全局配置文件(mybatis-config.xml)和映射文件(XXXMapper.xml)。全局配置文件主要用于配置數據源和其他全局性的信息,而映射文件則用于定義 SQL 語句。

1. 全局配置文件解析

全局配置文件在 MyBatis 啟動時被解析。SqlSessionFactoryBuilder 是 MyBatis 解析配置文件的入口點。它通過 build 方法接收一個 Reader 或 InputStream,然后調用 XMLConfigBuilder 來解析 XML 配置文件。

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);
    } finally {
        ErrorContext.instance().reset();
        try {
            inputStream.close();
        } catch (IOException e) {
            // Intentionally ignore. Prefer previous error.
        }
    }
}

XMLConfigBuilder 解析配置文件并構建出 Configuration 對象,該對象包含了 MyBatis 的所有配置信息。

2. 映射文件解析

映射文件中定義了 SQL 語句,通過 XMLMapperBuilder 進行解析。每個 <mapper> 標簽對應一個 MappedStatement 對象,MappedStatement 包含了 SQL 語句、輸入輸出參數類型、結果集映射等信息。

public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
        configurationElement(parser.evalNode("/mapper"));
        configuration.addLoadedResource(resource);
        bindMapperForNamespace();
    }
    parsePendingResultMaps();
    parsePendingCacheRefs();
    parsePendingStatements();
}

二、SQL 語句解析

MyBatis 支持動態 SQL,通過 <if>, <choose>, <foreach> 等標簽,可以根據不同的條件構造 SQL。動態 SQL 是 MyBatis 的一大特色,通過 SqlSource 接口實現。SqlSource 的主要實現類有 StaticSqlSource, DynamicSqlSource, RawSqlSource 等。

動態 SQL 解析

DynamicSqlSource 是處理動態 SQL 的核心類。它通過 SqlNode 樹來表示 SQL 語句的結構,SqlNode 是一個接口,常用的實現類有 IfSqlNode, ChooseSqlNode, WhereSqlNode 等。每個 SqlNode 的 apply 方法負責將節點轉換為 SQL 字符串。

public class DynamicSqlSource implements SqlSource {
    private final Configuration configuration;
    private final SqlNode rootSqlNode;

    public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
        this.configuration = configuration;
        this.rootSqlNode = rootSqlNode;
    }
    
    @Override
    public BoundSql getBoundSql(Object parameterObject) {
        DynamicContext context = new DynamicContext(configuration, parameterObject);
        rootSqlNode.apply(context);
        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
        SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
        return sqlSource.getBoundSql(parameterObject);
    }
}

三、參數設置

在獲得最終的 SQL 語句后,MyBatis 需要將參數傳遞給 SQL 語句。ParameterHandler 接口負責這項工作,默認實現是 DefaultParameterHandler。

public class DefaultParameterHandler implements ParameterHandler {
    private final TypeHandlerRegistry typeHandlerRegistry;
    private final MappedStatement mappedStatement;
    private final Object parameterObject;
    private final BoundSql boundSql;
    private final Configuration configuration;

    public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        this.mappedStatement = mappedStatement;
        this.configuration = mappedStatement.getConfiguration();
        this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
        this.parameterObject = parameterObject;
        this.boundSql = boundSql;
    }

    @Override
    public void setParameters(PreparedStatement ps) throws SQLException {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    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 = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    TypeHandler typeHandler = parameterMapping.getTypeHandler();
                    JdbcType jdbcType = parameterMapping.getJdbcType();
                    if (value == null && jdbcType == null) {
                        jdbcType = configuration.getJdbcTypeForNull();
                    }
                    typeHandler.setParameter(ps, i + 1, value, jdbcType);
                }
            }
        }
    }
}

四、SQL 執行

SQL 執行是 MyBatis 的核心功能之一。Executor 接口定義了執行操作的基本方法,主要的實現類有 SimpleExecutor, ReuseExecutor, BatchExecutor。這些執行器通過 StatementHandler 執行 SQL 語句。

public class SimpleExecutor extends BaseExecutor {
    public SimpleExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    @Override
    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
            stmt = prepareStatement(handler, ms.getStatementLog());
            return handler.update(stmt);
        } finally {
            closeStatement(stmt);
        }
    }
}

五、結果處理

MyBatis 提供了強大的結果集映射功能,允許將 SQL 查詢結果映射為 Java 對象。ResultSetHandler 接口負責處理結果集,DefaultResultSetHandler 是其主要實現類。

public class DefaultResultSetHandler implements ResultSetHandler {
    private final TypeHandlerRegistry typeHandlerRegistry;
    private final ObjectFactory objectFactory;
    private final boolean useConstructorMappings;
    private final ReflectorFactory reflectorFactory;
    private final MappedStatement mappedStatement;
    private final RowBounds rowBounds;
    private final ParameterHandler parameterHandler;
    private final ResultHandler<?> resultHandler;
    private final BoundSql boundSql;

    public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) {
        this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
        this.objectFactory = mappedStatement.getConfiguration().getObjectFactory();
        this.useConstructorMappings = mappedStatement.getConfiguration().isUseConstructorMappings();
        this.reflectorFactory = mappedStatement.getConfiguration().getReflectorFactory();
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;
        this.parameterHandler = parameterHandler;
        this.resultHandler = resultHandler;
        this.boundSql = boundSql;
    }

    @Override
    public List<Object> handleResultSets(Statement stmt) throws SQLException {
        final List<Object> multipleResults = new ArrayList<>();
        int resultSetCount = 0;
        ResultSetWrapper rsw = getFirstResultSet(stmt);
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        validateResultMapsCount(rsw, resultMapCount);
        while (rsw != null && resultMapCount > resultSetCount) {
            ResultMap resultMap = resultMaps.get(resultSetCount);
            handleResultSet(rsw, resultMap, multipleResults, null);
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }
        return collapseSingleResultList(multipleResults);
    }
}

六、總結

本文,我們通過核心源碼分析了 MyBatis, 它是一個輕量級的 ORM框架,它通過配置文件和注解將 Java 對象與數據庫記錄映射起來,其核心在于通過 XML和注解配置 SQL語句,利用執行器執行 SQL,并通過結果集處理器將結果映射為 Java對象。

MyBatis的設計使得開發者可以專注于 SQL本身,而不必關心底層 JDBC操作的細節,了解和掌握其執行原理和設計模式,可以幫組我們在實際應用中更好地使用 MyBatis。

責任編輯:趙寧寧 來源: 猿java
相關推薦

2025-03-28 10:47:05

開發注解Java

2024-09-29 09:50:05

2024-10-29 09:42:50

2025-04-08 09:20:00

Sentinel限流微服務

2025-03-20 09:59:55

Spring@ProfileJava

2025-03-25 12:00:00

@Value?Spring開發

2024-10-10 17:17:57

2021-04-25 09:58:48

mmapJava面試

2021-03-17 15:54:32

IO零拷貝方式

2025-03-18 08:30:00

Spring開發java

2024-07-30 14:01:51

Java字節碼JVM?

2024-10-15 09:25:08

JDBCMybatis數據庫

2011-08-08 13:45:58

jQuery

2021-05-10 17:20:55

AIOps開發人員人工智能

2024-08-30 08:59:15

2024-09-27 16:33:44

2023-04-18 14:53:48

2023-04-18 15:09:50

2010-08-02 16:56:03

ICMP協議

2021-08-03 14:29:30

ARPANET互聯網協議TCP
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美自拍偷拍视频 | 国产专区在线 | 九九精品在线 | 成人av播放 | 午夜视频在线 | 在线免费观看成年人视频 | 日本精品免费 | 国产精品高清在线 | 人操人人干人 | 久久久青草| 91天堂网 | 可以在线看的黄色网址 | 日韩欧美三级在线 | 中文字幕不卡在线观看 | 在线视频a| 在线视频国产一区 | 91网视频| 97超碰中文网 | av男人的天堂av | 亚洲成人高清 | 国产一区二区a | 国产精品欧美一区二区三区不卡 | 中文字字幕在线中文乱码范文 | a在线视频观看 | 国产91综合| 中文字幕亚洲一区二区va在线 | 九九av | 成人国产一区二区三区精品麻豆 | 日韩二区三区 | 久草在线中文888 | 国产成人高清视频 | 欧美成人第一页 | 中文字幕亚洲一区 | 久久久久免费精品国产小说色大师 | 亚洲精品99 | 久久天堂网 | 中文字幕 在线观看 | 在线欧美小视频 | 91精品国产综合久久久久 | 天天操天天操 | 夜夜av|