Spec-Zone .ru
спецификации, руководства, описания, API

21.3.15. Поиск и устранение неисправностей Приложения Connector/J

Этот раздел объясняет признаки и разрешения для проблем, с которыми обычно встречаются, с MySQL использования приложений, Connector/J.

Вопросы

Вопросы и Ответы

22.3.15.1: Когда я пытаюсь соединиться с базой данных с MySQL, Connector/J, я получаю следующее исключение:

SQLException: Server configuration denies access to data sourceSQLState: 08001VendorError: 0

MySQL, Connector/J, должен использовать сокеты TCP/IP, чтобы соединиться с MySQL, поскольку Java не поддерживает Сокеты Домена Unix. Поэтому, когда MySQL, Connector/J, соединяется с MySQL, менеджер безопасности в сервере MySQL будет использовать свои таблицы предоставления, чтобы определить, разрешается ли соединение.

Следует добавить необходимые учетные данные безопасности к серверу MySQL для этого, чтобы произойти, используя GRANT оператор к Вашему MySQL Server. См. Раздел 13.7.1.4,"GRANT Синтаксис", для получения дополнительной информации.

Отметить

Тестирование Вашей связи с mysql клиентом командной строки не будет работать, если Вы не добавите флаг "узла", и используете что-то другое чем localhost для узла. mysql клиент командной строки будет использовать сокеты домена Unix, если Вы будете использовать специальное имя хоста localhost. Если Вы тестируете связь к localhost, использовать 127.0.0.1 как имя хоста вместо этого.

Предупреждение

Изменение полномочий и полномочий ненадлежащим образом в MySQL может потенциально заставить Вашу установку сервера не иметь оптимальные свойства безопасности.

22.3.15.2: Мое приложение не бросает SQLException 'Никакой Подходящий Драйвер'. Почему это происходит?

Есть три возможных причины для этой ошибки:

22.3.15.3: Я пытаюсь использовать MySQL, Connector/J в апплете или приложении, и я получаю исключение, подобное:

SQLException: Cannot connect to MySQL server on host:3306.Is there a MySQL server running on the machine/port youare trying to connect to?(java.security.AccessControlException)SQLState: 08S01VendorError: 0 

Или Вы выполняете Апплет, Ваш сервер MySQL был установлен с "объединяющим в сеть пропуск" набором опции, или у Вашего сервера MySQL есть брандмауэр, находящийся перед этим.

Апплеты могут только сделать сетевые соединения назад с машиной, которая выполняет веб-сервер, который служил.class файлам для апплета. Это означает, что MySQL должен работать на той же самой машине (или у Вас должно быть своего рода перенаправление порта) для этого, чтобы работать. Это также означает, что Вы не будете в состоянии протестировать апплеты от своей локальной файловой системы, следует всегда развертывать их к веб-серверу.

MySQL, Connector/J, может только связаться с MySQL, используя TCP/IP, поскольку Java не поддерживает сокеты домена Unix. На передачу TCP/IP с MySQL можно было бы влиять, если бы MySQL был запущен с "объединяющего в сеть пропуск" флага, или если это - firewalled.

Если MySQL был запущен с "объединяющего в сеть пропуск" набора опции (пакет Linux Debian сервера MySQL делает это например), Вы должны прокомментировать это в файле /etc/mysql/my.cnf или /etc/my.cnf. Конечно, Ваш my.cnf файл мог бы также существовать в data каталог Вашего сервера MySQL, или где-либо еще (в зависимости от того, как MySQL был скомпилирован для Вашей системы). Всегда заглядывают двоичные файлы, создаваемые нами /etc/my.cnf и datadir/my.cnf. Если Ваш сервер MySQL был firewalled, Вам должны будут сконфигурировать брандмауэр, чтобы позволить соединения TCP/IP от узла, куда Ваш код Java работает к серверу MySQL на порту, который MySQL слушает (по умолчанию, 3306).

22.3.15.4: У меня есть сервлет/приложение, который хорошо работает в течение дня, и затем прекращает работать быстро

MySQL закрывает соединения после 8 часов неактивности. Вы или должны использовать пул соединения, который обрабатывает устарелые соединения, или используйте autoReconnect параметр (см. Раздел 21.3.5.1, "Имена классов Драйвера/Источника данных, Синтаксис URL и Свойства Конфигурации для Connector/J").

Кроме того, выгода SQLExceptions в Вашем приложении и соглашении с ними, вместо того, чтобы распространить их полностью до Ваших выходов приложения. Это - только хорошая практика программирования. MySQL, Connector/J, установит SQLState (см. java.sql.SQLException.getSQLState() в Ваших документах API) к 08S01 когда это встречается с проблемами сетевой связи во время обработки запроса. Попытка повторно соединиться с MySQL в этой точке.

