3.5.4 JDBC API 实现注意事项

MySQL Connector/J 作为 JDBC API的严格实现,通过了 Oracle 的 JDBC 合规性测试套件的公开版本中的所有测试。JDBC 规范在特定功能的实现方式上是灵活的。本节详细介绍了有关可能影响您如何使用 MySQL Connector/J 编写应用程序的实现决策的接口级别。

  • BLOB

    emulateLocators=true您可以通过将属性添加到您的 JDBC URL 来模拟带有定位器的 BLOB 。使用此方法,驱动程序将延迟加载实际的 BLOB 数据,直到您检索其他数据,然后对 BLOB 数据流使用检索方法(getInputStream()getBytes()等)。

    您必须使用列别名,其中列的值是 BLOB 的实际名称,例如:

    SELECT id, 'data' as blob_data from blobtable

    您还必须遵守以下规则:

    • SELECT必须仅引用一个表 。该表必须有一个 主键

    • 必须将SELECT指定为字符串的原始 BLOB 列名称别名为备用名称。

    • SELECT必须覆盖构成主键的所有列 。

    BLOB 实现不允许就地修改(它们是副本,如方法所报告的那样 DatabaseMetaData.locatorsUpdateCopies() )。因此,使用相应的 PreparedStatement.setBlob()ResultSet.updateBlob()(在可更新结果集的情况下)方法将更改保存回数据库。

  • 联系

    isClosed()方法不会通过 ping 服务器来确定它是否可用。根据 JDBC 规范,它仅在 closed()已在连接上调用时才返回 true。如果您需要确定连接是否仍然有效,请发出一个简单的查询,例如SELECT 1. 如果连接不再有效,驱动程序将抛出异​​常。

  • 数据库元数据

    外键 信息(getImportedKeys()/getExportedKeys()getCrossReference())只能从InnoDB表中获得。驱动程序用于SHOW CREATE TABLE检索此信息,因此如果任何其他存储引擎添加了对外键的支持,驱动程序也会透明地支持它们。

  • PreparedStatement

    Connector/J 实现了准备语句的两种变体,即客户端准备语句和服务器端准备语句。默认情况下使用客户端预编译语句,因为早期的 MySQL 版本不支持预编译语句功能或在实现时存在问题。服务器端准备好的语句和二进制编码的结果集在服务器支持时使用。要启用服务器端准备好的语句,请设置useServerPrepStmts=true.

    使用带有使用、 、 、、 、 、 或 设置的参数 的服务器端准备语句时要小心 。要重新执行将任何大参数更改为非大参数的语句,请再次调用并设置所有参数。原因如下: setBinaryStream()setAsciiStream()setUnicodeStream() setCharacterStream()setNCharacterStream()setBlob()setClob()setNCLob()clearParameters()

    • PreparedStatement.execute()在服务器端准备语句和客户端仿真期间,仅在调用 时才交换大数据 。

    • 完成后,用于读取客户端数据的流将关闭(根据 JDBC 规范),并且无法再次读取。

    • 如果参数从大变为非大,驱动程序必须重置准备语句的服务器端状态,以允许正在更改的参数取代先前的大值。这将删除所有已发送到服务器的大数据,因此需要使用 setBinaryStream(), setAsciiStream(), setUnicodeStream(), setCharacterStream(), setNCharacterStream(), setBlob(), setClob()setNCLob()方法重新发送数据。

    因此,要将参数类型更改为非大参数类型,必须 clearParameters()再次调用并设置准备好的语句的所有参数,然后才能重新执行。

  • 结果集

    默认情况下,ResultSets 被完全检索并存储在内存中。在大多数情况下,这是最有效的操作方式,并且由于 MySQL 网络协议的设计,更易于实施。如果您正在使用具有大量行或大值且无法在 JVM 中为所需内存分配堆空间的 ResultSet,您可以告诉驱动程序一次将结果流回一行。

    要启用此功能, Statement请按以下方式创建一个实例:

    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                  java.sql.ResultSet.CONCUR_READ_ONLY);
    stmt.setFetchSize(Integer.MIN_VALUE);

    只进、只读结果集与提取大小的组合Integer.MIN_VALUE 用作驱动程序逐行流式传输结果集的信号。此后,将逐行检索使用该语句创建的任何结果集。

    这种方法有一些注意事项。您必须先读取结果集中的所有行(或关闭它),然后才能对连接发出任何其他查询,否则将抛出异常。

    最早可以释放这些语句持有的锁(无论是MyISAM表级锁还是某些其他存储引擎中的行级锁,例如 InnoDB)是在语句完成时。

    如果语句在事务范围内,则在事务完成时释放锁(这意味着语句需要先完成)。与大多数其他数据库一样,在读取语句上所有挂起的结果或关闭语句的活动结果集之前,语句是不完整的。

    因此,如果使用流式结果,并且要保持对生成结果集的语句引用的表的并发访问,请尽快处理它们。

    另一种选择是使用基于游标的流式处理每次检索一定数量的行。这可以通过将连接属性设置 useCursorFetch为 true 来完成,然后调用 setFetchSize(int)with int每次获取所需的行数:

    conn = DriverManager.getConnection("jdbc:mysql://localhost/?useCursorFetch=true", "user", "s3cr3t");
    stmt = conn.createStatement();
    stmt.setFetchSize(100);
    rs = stmt.executeQuery("SELECT * FROM your_table_here");
  • 陈述

    Connector/J 包括对 Statement.cancel()和 的支持Statement.setQueryTimeout()。两者都需要一个单独的连接来发出 KILL QUERY 语句。在 的情况下 setQueryTimeout(),实现会创建一个额外的线程来处理超时功能。

    笔记

    取消语句的失败 setQueryTimeout()可能表现为RuntimeException而不是静默失败,因为目前没有办法解除阻塞正在执行由于超时到期而被取消的查询的线程并让它抛出异常。

    MySQL 不支持 SQL 游标,并且 JDBC 驱动程序不模拟它们,因此setCursorName()无效。

    Connector/J 还提供了两种额外的方法:

    • setLocalInfileInputStream()设置一个 InputStream实例,该实例将用于将数据发送到 MySQL 服务器以获取 LOAD DATA LOCAL INFILE语句,而不是 表示作为语句参数给出的路径 的FileInputStreamor 。URLInputStream

      该流将在语句执行时被读取至完成LOAD DATA LOCAL INFILE,并将由驱动程序自动关闭,因此需要在每次调用之前重置它,execute*()这将导致 MySQL 服务器请求数据以满足对 LOAD DATA LOCAL INFILE.

      如果此值设置为NULL,驱动程序将根据需要恢复使用 FileInputStreamor URLInputStream

    • getLocalInfileInputStream()返回InputStream将用于发送数据以响应 LOAD DATA LOCAL INFILE语句的实例。

      NULL如果没有使用 设置这样的流,则 此方法返回setLocalInfileInputStream()