ほとんどが読み取り専用のデータベース アプリケーションで作業していますが、アプリ内のユーザーの動きを記録し、多数の書き込みを行うテーブルが 1 つあります。数千回の書き込みごとに、次のようないくつかの例外がエラー ログに表示されます。
[WARN][2009-07-30 11:09:20,083][org.hibernate.util.JDBCExceptionReporter] SQL Error: 1062, SQLState: 23000
[ERROR][2009-07-30 11:09:20,083][org.hibernate.util.JDBCExceptionReporter] Duplicate entry '17011' for key 1
[ERROR][2009-07-30 11:09:20,083][org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
問題のテーブルには、次のスキーマがあります。
CREATE TABLE IF NOT EXISTS `my_table` (
`id` int(11) NOT NULL,
`data1` int(11) NOT NULL,
`data2` int(11) NOT NULL,
`timestamp` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
対応する Hibernate マッピング XML:
<hibernate-mapping>
<class name="mycorp.MyClass" table="my_table">
<id name="id" column="id" type="java.lang.Integer">
<generator class="increment"/>
</id>
<property name="data1" column="data1" type="java.lang.Integer"/>
<property name="data2" column="data2" type="java.lang.Integer"/>
<property name="timestamp" column="timestamp" type="java.util.Date"/>
</class>
</hibernate-mapping>
アプリケーションの新しいバージョンをシームレスにリリースするために、webapp コンテキストでバージョン番号を付けているため、可能性は低いですが、webapp の複数のインスタンスが一度にデータベースに書き込みを行う可能性があります。そのため、古いバージョンのアプリケーションが Web ブラウザーにキャッシュされているクライアントは、古いバージョンのサーバーにアクセスし、数週間後にデプロイを解除しました。
とにかく、これが問題であるとは確信していませんが、MySQL と Hibernate の間で同期の問題が発生しているのではないかと疑っています。ジェネレーターをシーケンス、seqhilo、または hilo に変更すると効果がありますか? また、MySQL でこのようなジェネレーターをセットアップする例を提供できれば、非常に役に立ちます。オンラインのリソースのほとんどは、Hibernate マニュアルの非常に最小限の例から単純にコピーして貼り付けたものだからです。