Следующий (упрощенный) пример показывает то, что кодирует, который может обработать эти исключения, мог бы быть похожим:

Пример 21.12. Connector/J: Пример транзакции с логикой повторной попытки

public void doBusinessOp() throws SQLException {    Connection conn = null;    Statement stmt = null;    ResultSet rs = null;    //    // How many times do you want to retry the transaction    // (or at least _getting_ a connection)?    //    int retryCount = 5;    boolean transactionCompleted = false;    do {        try {            conn = getConnection(); // assume getting this from a                                    // javax.sql.DataSource, or the                                    // java.sql.DriverManager            conn.setAutoCommit(false);            //            // Okay, at this point, the 'retry-ability' of the            // transaction really depends on your application logic,            // whether or not you're using autocommit (in this case            // not), and whether you're using transactional storage            // engines            //            // For this example, we'll assume that it's _not_ safe            // to retry the entire transaction, so we set retry            // count to 0 at this point            //            // If you were using exclusively transaction-safe tables,            // or your application could recover from a connection going            // bad in the middle of an operation, then you would not            // touch 'retryCount' here, and just let the loop repeat            // until retryCount == 0.            //            retryCount = 0;            stmt = conn.createStatement();            String query = "SELECT foo FROM bar ORDER BY baz";            rs = stmt.executeQuery(query);            while (rs.next()) {            }            rs.close();            rs = null;            stmt.close();            stmt = null;            conn.commit();            conn.close();            conn = null;            transactionCompleted = true;        } catch (SQLException sqlEx) {            //            // The two SQL states that are 'retry-able' are 08S01            // for a communications error, and 40001 for deadlock.            //            // Only retry if the error was due to a stale connection,            // communications problem or deadlock            //            String sqlState = sqlEx.getSQLState();            if ("08S01".equals(sqlState) || "40001".equals(sqlState)) {                retryCount -= 1;            } else {                retryCount = 0;            }        } finally {            if (rs != null) {                try {                    rs.close();                } catch (SQLException sqlEx) {                    // You'd probably want to log this...                }            }            if (stmt != null) {                try {                    stmt.close();                } catch (SQLException sqlEx) {                    // You'd probably want to log this as well...                }            }            if (conn != null) {                try {                    //                    // If we got here, and conn is not null, the                    // transaction should be rolled back, as not                    // all work has been done                    try {                        conn.rollback();                    } finally {                        conn.close();                    }                } catch (SQLException sqlEx) {                    //                    // If we got an exception here, something                    // pretty serious is going on, so we better                    // pass it up the stack, rather than just                    // logging it...                    throw sqlEx;                }            }        }    } while (!transactionCompleted && (retryCount > 0));}
Отметить

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

22.3.15.5: Я пытаюсь использовать JDBC 2.0 обновляемых набора результатов, и я получаю исключение, говоря, что мой набор результатов не обновляем.

Поскольку у MySQL нет идентификаторов строки, MySQL, Connector/J, может только обновить наборы результатов, которые прибыли из запросов на таблицах, у которых есть по крайней мере один первичный ключ, запрос должен выбрать каждый столбец первичного ключа, и запрос может только охватить одну таблицу (то есть, никакие соединения). Это обрисовывается в общих чертах в спецификации JDBC.

Отметьте, что эта проблема только происходит при использовании обновляемых наборов результатов, и вызывается, потому что Connector/J неспособен гарантировать, что это может идентифицировать корректные строки в пределах набора результатов, который будет обновлен, не имея уникальную ссылку на каждую строку. Нет никакого требования, чтобы иметь уникальное поле на таблице, если Вы используете UPDATE или DELETE операторы на таблице, где можно индивидуально определить критерии, которые будут соответствующими, используя a WHERE пункт.

22.3.15.6: Я не могу соединиться с сервером MySQL, используя Connector/J, и я уверен, что параметры соединения корректны.

Удостоверьтесь что skip-networking опция не была включена на Вашем сервере. Connector/J должен быть в состоянии связаться с Вашим сервером по TCP/IP; названный сокетами не поддерживаются. Также гарантируйте, что Вы не пропускаете соединения через брандмауэр или другую систему сетевой безопасности. Для получения дополнительной информации см. Раздел C.5.2.2,"Can't connect to [local] MySQL server".

22.3.15.7: Я пытаюсь соединиться с моим сервером MySQL в пределах моего приложения, но я получаю следующую ошибку и складываю трассировку:

java.net.SocketExceptionMESSAGE: Software caused connection abort: recv failedSTACKTRACE:java.net.SocketException: Software caused connection abort: recv failedat java.net.SocketInputStream.socketRead0(Native Method)at java.net.SocketInputStream.read(Unknown Source)at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:1392)at com.mysql.jdbc.MysqlIO.readPacket(MysqlIO.java:1414)at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:625)at com.mysql.jdbc.Connection.createNewIO(Connection.java:1926)at com.mysql.jdbc.Connection.<init>(Connection.java:452)at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:411)

