¿Cuál es la “mejor” forma de hacer transacciones distribuidas en múltiples bases de datos usando Spring e Hibernate?

Tengo una aplicación, más parecida a una utilidad, que se encuentra en una esquina y actualiza periódicamente dos bases de datos diferentes.

Es una pequeña aplicación independiente que se ha creado con un contexto de aplicación de spring. El contexto tiene dos Hibernate Session Factories configuradas en él, a su vez utilizando fonts de datos de Commons DBCP configuradas en Spring.

Actualmente no hay administración de transacciones, pero me gustaría agregar algunas. La actualización de una base de datos depende de una actualización exitosa de la otra.

La aplicación no se sienta en un contenedor Java EE, sino que está iniciada por una clase de iniciador estático llamado desde un script de shell. La clase de iniciador crea una instancia del contexto de la aplicación y luego invoca un método en uno de sus beans.

¿Cuál es la “mejor” forma de poner transaccionalidad en las actualizaciones de la base de datos?

Dejaré la definición de “lo mejor” para ti, pero creo que debería ser una función de “fácil de configurar”, “fácil de configurar”, “económica” y “fácil de empaquetar y redistribuir”. Naturalmente, FOSS sería bueno.

La mejor forma de distribuir transacciones en más de una base de datos es: No hacer.

Algunas personas lo señalarán con XA, pero XA (o Compromiso de dos fases) es una mentira (o marketese).

Imagínese: después de la primera fase le dijo al administrador de XA que puede enviar el compromiso final, la conexión de red a una de las bases de datos falla. ¿Ahora que? ¿Se acabó el tiempo? Eso dejaría la otra base de datos corrupta. ¿Retroceder? Dos problemas: no puede deshacer una confirmación y ¿cómo sabe qué sucedió con la segunda base de datos? ¿Tal vez la conexión de red falló después de que haya confirmado los datos y solo se haya perdido el mensaje de “éxito”?

La mejor manera es copiar los datos en un solo lugar. Utilice un esquema que le permita abortar la copia y continuarla en cualquier momento (por ejemplo, ignore los datos que ya tiene o solicite el ID seleccionado por ID y solicite solo registros> MAX (ID) de su copia). Protege esto con una transacción. Esto no es un problema, ya que solo está leyendo datos de la fuente, por lo que cuando la transacción falla por algún motivo, puede ignorar la base de datos de origen. Por lo tanto, esta es una simple transacción de origen única.

Después de haber copiado los datos, trátelos localmente.

Configura un administrador de transacciones en tu contexto. Los documentos de Spring tienen ejemplos, y es muy simple. Luego, cuando quieras ejecutar una transacción:

try { TransactionTemplate tt = new TransactionTemplate(txManager); tt.execute(new TransactionCallbackWithoutResult(){ protected void doInTransactionWithoutResult( TransactionStatus status) { updateDb1(); updateDb2(); } } catch (TransactionException ex) { // handle } 

Para obtener más ejemplos e información, tal vez vea esto: transacciones XA usando Spring

Cuando dices “dos bases de datos diferentes”, ¿te refieres a diferentes servidores de bases de datos, o dos esquemas diferentes dentro del mismo servidor de bases de datos?

Si es el primero, entonces si desea una transaccionalidad completa, necesita la API de transacción XA, que proporciona una confirmación de dos fases completa. Pero lo más importante es que también necesita un coordinador / monitor de transacciones que administre la propagación de transacciones entre los diferentes sistemas de bases de datos. Esto es parte de la especificación JavaEE, y una parte bastante enrarecida de eso. El coordinador de TX en sí es una pieza compleja de software. El software de su aplicación (a través de Spring, si lo desea) habla con el coordinador.

Sin embargo, si solo quiere decir dos bases de datos dentro del mismo servidor de bases de datos, entonces las transacciones JDBC de vanilla deberían funcionar bien, solo realice sus operaciones con ambas bases de datos en una sola transacción.

En este caso, necesitaría un Monitor de transacciones (servidor compatible con el protocolo XA) y asegúrese de que sus bases de datos también sean compatibles con XA. La mayoría (¿todos?) De los servidores J2EE vienen con el Monitor de Transacción incorporado. Si su código no se está ejecutando en el servidor J2EE, existen muchas alternativas independientes: Atomicos, Bitronix, etc.

Puede probar Spring ChainedTransactionManager – http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html que admite la transacción distribuida de db. Esta podría ser una mejor alternativa a XA