JDBC - c3p0 - hibernate - setAutocommit, может кто-нибудь, пожалуйста, помогите мне прояснить историю - PullRequest
3 голосов
/ 15 октября 2011

Фундаментальный источник моих вопросов пришел из этого наблюдения.Когда я использую Hibernate и делаю любой запрос, в журналах MySQL я получаю следующее:

SET autocommit=0
insert into SimpleNamedEntity (name, version) values (null, 0)
commit
SET autocommit=1

Теперь я провел некоторое исследование (ссылки ниже, добавил бы больше, но я не «хорош»).кажется, достаточно :-)) и это довольно классическая проблема.Я провел несколько тестов на разных уровнях архитектуры (mysql config, jdbc, пул соединений, hibernate), чтобы получить лучшее представление о том, как все работает, и в результате я оказался более смущенным, поэтому вот несколько вопросов:

  • Может ли кто-нибудь подтвердить, оказывает ли автокоммит негативное влияние на производительность?Основной причиной, по которой я это вижу, является защитное поведение для предотвращения нежелательных незафиксированных транзакций, которые могут произойти, если люди забудут зафиксировать после выполнения оператора.Есть ли другая причина?

  • На мой взгляд, вам нужно отключить автокоммит при выполнении больших зависимых операций вставки-обновления-удаления, поскольку это помогает обеспечить целостность данных.Если все, что я хочу сделать, - это выборки, то это бесполезно, и я бы, вероятно, захотел установить для него значение true, чтобы избежать некоторых побочных эффектов типа блокировки длинной транзакции.Имеет ли это смысл?

  • Я заметил, что независимо от настройки автокоммитирования mysql, соединение jdbc всегда имеет значение true, и единственный способ для меня это контролировать (по умолчанию имеет значение false)добавить init-connect="SET AUTOCOMMIT=0" на сервере MySQL '.Но странным моментом является то, что как только я начинаю использовать c3p0 с этим параметром, c3p0 решает вручную отменить это и принудительно устанавливает автоматическую фиксацию на 1. В этом случае я даже нахожу подозрительным даже откат.Почему c3p0 принудительно устанавливает флаг?Почему происходит откат, когда обычно нет?Есть ли способ сказать c3p0 не делать этого?

    19 Query    SHOW COLLATION
    19 Query    SELECT @@session.autocommit
    19 Query    SET NAMES utf8mb4
    19 Query    SET character_set_results = NULL
    19 Query    SET sql_mode='STRICT_TRANS_TABLES'
    19 Query    SELECT @@session.tx_isolation
    19 Query    rollback
    19 Query    SET autocommit=1
    
  • Я пытался «очистить» операторы autocommit, которые у меня были в примере выше.Самым близким, что я получил, было отключение autocommit на сервере MySQL.Но даже тогда hibernate чувствует себя вынужденным как минимум сделать один оператор set autocommit = 0 в начале транзакции.Зачем это нужно делать?«Сбросить» состояние транзакции?Есть ли какой-нибудь путь конфигурации, который я могу использовать где-нибудь в стеке, чтобы предотвратить это в спящем режиме?

Ссылки: Java JDBC ref Статья по проблеме


(правка - уточнение)

Я перечитываю свой вопрос и могу понять, как сложно все это звучит.Извини, я не понял, попробую уточнить.Я хочу транзакции.Я получил часть InnoDB, READ_COMMITED.Я также понимаю, что autocommit - это, по сути, транзакция на SQL-оператор.Вот что я не получаю:

  1. hibernate делает 2 обращения к БД, которые не нужно делать в моем первом примере.Мне не нужно переключаться между autocommit = false и autocommit = true.Я ожидаю, что он будет всегда оставаться в состоянии false, но как бы я ни настраивал его, он все равно хочет автоматически устанавливать вызовы с автоматической фиксацией.Я не понимаю, почему это так.

  2. c3p0 демонстрирует несколько похожее поведение.Он автоматически устанавливает автокоммит для меня, когда я этого не хочу, и я также не понимаю, почему это происходит.

