Это старый вопрос, но у меня возникла похожая проблема, и я решил добавить в эту тему. Мне нужно было добавить журнал в существующую программу записи журнала аудита StatelessSession. Существующая реализация использовала StatelessSession, потому что поведение кеширования стандартной реализации сеанса было ненужным: и . Мы не хотели, чтобы наши слушатели hibernate запускались для записи журнала аудита. Эта реализация была направлена на достижение максимально высокой производительности записи без каких-либо взаимодействий.
Однако новый тип журнала должен был использовать поведение типа вставки-обновления-обновления, где мы намереваемся обновить существующие записи журнала со временем транзакции как тип поведения «пометки». В StatelessSession saveOrUpdate () не предлагается, поэтому нам нужно было реализовать вставку-еще-обновление вручную.
В свете этих требований:
Вы можете использовать mysql "вставка ... при обновлении дублированного ключа" через пользовательский sql-вставку для персистентного объекта гибернации. Вы можете определить пользовательское предложение sql-insert либо с помощью аннотации (как в приведенном выше ответе), либо с помощью объекта sql-insert с помощью отображения hibernate xml, например ::
<class name="SearchAuditLog" table="search_audit_log" persister="com.marin.msdb.vo.SearchAuditLog$UpsertEntityPersister">
<composite-id name="LogKey" class="SearchAuditLog$LogKey">
<key-property
name="clientId"
column="client_id"
type="long"
/>
<key-property
name="objectType"
column="object_type"
type="int"
/>
<key-property
name="objectId"
column="object_id"
/>
</composite-id>
<property
name="transactionTime"
column="transaction_time"
type="timestamp"
not-null="true"
/>
<!-- the ordering of the properties is intentional and explicit in the upsert sql below -->
<sql-insert><![CDATA[
insert into search_audit_log (transaction_time, client_id, object_type, object_id)
values (?,?,?,?) ON DUPLICATE KEY UPDATE transaction_time=now()
]]>
</sql-insert>
Оригинальный постер спрашивает конкретно о MySQL. Когда я реализовал поведение вставки-обновления-обновления с помощью mysql, я получал исключения, когда «путь обновления» sql был представлен. В частности, mysql сообщал, что 2 строки были изменены, когда была обновлена только 1 строка (якобы потому, что существующая строка удаляется, а новая строка вставляется). См. этот выпуск для получения более подробной информации об этой конкретной функции.
Поэтому, когда обновление вернулось в 2 раза больше строк, затронутых hibernate, hibernate выдавал исключение BatchedTooManyRowsActedException, откатил транзакцию и распространил исключение. Даже если вы должны были перехватить исключительную ситуацию и обработать ее, к этому моменту транзакция уже была отменена.
После некоторого копания я обнаружил, что это проблема с персистентностью сущности, которую использовал hibernate. В моем случае hibernate использовал SingleTableEntityPersister, который определяет ожидание того, что число обновленных строк должно соответствовать количеству строк, определенных в пакетной операции.
Последней настройкой, необходимой для работы этого поведения, было определение пользовательского персистера (как показано в приведенном выше сопоставлении xml). В этом случае все, что нам нужно было сделать, это расширить SingleTableEntityPersister и «переопределить» ожидание вставки. Например. Я просто прикрепил этот статический класс к объекту персистентности и определил его как пользовательский персистент в отображении гибернации:
public static class UpsertEntityPersister extends SingleTableEntityPersister {
public UpsertEntityPersister(PersistentClass arg0, EntityRegionAccessStrategy arg1, SessionFactoryImplementor arg2, Mapping arg3) throws HibernateException {
super(arg0, arg1, arg2, arg3);
this.insertResultCheckStyles[0] = ExecuteUpdateResultCheckStyle.NONE;
}
}
Потребовалось немало времени, чтобы покопаться в коде гибернации, чтобы найти это - я не смог найти ни одной темы в сети с решением этой проблемы.