2009-07-30 30 views
7

Estoy trabajando en una aplicación de base de datos que es principalmente de solo lectura, pero hay una tabla que registra el movimiento del usuario en la aplicación y tiene una gran cantidad de escrituras. Por cada pocos miles escribe, vemos algunas excepciones en el registro de errores de este modo:Obtener errores de entrada duplicados de Hibernate, ¿es culpa de MySQL?

[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) 

La tabla en cuestión tiene el siguiente esquema:

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; 

y la correspondiente XML de mapeo de Hibernate:

<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> 

Es posible, aunque poco probable, que varias instancias de nuestra aplicación web puedan estar escribiendo en la base de datos de una vez, ya que los números de versión en nuestro contexto de webapp liberan nueva v ersiones de las aplicaciones. Los clientes con la versión anterior de la aplicación almacenada en caché en su navegador web accederían a las versiones anteriores del servidor, que no implementamos después de unas semanas.

De todos modos, no estoy convencido de que este sea el problema, pero sospecho que hay un problema de sincronización entre MySQL e Hibernate aquí. ¿Cambiaría mi generador a secuencia, seqhilo o me ayudó? Además, si puede proporcionar un ejemplo de configuración de dicho generador en MySQL, sería muy útil, ya que la mayoría de los recursos en línea simplemente se copian y copian de los lamentablemente ejemplos minimalistas del manual de Hibernate.

Respuesta

9

Incrementar es definitivamente malo si tiene más de un proceso escribiendo en la misma tabla; es probable que tenga colisiones.

Dado que se trata de MySQL, lo más fácil de usar sería identity. En el mapeo de Hibernate:

<generator class="identity"/> 

en la secuencia de comandos de MySQL:

CREATE TABLE IF NOT EXISTS `my_table` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `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; 

Para modificar una tabla existente:

ALTER TABLE `my_table` 
    CHANGE COLUMN `id` `id` int(11) NOT NULL AUTO_INCREMENT=$NEW_VALUE$; 

donde $ NEW_VALUE $ debe ser sustituido por el siguiente ID disponible así esa secuencia no se reinicia a 1.

+0

Respuesta muy completa y clara - ¡gracias! –

Cuestiones relacionadas