Ошибка, вероятно, указывает, что Вы используете более старую версию Connector/J JDBC драйвер (2.0.14 или 3.0.x), и Вы пытаетесь соединиться с сервером MySQL с версией 4.1x или более новый. Более старые драйверы не являются совместимыми с 4.1 или более новыми из MySQL, поскольку они не поддерживают более новые механизмы аутентификации.

Вероятно, что более старая версия драйвера Connector/J существует в пределах Вашего каталога приложения или Вашего CLASSPATH включает более старый пакет Connector/J.

22.3.15.8: Мое приложение развертывается через JBoss, и я использую транзакции, чтобы обработать операторы на базе данных MySQL. Под тяжелыми грузами я получаю ошибку и трассировку стека, но они только происходят после установленного срока тяжелого действия.

Это - JBoss, не Connector/J, проблема и соединяется с использованием транзакций. Под тяжелыми грузами может увеличиться время, потраченное для транзакций, чтобы завершиться, и ошибка вызывается, потому что Вы превысили предопределенный тайм-аут.

Можно увеличить значение тайм-аута, устанавливая TransactionTimeout припишите TransactionManagerService в пределах /conf/jboss-service.xml файл (пред4.0.3) или /deploy/jta-service.xml для JBoss 4.0.3 или позже. См. TransactionTimeout в пределах wiki JBoss для получения дополнительной информации.

22.3.15.9: При использовании gcj, a java.io.CharConversionException исключение повышается, работая с определенными символьными последовательностями.

Это - известная проблема с gcj, который повышает исключение, когда он достигает неизвестного символа, или один он не может преобразовать. Добавить useJvmCharsetConverters=true к Вашей строке подключения, чтобы вызвать преобразование символов за пределами gcj библиотек, или попробовать различный JDK.

22.3.15.10: Обновление таблицы, которая содержит первичный ключ, который является также FLOAT или соедините первичный ключ, который использует FLOAT сбои, чтобы обновить таблицу и повышения исключение.

Connector/J добавляет условия к WHERE пункт во время UPDATE проверять старые значения первичного ключа. Если там не идет ни в какое сравнение, то Connector/J считает это условием отказа и повышает исключение.

Проблема состоит в том, что округление различий между предоставленными значениями и значениями, сохраненными в базе данных, может означать, что значения никогда не соответствуют, и следовательно сбои обновления. Проблема будет влиять на все запросы, не только тех от Connector/J.

Чтобы предотвратить эту проблему, используйте первичный ключ, который не использует FLOAT. Если необходимо использовать столбец с плавающей точкой в своем первичном ключе, использовать DOUBLE или DECIMAL типы вместо FLOAT.

22.3.15.11: Вы добираетесь ER_NET_PACKET_TOO_LARGE исключение, даже при том, что двоичный размер блоба Вы хотите вставить использование JDBC, безопасно ниже max_allowed_packet размер.

Это то, потому что hexEscapeBlock() метод в com.mysql.jdbc.PreparedStatement.streamToBytes() май почти удваивает размер Ваших данных.

22.3.15.12: Что должно Вы делать, если Вы получаете сообщения об ошибках, подобные следующему: "Отказ линии связи – Последний пакет, отправленный серверу, был несколько X мс назад"?

Вообще говоря, эта ошибка предполагает, что сетевое соединение было закрыто. Может быть несколько первопричин:

Чтобы помочь диагностировать эти проблемы, следующие советы могут использоваться. Если недавнее (5.1.13 +) версия Connector/J будет использоваться, то Вы будете видеть улучшенный уровень информации по сравнению с более ранними версиями. Более старые версии просто выводят на экран в прошлый раз, когда пакет был отправлен серверу, который часто является несколько 0 мс назад. Это имеет ограниченное использование, поскольку может случиться так, что пакет был только отправлен, в то время как пакет от сервера не получался в течение нескольких часов. Зная промежуток времени, так как последний Connector/J получил пакет от сервера, полезная информация, так, если это не выводится на экран в Вашем сообщении об исключительной ситуации, рекомендуется, чтобы Вы обновили Connector/J.

