服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Mysql - SQL语句解析执行的过程及原理

SQL语句解析执行的过程及原理

2022-10-13 15:03zfcq Mysql

这篇文章主要介绍了SQL语句解析执行的过程及原理,文章主要通过获得SqlSession对象后就能执行各种CRUD方法展开全文内容需要的小伙伴可以参考一下,希望对你有所帮助

一、sqlSession简单介绍

  • 拿到SqlSessionFactory对象后,会调用SqlSessionFactoryopenSesison方法,这个方法会创建一个Sql执行器(Executor),这个Sql执行器会代理你配置的拦截器方法。
  • 获得上面的Sql执行器后,会创建一个SqlSession(默认使用DefaultSqlSession),这个SqlSession中也包含了Configration对象,所以通过SqlSession也能拿到全局配置;
  • 获得SqlSession对象后就能执行各种CRUD方法了。

SQL语句解析执行的过程及原理

二、获得sqlSession对象源码分析

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
 * 通过sqlSessionFactory.openSession进行获取sqlSession对象
 * 源码位置:org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSession()
 */
public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
 
/**
 * 通过数据源去获取SqlSession
 * 源码位置:org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource(ExecutorType, TransactionIsolationLevel, boolean)
 */
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
        boolean autoCommit) {
    Transaction tx = null;
    try {
        // 获取环境变量
        final Environment environment = configuration.getEnvironment();
        // 获取事务工厂
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        // 获取一个事务
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 获取执行器,这边获得的执行器已经代理拦截器的功能
        final Executor executor = configuration.newExecutor(tx, execType);
        // 根据获取的执行器创建SqlSession
        return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
        closeTransaction(tx); // may have fetched a connection so lets call close()
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}
 
/**
 * 获取执行器
 * 源码位置:org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource(ExecutorType, TransactionIsolationLevel, boolean)
 */
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    // 默认使用SIMPLE的执行器
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
 
    if (ExecutorType.BATCH == executorType) {
        // 批量的执行器
        executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
        // 可重复使用的执行器
        executor = new ReuseExecutor(this, transaction);
    } else {
        // 简单的sql执行器
        executor = new SimpleExecutor(this, transaction);
    }
 
    // 判断Mybatis的全局配置文件是否开启二级缓存
    if (cacheEnabled) {
        // 开启缓存,吧executor包装为CachingExecutor
        executor = new CachingExecutor(executor);
    }
    
    // 插件的调用:责任链模式
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

三、SQL执行流程,以查询为例

SQL语句解析执行的过程及原理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/**
 * 查询的入口方法
 * 源码位置:org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(String, Object)
 */
public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    // 查询数据
    List<T> list = this.<T>selectList(statement, parameter);
 
    // 长度为1,拿第一个
    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 {
        // 没有拿到返回null
        return null;
    }
}
 
/**
 * 查询数据
 * 源码位置:org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(String, Object, RowBounds)
 */
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        // 通过statement去全局配置文件中获取MappedStatement(得到mapper中增删改查的节点)
        MappedStatement ms = configuration.getMappedStatement(statement);
 
        // 通过执行器去执行SQL
        return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}
 
/**
 * 执行查询操作的准备工作
 * 源码位置:org.apache.ibatis.executor.CachingExecutor.query(MappedStatement, Object, RowBounds, ResultHandler)
 */
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
        ResultHandler resultHandler) throws SQLException {
 
    // 通过参数进行sql解析
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
 
/**
 * 执行查询操作的准备工作
 * 源码位置:org.apache.ibatis.executor.CachingExecutor.query(MappedStatement, Object, RowBounds, ResultHandler, CacheKey, BoundSql)
 */
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
        ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    // 判断sql是否开启了缓存 <cache></cache>
    Cache cache = ms.getCache();
    
    // 有缓存
    if (cache != null) {
        // 判断是否需要刷新缓存
        flushCacheIfRequired(ms);
        if (ms.isUseCache() && resultHandler == null) {
            ensureNoOutParams(ms, boundSql);
            @SuppressWarnings("unchecked")
 
            // 去二级缓存中获取(装饰者模式)
            List<E> list = (List<E>) tcm.getObject(cache, key);
 
            // 二级缓存没有找到
            if (list == null) {
 
                // 查询数据,并放入缓存
                list = delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                tcm.putObject(cache, key, list); // issue #578 and #116
            }
            return list;
        }
    }
    // 查询数据
    return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
 
/**
 * 一级缓存查询的调用
 * 源码位置:org.apache.ibatis.executor.BaseExecutor.query(MappedStatement, Object, RowBounds, ResultHandler, CacheKey, BoundSql)
 */
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());
 
    // 已经关闭了,抛异常
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
 
    // 清空本地缓存
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    List<E> list;
    try {
        // 从一级缓存中获取数据
        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--;
    }
    if (queryStack == 0) {
        for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
        }
        // issue #601
        deferredLoads.clear();
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            // issue #482
            clearLocalCache();
        }
    }
    return list;
}
 
