Spec-Zone.ru › MySQL Connectors 1.0

Примечания к реализации JDBC API 6.4

MySQL Connector/J, как строгая реализация JDBC API, проходит все тесты в общедоступном наборе тестов соответствия JDBC спецификации Oracle. Спецификация JDBC гибкая в отношении реализации определенных функций. В этом разделе подробно рассматриваются решения, принимаемые на уровне интерфейса, которые могут повлиять на то, как вы будете кодировать приложения с MySQL Connector/J.

  • BLOB

    Вы можете эмулировать BLOB с помощью локаторов, добавив свойство emulateLocators=true в ваш JDBC URL. Используя этот метод, драйвер отложит загрузку фактических данных BLOB до тех пор, пока вы не получите другие данные, а затем используете методы извлечения (getInputStream(), getBytes() и т. д.) для потока данных BLOB.

    Вы должны использовать псевдоним столбца со значением столбца для фактического имени BLOB, например:

    SELECT id, 'data' as blob_data from blobtable
    

    Вы также должны следовать этим правилам:

    • Псевдоним должен ссылаться только на одну таблицу. Таблица должна иметь ...

    • Псевдоним должен изменять оригинальное имя столбца BLOB, указанное как строка, на другое имя.

    • Псевдоним должен охватывать все столбцы, составляющие первичный ключ.

    Реализация BLOB не допускает изменения на месте (они являются копиями, как сообщается методом DatabaseMetaData.locatorsUpdateCopies()). По этой причине используйте соответствующие методы PreparedStatement.setBlob() или ResultSet.updateBlob() (в случае обновляемых наборов результатов), чтобы сохранить изменения обратно в базу данных.

  • Connection

    Метод isClosed() не проверяет сервер на доступность. В соответствии со спецификацией JDBC он возвращает true только в том случае, если closed() был вызван для подключения. Если вам нужно определить, всё ли в порядке с подключением, выполните простой запрос, например, SELECT 1. Драйвер выбросит исключение, если подключение больше недействительно.

  • DatabaseMetaData

    Информация (getImportedKeys()/getExportedKeys() и getCrossReference()) доступна только из таблиц. Драйвер использует , чтобы получить эту информацию, поэтому, если другие хранилища данных добавят поддержку внешних ключей, драйвер будет поддерживать их также прозрачно.

  • 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() и снова задать все параметры подготовленного запроса, прежде чем его можно будет повторно выполнить.

  • ResultSet

    По умолчанию наборы результатов полностью извлекаются и хранятся в памяти. В большинстве случаев это наиболее эффективный способ работы и, благодаря дизайну сетевого протокола MySQL, проще для реализации.

    Если вы работаете с наборами результатов, содержащими большое количество строк или больших значений, и не можете выделить необходимое количество памяти в вашей JVM, вы можете указать драйверу передавать результаты по одной строке за раз.

    Для включения этой функциональности создайте экземпляр 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) с 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");
    
  • Statement

    Connector/J поддерживает как Statement.cancel(), так и Statement.setQueryTimeout(). Для обоих требуется отдельное подключение для выполнения запроса.

    В случае setQueryTimeout() реализация создает дополнительный поток для обработки таймаута.

    Примечание

    Неудачные попытки отмены запроса для setQueryTimeout() могут привести к RuntimeException, а не к молчаливому завершению, так как в настоящее время нет возможности разблокировать поток, выполняющий запрос, который отменяется из-за истечения времени ожидания, и заставить его вместо этого выбросить исключение.

    MySQL не поддерживает SQL-курсоры, и JDBC-драйвер не эмулирует их, поэтому setCursorName() не оказывает никакого влияния.

    Connector/J также предоставляет два дополнительных метода:

    • setLocalInfileInputStream() устанавливает экземпляр InputStream, который будет использоваться для отправки данных на сервер MySQL для запроса, а не FileInputStream или URLInputStream, представляющего путь, заданный в качестве аргумента запросу.

      Этот поток будет полностью прочитан при выполнении запроса и автоматически закрыт драйвером, поэтому его необходимо сбрасывать перед каждым вызовом execute*(), который приведет к запросу данных на сервере MySQL для удовлетворения запроса.

      Если это значение установлено в NULL, драйвер вернётся к использованию FileInputStream или URLInputStream по мере необходимости.

    • getLocalInfileInputStream() возвращает экземпляр InputStream, который будет использоваться для отправки данных в ответ на запрос.

      Этот метод возвращает NULL, если такой поток не был задан с помощью setLocalInfileInputStream().

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/connector-j-en/connector-j-reference-implementation-notes.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API