Pregunta

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 de escrituras, vemos algunas excepciones en el registro de errores así:

[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 el correspondiente mapeo de 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>

Es posible, aunque improbable, que varias instancias de nuestra aplicación web puedan escribir en la base de datos a la vez, ya que tenemos los números de versión en nuestro contexto de la aplicación web para lanzar nuevas versiones de las aplicaciones de manera transparente. Los clientes con la versión anterior de la aplicación almacenada en caché en su navegador web accederían así a las versiones anteriores del servidor, que no desplegaremos luego de unas semanas.

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

¿Fue útil?

Solución

El incremento es definitivamente malo si tiene más de un proceso de escritura en la misma tabla; está obligado a tener colisiones.

Ya que estamos hablando de MySQL, lo más fácil de usar sería identidad . En su asignación de hibernación:

<generator class="identity"/>

En tu script 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 alterar una tabla existente:

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

donde $ NEW_VALUE $ debe reemplazarse por el siguiente ID disponible para que la secuencia no se restablezca a 1.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top