sesion script raspberry que programa para inicio iniciar hacer ejecute ejecutar como automaticamente java oracle spring-boot jdbctemplate spring-transactions

java - raspberry - ejecutar script al inicio linux centos 7



Deshaga A si B sale mal. arranque de primavera, jdbctemplate (6)

Tengo un método, ''databaseChanges'', que llama a 2 operaciones: A, B de forma iterativa. ''A'' primero, ''B'' último. ''A'' y ''B'' pueden ser funcionalidades de actualización, actualización y actualización en mi almacenamiento permanente, Oracle Database 11g.

Digamos,

''A'' actualiza un registro en la tabla Usuarios, atributo zip, donde id = 1.

''B'' inserta un registro en pasatiempos en la mesa.

Escenario: se llama al método databaseChanges, ''A'' opera y actualiza el registro. ''B'' funciona e intenta insertar un registro, sucede algo, se ha lanzado una excepción, la excepción es el método de cambio de base de datos.

Esperado: ''A'' y ''B'' no cambiaron nada. la actualización que ''A'' hizo, se revertirá. ''B'' no cambió nada, bueno ... hubo una excepción.

Actual: la actualización ''A'' no parece haberse revertido. ''B'' no cambió nada, bueno ... hubo una excepción.

Cierto código

Si tuviera la conexión, haría algo como:

