MySQL Server-Side Cursor及OceanBase是否支持此功能

本文探讨了MySQL的Server-Side Cursor及其在JDBC中的实现,详细解析了Server-Side Prepared Statement的工作原理。同时,分析了OceanBase对这两项功能的支持情况,指出OceanBase在最新版本中可能不支持Server-Side Prepared Statement和Server-Side Cursor,这意味着在使用OceanBase时,应用需要采取不同的策略来处理预编译语句和大数据结果集。
摘要由CSDN通过智能技术生成

MySQL Server-Side Cursor及OceanBase是否支持此功能

背景与目的

从过往经验,从Informix到Oracle到DB2,应用使用这些数据库时,都会被强调:在语句中尽量使用变量参数,然后Prepare后可多次使用,减少数据库Server端语句硬解析带来的性能损耗,减少数据库Server端语句Cache空间的占用。

另外,不管是显式声明还是隐式产生,数据库Server端都会为Select语句(或者所有DML语句)一个Cursor(游标),通过Fetch这个Cursor来获取结果集。如果结果集小,一次就可全部取得整个结果集;如果结果集大,就需要多次交互,每次由Server端从库中读取一部分数据返回。每次获取的记录数,可通过参数控制,以在减少交互提高性能与客户端内存资源耗用间权衡。比如Oracle,JDBC是通过fetchsize、OCI是通过OCIStmtFetch函数参数nrows、Pro*C是通过宿主变量数组大小,来控制每次从Server端获取多少条记录回来。

由于上面提到的Prepare与Cursor功能,都是在数据库Server端实现的,所以可以被叫做Server-Side Prepared Statement与Server-Side Cursor。

最近因为某些原因,需要了解下OceanBase分布式数据库,OB对外是兼容MySQL数据库协议,也就看了下MySQL JDBC对Server-Side Prepared Statement和Server-Side Cursor的支持程度,以及OceanBase数据库Server是否支持这两个功能。

MySQL JDBC的实现

这部分内容的主要参考内容是MySQL Connector/J(JDBC) ReferenceJDBC源码MySQL Server源码

Server-Side Prepared Statement

MySQL JDBC实现了两种Prepared Statement:

  • Client-Side Prepared Statement

    此种方式是由JDBC在客户端模拟对Prepared Statment的功能,实际发往数据库Server端的是已经将变量参数值代入后拼装出来的SQL语句,变量参数值不同就是不同的SQL语句。

    这也是MySQL JDBC的默认使用的方式,官方解释的原因是:

    default because early MySQL versions did not support the prepared statement feature or had problems with its implementation

  • Server-Side Prepared Statement

    为了使用这种方式,需要设置属性useServerPrepStmts的值为true,通过:

让我们来大致看一下JDBC源代码中对Server-Side Prepared Statement的支持实现。

首先,在java.sql.Connection实现类com.mysql.jdbc.ConnectionImpl中方法prepareStatement():

public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
    synchronized (getConnectionMutex()) {
       ....

        if (this.useServerPreparedStmts && canServerPrepare) {
            if (this.getCachePreparedStatements()) {
                synchronized (this.serverSideStatementCache) {
                    ....
                    if (pStmt == null) {
                        try {
                            pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType,
                                                                        resultSetConcurrency);
                           ...
                            pStmt.setResultSetType(resultSetType);
                            pStmt.setResultSetConcurrency(resultSetConcurrency);
                        } catch (SQLException sqlEx) {
                           ....
                }
            } else {
                try {
                    pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType, resultSetConcurrency);

                    pStmt.setResultSetType(resultSetType);
                    pStmt.setResultSetConcurrency(resultSetConcurrency);
                } catch (SQLException sqlEx) {
                    ...
            }
        } else {
            pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
        }

        return pStmt;
    }
}

从上面代码可以看出,如果属性useServerPreparedStmts为true,且canServerPrepare也为真,就会使用ServerPreparedStatement类来构造Statement供后续执行SQL使用。属性useServerPreparedStmts是在哪里设置的呢? 是在ConnectionImpl类的initializePropsFromServer()方法中:

if (getUseServerPreparedStmts() && versionMeetsMinimum(4, 1, 0)) {
    this.useServerPreparedStmts = true;

    if (versionMeetsMinimum(5, 0, 0) && !versionMeetsMinimum(5, 0, 3)) {
        this.useServerPreparedStmts = false; // 4.1.2+ style prepared
        // statements
        // don't work on these versions
    }
}

getUseServerPreparedStmts()方法读取了连接属性中的detectServerPreparedStmts属性值:

public boolean getUseServerPreparedStmts() {
    return this.detectServerPreparedStmts.getValueAsBoolean();
}

属性detectServerPreparedStmts在这里被定义:

// Think really long and hard about changing the default for this many, many applications have come to be acustomed to the latency profile of preparing
// stuff client-side, rather than prepare (round-trip), execute (round-trip), close (round-trip).
private Boolean
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值