2009-06-21 24 views
9

Estoy trabajando en una aplicación Java que usa Spring IoC y clases de plantilla JDBC. Tengo una clase DAO que tiene 4 métodos: m1() a m4(). m1 realiza múltiples inserciones y actualizaciones en la tabla t1, t2 m2 en mesa, m3 en t3, etc.Transacciones fáciles usando Spring JDBC?

Los métodos DAO se utilizan como sigue:

while(true) 
{ 
    //process & generate data 

    dao.m1(data1); 
    dao.m2(data2); 
    dao.m3(data3); 
    dao.m4(data4); 

    //sleep 
} 

Quiero las operaciones db bajo el método consecutiva 4 llamadas para ser atómicas, o bien todas las 4 tablas se actualizan correctamente o ninguna. Entonces, si hay un error al realizar operaciones en m3(), quiero deshacer todos los cambios (actualizaciones & insertos) realizados en m2 & m1.

Entonces, ¿la primavera te permite hacerlo de la siguiente manera?

while (true) 
{ 
    //process & generate data 

    transaction = TransactionManager.createNewTransaction(); 

    transaction.start() 

    try 
    { 
    dao.m1(data1); 
    dao.m2(data2); 
    dao.m3(data3); 
    dao.m4(data4); 
    } 
    catch(DbUpdateException e) 
    { 
    transaction.rollBack(); 
    } 

    transaction.end(); 

    // sleep 

}

o hay mejores maneras de hacerlo?

Respuesta

8

Para completar, la solución programática sería:

private TransactionTemplate transactionTemplate; 

public setTransactionManager(PlatformTransactionManager transactionManager) { 
    this.transactionTemplate = new TransactionTemplate(transactionManager); 
} 

... 

while (true) { 

    transactionTemplate.execute(new TransactionCallbackWithoutResult() { 
    protected void doInTransactionWithoutResult(TransactionStatus status) { 
     try { 
     dao.m1(data1); 
     dao.m2(data2); 
     dao.m3(data3); 
     dao.m4(data4); 
     } catch(DbUpdateException e) { 
     status.setRollbackOnly(); 
     } 
    } 
    }); 
} 
1

Sí, puede poner esas llamadas dentro de un método y especificar sus transacciones declaratively.

No necesita agregar ese código - Spring puede hacerlo por usted.

15

Sí Spring le permite programmatically control transactions.

Personalmente prefiero declarative transactions utilizando anotaciones, que dice así:

public void runBatchJob() { 
    while (true) { 
    // generate work 
    doWork(unitOfWork); 
    } 
} 

@Transactional 
private void doWork(UnitOfWork work) { 
    dao.m1(data1); 
    dao.m2(data2); 
    dao.m3(data3); 
    dao.m4(data4); 
} 

donde se definen las funciones DAO:

@Transactional 
public void m1(Data data) { 
    ... 
} 

Esto requiere en su applicationContext.xml:

<tx:annotation-driven/> 

Declarat Es posible declarar que las transacciones requieren una transacción, requieren una nueva transacción, transacciones de soporte, etc. La reversión se producirá cuando un bloque anotado con @Transactional arroja un RuntimeException.

+0

No creo que necesita anotar el M1, M2, etc., como @Transactional. Si alguno arroja una excepción, todo lo completado por doWork se revertirá. – Chadwick

+0

No es necesario en este contexto, no. Pero si están haciendo actualizaciones, debe anotar que requieren transacciones, de lo contrario, puede encontrarse realizando actualizaciones no transaccionales si las llama fuera del contexto de doWork(). – cletus

+0

¿La anotación @Transactional hace algo cuando se aplica a un método privado? –

1

primavera puede manejar todo esto para usted mediante el uso de @Transactional como se explica en XML o si lo prefiere.

La cuestión de la importación correcta es el tipo de Propagación de la transacción que desea que todo depende de su aplicación.

De manera predeterminada, se iniciará una transacción si no existe, y se volverá a utilizar una transacción existente si ya se ha iniciado una. Este es el comportamiento que desea si desea que los 4 DAO sean atómicos.

Ponga @Transactional en una clase que gestionará los métodos DAO llamados (MyService): cualquier elemento por debajo de esta capa ahora formará parte de ese límite de transacción.

i.e:

@Transactional 
public void m1(Data data) { 
... 
} 

@Transactional 
public void m2(Data data) { 
... 
} 

Hacer esto en el código es completamente innecesario.

Ver here for more info

Cuestiones relacionadas