private void databaseChanges(Connection conn) { try { conn.setAutoCommit(false); A(); //update. B(); //insert conn.commit(); } catch (Exception e) { try { conn.rollback(); } catch (Exception ei) { //logs... } } finally { conn.setAutoCommit(true); } }

El problema: no tengo la conexión (ver las etiquetas que se publican con la pregunta)

Lo intenté:

@Service public class SomeService implements ISomeService { @Autowired private NamedParameterJdbcTemplate jdbcTemplate; @Autowired private NamedParameterJdbcTemplate npjt; @Transactional private void databaseChanges() throws Exception { A(); //update. B(); //insert } }

Mi clase AppConfig:

import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @Configuration public class AppConfig { @Autowired private DataSource dataSource; @Bean public NamedParameterJdbcTemplate namedParameterJdbcTemplate() { return new NamedParameterJdbcTemplate(dataSource); } }

''A'' hace la actualización. de ''B'' se ha lanzado una excepción. La actualización realizada por ''A'' no se ha retrotraído.

Por lo que leí, entiendo que no estoy usando el @Transactional correctamente. Leí y probé varias publicaciones en blogs y preguntas y respuestas de stackverflow sin poder resolver mi problema.

¿Alguna sugerencia?

EDITAR

Hay un método que llama al método databaseChanges ()

public void changes() throws Exception { someLogicBefore(); databaseChanges(); someLogicAfter(); }

Qué método debe ser anotado con @Transactional,

cambios ()? databaseChanges ()?


Prueba esto:

@TransactionManagement(TransactionManagementType.BEAN) public class MyFacade { @TransactionAttribute(TransactionAttribute.REQUIRES_NEW) public void databaseChanges() throws Exception { A(); //update. B(); //insert }


Lo que parece que se está perdiendo es un TransactionManager . El objetivo de TransactionManager es poder gestionar las transacciones de la base de datos. Hay 2 tipos de transacciones, programáticas y declarativas. Lo que está describiendo es la necesidad de una transacción declarativa a través de anotaciones.

Entonces, lo que necesita para su proyecto es lo siguiente:

Dependencia de transacciones de primavera (usando Gradle como ejemplo)

compile("org.springframework:spring-tx")

Definir un administrador de transacciones en Spring Boot Configuration

Algo como esto

@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }

También necesitaría agregar la anotación @EnableTransactionManagement (no estoy seguro de si esto es gratis en las versiones más recientes del arranque de primavera).

@EnableTransactionManagement public class AppConfig { ... }

Añadir @Transactional

Aquí debería agregar la anotación @Transactional para el método que desea que participe en la transacción

@Transactional public void book(String... persons) { for (String person : persons) { log.info("Booking " + person + " in a seat..."); jdbcTemplate.update("insert into BOOKINGS(FIRST_NAME) values (?)", person); } };

Tenga en cuenta que este método debe ser público y no privado. Es posible que desee considerar poner @Transactional en el método público llamando a databaseChanges() .

También hay temas avanzados sobre dónde debe ir @Transactional y cómo se comporta, así que es mejor trabajar primero y luego explorar esta área un poco más tarde :)

Una vez que todos estos estén en su lugar (dependencia + configuración de transactionManager + anotación), las transacciones deberían funcionar en consecuencia.

Referencias

Spring Reference Documentation on Transactions

Guía de primavera para las transacciones que usan Spring Boot : tiene un código de muestra con el que puede jugar


@Transactional anotación @Transactional en la primavera funciona envolviendo su objeto en un proxy que a su vez ajusta los métodos anotados con @Transactional en una transacción. Debido a que la anotación no funcionará en métodos privados (como en su ejemplo) porque los métodos privados no se pueden heredar => no se pueden envolver (esto no es cierto si usa transacciones declarativas con aspectj , entonces las advertencias relacionadas con proxy a continuación no se aplican).

Aquí hay una explicación básica de cómo @Transactional magia de primavera @Transactional .

Tu escribiste:

class A { @Transactional public void method() { } }

Pero esto es lo que realmente obtienes cuando te inyectas un frijol:

class ProxiedA extends A { private final A a; public ProxiedA(A a) { this.a = a; } @Override public void method() { try { // open transaction ... a.method(); // commit transaction } catch (RuntimeException e) { // rollback transaction } catch (Exception e) { // commit transaction } } }

Esto tiene limitaciones. No funcionan con los métodos de @PostConstruct porque se llaman antes de que el objeto sea proxy. E incluso si configuró todos correctamente, las transacciones solo se retrotraen en excepciones sin marcar de forma predeterminada. Utilice @Transactional(rollbackFor={CustomCheckedException.class}) si necesita deshacer una excepción marcada.

Otra advertencia frecuente que conozco:

@Transactional método @Transactional solo funcionará si lo llama "desde afuera", en el siguiente ejemplo b() no se incluirá en la transacción:

class X { public void a() { b(); } @Transactional public void b() { } }

También es porque @Transactional funciona al @Transactional tu objeto. En el ejemplo anterior, a() llamará a Xb() no a un método mejorado "proxy de primavera" b() por lo que no habrá transacción. Como solución, debe llamar a b() desde otro bean.

Cuando encuentre alguna de estas advertencias y no pueda utilizar una solución alternativa sugerida (haga que el método no sea privado o llame a b() desde otro bean) puede usar TransactionTemplate lugar de transacciones declarativas:

public class A { @Autowired TransactionTemplate transactionTemplate; public void method() { transactionTemplate.execute(status -> { A(); B(); return null; }); } ... }

Actualizar

Respondiendo a OP pregunta actualizada utilizando la información anterior.

¿Qué método debe ser anotado con @Transactional: changes ()? databaseChanges ()?

@Transactional(rollbackFor={Exception.class}) public void changes() throws Exception { someLogicBefore(); databaseChanges(); someLogicAfter(); }

Asegúrese de que los changes() se llamen "desde afuera" de un bean, no de la clase en sí y después de la afterPropertiesSet() instancias del contexto (por ejemplo, esto no es afterPropertiesSet() o @PostConstruct método anotado). Comprenda que la transacción de rollbacks de primavera solo se realiza por excepciones sin marcar de forma predeterminada (intente ser más específico en la reversión para la lista de excepciones verificadas).


Cualquier RuntimeException desencadena reversión, y cualquier Excepción marcada no lo hace.

Este es un comportamiento común en todas las API de transacciones de Spring. De forma predeterminada , si se lanza una RuntimeException dentro del código transnacional, la transacción se retrotraerá. Si se lanza una excepción marcada (es decir, no una RuntimeException ), la transacción no se revertirá.

Depende de qué excepción obtenga dentro de la función de cambio de base de datos. Entonces, para capturar todas las excepciones, todo lo que necesita hacer es agregar rollbackFor = Exception.class

El cambio se supone que debe estar en la clase de servicio, el código será así:

@Service public class SomeService implements ISomeService { @Autowired private NamedParameterJdbcTemplate jdbcTemplate; @Autowired private NamedParameterJdbcTemplate npjt; @Transactional(rollbackFor = Exception.class) private void databaseChanges() throws Exception { A(); //update B(); //insert } }

Además, puede hacer algo agradable con él, así que no todo el tiempo tendrá que escribir rollbackFor = Exception.class . Puede lograrlo escribiendo su propia anotación personalizada:

@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Transactional(rollbackFor = Exception.class) @Documented public @interface CustomTransactional { }

El código final será así:

@Service public class SomeService implements ISomeService { @Autowired private NamedParameterJdbcTemplate jdbcTemplate; @Autowired private NamedParameterJdbcTemplate npjt; @CustomTransactional private void databaseChanges() throws Exception { A(); //update B(); //insert } }


El primer código que presenta es para UserTransactions, es decir, la aplicación tiene que hacer la gestión de transacciones. Por lo general, usted quiere que el contenedor se encargue de eso y use la anotación @Transactional. Creo que el problema en tu caso podría ser que tienes la anotación en un método privado. Movería la anotación al nivel de clase

@Transactional public class MyFacade { public void databaseChanges() throws Exception { A(); //update. B(); //insert }

Entonces debería deshacerse correctamente. Puede encontrar más detalles aquí. ¿Funciona el atributo Spring @Transactional en un método privado?


Lo que necesitas es algo como esto:

@Transactional(propagation=Propagation.REQUIRES_NEW, rollbackFor = {Exception.class}) public void databaseChanges() throws Exception { A(); //update. B(); //insert } @Transactional(propagation=Propagation.REQUIRED, rollbackFor = {Exception.class}) public void A() throws Exception { // update } @Transactional(propagation=Propagation.REQUIRED, rollbackFor = {Exception.class}) public void B() throws Exception { // insert }

Al especificar la propagación como REQUIRES_NEW se asegura de que se inicia una nueva transacción para el método databaseChanges() y A() y B() participan en la misma transacción con su propagación especificada como REQUIRED .

Debes asegurarte de que los métodos que estás anotando con @Transactional anotaciones @Transactional sean públicos porque el consejo transaccional se aplica solo a los métodos públicos . Un método privado anotado como tal NO arrojaría un error pero NO mostraría el comportamiento transaccional.

Ahora, cuando se producirá una excepción en B() durante la inserción, el administrador de transacciones verifica internamente las reglas de retrotracción (que se especifican mediante rollbackFor); encuentra Exception.class y marca la transacción (iniciada en databaseChanges ()) como rollback-only y retrotraerá A () junto con ella ya que A () está participando en la misma transacción

Si esto no resuelve su problema, habilite los registros de rastreo de Springframework y bríndenme eso. Los límites de las transacciones y los sucesos se registran con precisión en estos registros cuando están habilitados.

Si no ve el registro de transacciones adecuado, entonces verifique si la gestión de transacciones está realmente habilitada en su aplicación. Agregar @EnableTransactionManagement en la clase de configuración lo habilita.

Campo de golf:
Propagación
RollbackFor
Transaccional en métodos privados
@EnableTransactionManagement