1 Ответ

3 голосов
/ 15 октября 2011

Вам необходимо решить, выполняете ли вы транзакции или нет.

Важно понимать, как работают серверы SQL, не существует такой вещи, как транзакции.То, что autoCommit = true делает каждый оператор самостоятельной транзакцией, вам не нужно использовать явные BEGIN TRANSACTION и COMMIT вокруг каждого оператора (SQL-сервер подразумевает такое поведение).

Да ... важно, чтобы вы делали SELECT внутри транзакции.Тот факт, что вы полагаете, что в этом нет необходимости, указывает на то, что вы еще не до конца понимаете и понимаете смысл реляционной целостности.

Hibernate ожидает, что реляционная целостность будет существовать, если вы сейчас читаете некоторые данные, затем запускаете некоторый код Java, а затемиспользуйте ранее прочитанные данные для доступа к большему количеству данных из SQL (например, с помощью функции отложенной загрузки Hibernates), тогда важно, чтобы данные все еще существовали, не так ли.Иначе, что должен делать ваш Java-код сейчас?выдать пользователю ошибку?

Это то, что при использовании транзакций, скажем, по умолчанию READ_COMMITTED Уровень изоляции транзакций обеспечит, и это минимальный уровень, который вы должны начать свой квест для получения (изучения) SQL.

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

Re autoCommit = true | false, влияющий на производительность.Я думаю, что вы задаете неправильный вопрос.

Повторная блокировка баз данных из-за длительных транзакций, обычно это ошибка проектирования кода / кода, иногда это проблема проектирования, связанная с действиями в SQL,Многие транзакции с маленькими наборами данных хороши, а один большой большой - плохо.

.

Чтобы получить поддержку транзакций в MySQL, вы должны убедиться, что все ваши таблицы имеют тип InnoDB, используя "CREATE TABLE tableName ( ... ) ENGINE=InnoDB;".

Необходимо сохранить драйвер SQL, дескриптор пула соединения (через c3p0) с autoCommit=false (это должно быть по умолчанию).

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

Не забудьте использовать правильный диалект Hibernate для InnoDB (проверьте выходные данные журнала запуска Hibernate).

Теперь узнайте, как это использовать.Если вы столкнулись с проблемой, это потому, что вы делаете что-то не так и не до конца понимаете.Если вы чувствуете, что вам нужно снизить уровень изоляции, прекратить использование транзакций или вам нужно autoCommit=true, тогда вам следует серьезно нанять профессионального консультанта, чтобы посмотреть на проект, и не стоит рассматривать его выключение, пока вы не поймете, почему и когда вы можете отключить его..

.

Обновление после редактирования

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

По умолчанию hibernate проверяет, что он получает, и модифицирует его при необходимости.Затем put возвращается к тому, что было до возвращения Соединения в пул соединений (некоторые разорванные пулы соединений не проверяют / сбрасывают это, поэтому hibernate делает это для улучшения взаимодействия в более крупной системе).

Так что, если это поможет с настройкой пула соединений (c3p0), то, возможно, вам следует начать с публикации подробностей о том, как вы его настроили?Используемая версия, а также пример используемой строки подключения JDBC, а также используемый вами JAR-драйвер MySQL.

И каков сценарий развертывания?автономный J2SE?веб-приложение WAR?сервер приложений?

Можете ли вы написать тестовый код, чтобы получить соединение, и есть API, чтобы спросить его, что это за режим autoCommit.http://download.oracle.com/javase/6/docs/api/java/sql/Connection.html#getAutoCommit%28%29 Ваша цель состоит в том, чтобы затем настроить свою конфигурацию так, чтобы вы всегда получали «false» из этого API.

Документация по драйверу MySQL http://dev.mysql.com/doc/refman/5.1/en/connector-j-reference-configuration-properties.html там есть ссылка на autoCommit.

Вы также хотите попытаться запустить «переменные mysqladmin» на своем сервере, чтобы вернуть конфигурацию сервера, возможно, можно установить ее глобально (что кажется ИМХО глупым занятием).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...