Далее, если время, пакет был последним, отправило/получило, превышает wait_timeout или interactive_timeout порог, это отмечается в сообщении об исключительной ситуации.

Хотя сетевые соединения могут быть энергозависимыми, следующее может быть полезным в уходе от проблем:

Отметить

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

22.3.15.13: Почему делает Connector/J не, повторно соединяются с MySQL и переиздают оператор после коммуникационного отказа, вместо того, чтобы выдать Исключение, даже при том, что я использую autoReconnect опция строки подключения?

Есть несколько причин этого. Первой является транзакционная целостность. MySQL Reference Manual утверждает, что "нет никакого надежного метода пересоединения с сервером MySQL, не рискуя некоторым повреждением состояния соединения или информации о состоянии базы данных". Рассмотрите следующую серию операторов например:

conn.createStatement().execute(  "UPDATE checking_account SET balance = balance - 1000.00 WHERE customer='Smith'");conn.createStatement().execute(  "UPDATE savings_account SET balance = balance + 1000.00 WHERE customer='Smith'");conn.commit();

Рассмотрите случай где соединение со сбоями сервера после UPDATE к checking_account. Если никакое исключение не будет выдано, и приложение никогда не узнает о проблеме, то оно будет продолжать выполняться. Однако, сервер не фиксировал первую транзакцию в этом случае, так, чтобы откатывался. Но выполнение продолжается со следующей транзакцией, и увеличивается savings_account баланс 1000. Приложение не получало исключение, таким образом, оно продолжалось независимо, в конечном счете фиксируя вторую транзакцию, поскольку фиксация только применяется к изменениям, произведенным в новом соединении. А не передача, имеющая место, депозит был сделан в этом примере.

Отметьте то выполнение с autocommit включенный не решает эту проблему. Когда Connector/J встречается с проблемой коммуникации, нет никакого средства определить ли сервер, обработанный в настоящий момент выполняющийся оператор или нет. Следующие теоретические состояния одинаково возможны:

Если Вы работаете с autocommit включенный, не возможно гарантировать состояние данных на сервере, когда с коммуникационным исключением встречаются. Оператор, возможно, достиг сервера, или это не может. Все, что Вы знаете, то, что передача, отказавшая в некоторый момент перед клиентом полученное подтверждение (или данные) от сервера. Это не только влияет autocommit операторы все же. Если проблема коммуникации произошла во время Connection.commit(), вопрос возникает того, фиксировалась ли транзакция на сервере перед передачей, отказавшей, или ли сервер, полученный запрос фиксации вообще.

Вторая причина генерации исключений - определяющие контекст транзакцией контекстные данные могут быть уязвимыми, например:

Эти элементы теряются, когда связь прерывается, и если соединение тихо повторно соединяется, не генерируя исключение, это могло бы быть вредно для корректного выполнения Вашего приложения.

В сводке коммуникационные ошибки генерируют условия, которые могут хорошо быть опасны для Connector/J просто проигнорировать, тихо повторно соединяясь. Необходимо для приложения быть уведомленным. Это тогда для разработчика приложений, чтобы решить, как продолжить в случае ошибок соединения и отказов.

22.3.15.14: Как я могу использовать 3-байтовый UTF8 с Connector/J?

Использовать 3-байтовый UTF8 с набором Connector/J characterEncoding=utf8 и набор useUnicode=true в строке подключения.

22.3.15.15: Как может я использовать 4-байтовый UTF8, utf8mb4 с Connector/J?

Чтобы использовать 4-байтовый UTF8 с Connector/J конфигурируют сервер MySQL с character_set_server=utf8mb4. Connector/J будет тогда использовать ту установку пока characterEncoding не был установлен в строке подключения. Это эквивалентно автоматическому обнаружению набора символов.

22.3.15.16: Используя useServerPrepStmts=false и определенные кодировки символов могут привести к повреждению, вставляя BLOB. Как этого можно избежать?

При использовании определенных кодировок символов, таких как SJIS, CP932, и BIG5, возможно, что данные BLOB содержат символы, которые могут быть интерпретированы как управляющие символы, например, наклонная черта влево, '\'. Это может привести к поврежденным данным, вставляя BLOB в базу данных. Есть две вещи, которые должны быть сделаны, чтобы избежать этого:

  1. Установите опцию строки подключения useServerPrepStmts к true.

  2. Набор SQL_MODE к NO_BACKSLASH_ESCAPES.