/**
 * 在数据库中查询
 * 源码位置:org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(MappedStatement, Object, RowBounds, ResultHandler, CacheKey, BoundSql)
 */
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds,
        ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
        // 去数据库查询
        list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
        localCache.removeObject(key);
    }
 
    // 一级缓存进行缓存
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
        localOutputParameterCache.putObject(key, parameter);
    }
    return list;
}
 
/**
 * 查询逻辑
 * 源码位置:org.apache.ibatis.executor.SimpleExecutor.doQuery(MappedStatement, Object, RowBounds, ResultHandler, BoundSql)
 */
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
        BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
        // 得到整体的配置对象
        Configuration configuration = ms.getConfiguration();
 
        // 内部封装了ParameterHandler和ResultSetHandler
        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds,
                resultHandler, boundSql);
        stmt = prepareStatement(handler, ms.getStatementLog());
 
        // 执行查询
        return handler.<E>query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}
 
/**
 * 执行查询语句
 * 源码位置:org.apache.ibatis.executor.statement.SimpleStatementHandler.query(Statement, ResultHandler)
 */
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    // 得到要执行的sql
    String sql = boundSql.getSql();
 
    // 执行sql
    statement.execute(sql);
 
    // 处理结果集
    return resultSetHandler.<E>handleResultSets(statement);
}

到此这篇关于SQL语句解析执行的过程及原理的文章就介绍到这了,更多相关SQL语句解析原理内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/zfcq/p/16069357.html

延伸 · 阅读

精彩推荐
  • MysqlMySQL DBA 常用手册小结

    MySQL DBA 常用手册小结

    MySQL DBA 常用手册小结,使用mysql的朋友可以参考下。 ...

    MYSQL教程网4272019-11-27
  • Mysql实操MySQL+PostgreSQL批量插入更新insertOrUpdate

    实操MySQL+PostgreSQL批量插入更新insertOrUpdate

    这篇文章主要介绍了MYsql和PostgreSQL优势对比以及如何实现MySQL + PostgreSQL批量插入更新insertOrUpdate,附含详细的InserOrupdate代码实例,需要的朋友可以参考下...

    哪 吒12712021-09-18
  • Mysql浅谈MySQL索引优化分析

    浅谈MySQL索引优化分析

    这篇文章主要介绍了浅谈MySQL索引优化分析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    ITDragon龙5032020-08-27
  • MysqlMysql索引的类型和优缺点详解

    Mysql索引的类型和优缺点详解

    这篇文章主要为大家详细介绍了Mysql索引的类型和优缺点,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    黎明&岁月5592020-06-23
  • MysqlUbuntu 18.04 安装mysql5.7

    Ubuntu 18.04 安装mysql5.7

    这篇文章主要为大家详细介绍了Ubuntu 18.04 安装mysql 5.7的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ...

    lynnyq4512020-09-11
  • MysqlMysql错误1366 - Incorrect integer value解决方法

    Mysql错误1366 - Incorrect integer value解决方法

    这篇文章主要介绍了Mysql错误1366 - Incorrect integer value解决方法,本文通过修改字段默认值解决,需要的朋友可以参考下 ...

    未来往事7622020-04-21
  • MysqlMySQL里面的子查询实例

    MySQL里面的子查询实例

    最近学习php+mysql执行操作,发现了这一篇实例代码 ...

    mysql技术网2442019-10-21
  • Mysql项目从MYSQL迁移至MARIADB教程

    项目从MYSQL迁移至MARIADB教程

    本文给大家分享的是将项目从MySQL迁移至MariaDB的详细步骤,非常的实用,有需要的小伙伴可以参考下 ...

    快步的小风3112020-08-01