duda SimpleJdbctemplate con transction Manager

Hola a todos, mi duda es la sigueinte tengo una operacion de negocio que inserta en una cabecera y 5 detalles, la cuestion es qu si falla la insercion de detalles debo hacer rollback a todas las insercciones anteriores, he tratado de configurar el tranasaction manager de spring y al parecer todo esta bien pero cuando obligo a la operacion a lanzar una excepcion en uno de los detalles no le hacer rollback a nada, anexo mi codigo de configuracion para saber si estoy haciendo algo mal o si me falta algo de antemano gracias por su valiosa atencion

APP Context

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName">
            <value>jdbc/SimaEspecial</value>
        </property>
    </bean>
       
                <tx:annotation-driven transaction-manager="transactionManager"/>  
       
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>

        <aop:config>  
             <aop:advisor pointcut="execution(* *..com.easywest.sima.inventario.DAO+.*(..))" advice-ref="txAdvice"/>  
     </aop:config>  
 
         <tx:advice id="txAdvice">  
                  <tx:attributes>  
                                <tx:method name="insert*" rollback-for="java.lang.RuntimeException"/>  
                  </tx:attributes>  
        </tx:advice>  
       
        <bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">  
                <constructor-arg><ref bean="dataSource"/></constructor-arg>
        </bean>  

.

DAO

.
@Transactional
    public boolean insertConfigC(InvCconfiDTO insrtCconfiDTO){
       
        SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd" );
       
        boolean flag=false;
        String sSql="INSERT INTO ABASTO_DB.INV_C_CONFIG_CAB (ID_FOLIO_C,"
                    + " ID_MOTIVO,"
                    + "B_LUNES,"
                    + "B_MARTES,"
                    + "B_MIERCOLES,"
                    + "B_JUEVES,"
                    + "B_VIERNES,"
                    + "B_SABADO,"
                    + "B_DOMINGO,"
                    + " FRECUENCIA,"
                    + " FH_CREACION,"
                    + "SEMANA_PEDIR,"
                    + "F_INICIO_VIGENCIA, "
                    +" F_FIN_VIGENCIA,"
                    + " DIAS_VIGENCIA,"
                    + " MAX_ARTICULO,"
                    + " ESTATUS )"
                    + " VALUES (?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "SYSDATE,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?,"
                    + "?)";
        try {
            simpleJdbcTemplate.update(sSql,
                                      insrtCconfiDTO.getIdFolio(),
                                      insrtCconfiDTO.getIdMotivo(),
                                      valdiaBoolean(insrtCconfiDTO.isB_Lunes()),
                                      valdiaBoolean(insrtCconfiDTO.isB_Martes()),
                                      valdiaBoolean(insrtCconfiDTO.isB_Miercoles()),
                                      valdiaBoolean(insrtCconfiDTO.isB_Jueves()),
                                      valdiaBoolean(insrtCconfiDTO.isB_Viernes()),
                                      valdiaBoolean(insrtCconfiDTO.isB_Sabado()),
                                      valdiaBoolean(insrtCconfiDTO.isB_Domingo()),
                                      insrtCconfiDTO.getFrecuencia(),
                                      insrtCconfiDTO.getSemanaPedir(),
                                      sdf.parse(insrtCconfiDTO.getFchInicioV()),
                                      sdf.parse(insrtCconfiDTO.getFchFinV()),
                                      insrtCconfiDTO.getDiasVigencia(),
                                      insrtCconfiDTO.getMax_art(),
                                      1);
            flag=true;
        } catch (Exception e) {
            log.error("Error: " + e.getMessage());
        }
        return flag;
    }

.

esta es la inserccion del detalle como se ve le estoy mandando un null al id para que lance la excepcion y pro lo consiguiente deberia de ahcer rollback a la cabecera. si alguien me puede ilustrar en que estoy haciendo mal de antemano se los agradezco

@Transactional(propagation= Propagation.REQUIRED)
public boolean insertArt(InsertDTO insertDTO){
    boolean flag=false;
    StringBuilder sb=new StringBuilder();
    sb.append("INSERT INTO ");
    sb.append(OWNER);
    sb.append(".INV_C_DET_ARTICULO(");
    sb.append("ID_FOLIO_C,");
    sb.append("CODIGO_BARRAS) ");
    sb.append("VALUES");
    sb.append("(");
    sb.append("?,");
    sb.append("?)");
    try {
        simpleJdbcTemplate.update(sb.toString(),
                null,
                insertDTO.getIdArt());
        flag=true;
    } catch (DataAccessException e) {
        log.error("Error: "+e.getMessage());
    }
   
    return flag;
}

.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

@Transactional

Si usas @Transactional, no veo por qué necesitas lo de aop:config.

Todo lo veo bien... excepto que estás cachando DataAccessException.

Para que eso funcione necesitas lo siguiente:

Configurar lo de annotation-driven, indicando una de las dos opciones:

1. Configurar Spring para que tus proxies los haga con CGLIB, creando subclases para envolver TODOS los métodos
2. (más fácil, y la opción default) crear interfaces con los métodos que van a ser transaccionales, y que tus componentes implementen esas interfaces.

Ejemplo:

public interface Transaccional {
  public void insertar5datos();
}

public class Componente implements Transaccional {
  @Transactional
  public void insertar5datos() {
    //blabla
  }
}

Eso lo tienes (casi) bien. Y en tu XML va algo así:

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans <a href="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
" title="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
">http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
</a>            <a href="
http://www.springframework.org/schema/context" title="http://www.springframework.org/schema/context">http://www.springframework.org/schema/context</a> <a href="http://www.springframework.org/schema/context/spring-context-3.0.xsd
" title="http://www.springframework.org/schema/context/spring-context-3.0.xsd
">http://www.springframework.org/schema/context/spring-context-3.0.xsd
</a>            <a href="
http://www.springframework.org/schema/tx" title="http://www.springframework.org/schema/tx">http://www.springframework.org/schema/tx</a> <a href="http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<context:annotation-config" title="http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<context:annotation-config">http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<context:a...</a> />
<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager" class="blabla, esto ya lo tienes definido" />

<bean id="componente" class="Componente" />

</beans>

Ahí nomás vi que te sobra lo de aop:config pero tal vez es para otra cosa, no sé.

Lo más importante: NO CACHES las excepciones de tiempo de ejecución! si lo haces pues el interceptor no se puede dar cuenta y por eso no da rollback. Si vas a manejar las excepciones entonces TU tienes que manejar tus transacciones. Necesitas más bien algo así:

@Transactional
public boolean metodo() {
  boolean flag = false;
  try {
    //todo tu codigo
    flag = true;
  } finally {
    //liberar cualquier recurso que se necesite (aunque no veo nada en tu código)
  }
  return flag;

La documentación de todo este rollo de @Transactional y annotation-driven dice que la manera en que funciona es que se abren transacciones para los métodos anotados; si terminan bien su ejecución se hace commit, pero si se arroja cualquier RuntimeException entonces se da rollback. No hay rollback para excepciones declaradas (tu método las debe manejar todas, o arrojar RuntimeException que envuelva una excepción declarada). A fin de cuentas lo que hace es crear un proxy dinámico que envuelva tu componente y hace algo así:

public void interceptarLlamada() {
  TransactionStatus tx = //crear transaccion con el transactionManager
  try {
    tuobjeto.tumetodo();
  } catch (RuntimeException ex) {
    tx.setRollbackOnly();
  }
  transactionManager.commit(tx);
}

Por lo tanto, obviamente si cachas internamente DataAccessException, pues el método externo nunca se da cuenta y se da commit.

Imagen de ingscjoshua

GRacias!!!

ok Pues si hare lo del proxy por default, entoces solo necesito configurar mis clases y en ellas debo de poner un throws SQL Exception?? o solo lo debo dejar sin ningu throws?, si en mi Buissne Object primero ejecuto la inserccion de la cabecera y despues las demas inserciones si alguna de las otras inserciones falla se hara el rollback incluso de la cabecera?

Imagen de ingscjoshua

y lo de AOP

dado q nunca he usado el transaction manager fui viendo implementaciones y me encontre una muy parecida a la q yo necesitaba pero no funcionaba asi q pro eso esta eso de AOP pero no lo necesito solo fue un ejemplo fallido

Imagen de ezamudio

SQLException

SQLException es una excepción declarada, no de tiempo de ejecución. Tus métodos anotados con @Transactional deben manejar ese caso (pero si estás usando JdbcTemplate no veo por qué vas a declarar que arrojas eso).

Imagen de ingscjoshua

gracias

Ok, ya cambie mi implementaciion pero no le da rollback a la cabecera, si falla algo en la inserccion de los detalles

metodo del DAO

@Transactional
public boolean insertArt(InsertDTO insertDTO){
    boolean flag=false;
    StringBuilder sb=new StringBuilder();
    sb.append("INSERT INTO ");
    sb.append(OWNER);
    sb.append(".INV_C_DET_ARTICULO(");
    sb.append("ID_FOLIO_C,");
    sb.append("CODIGO_INTERNO,");
    sb.append("CODIGO_BARRAS) ");
    sb.append("VALUES");
    sb.append("(");
    sb.append("?,");
    sb.append("?,");
    sb.append("?)");
        simpleJdbcTemplate.update(sb.toString(),
               // insertDTO.getIdFolio(),
                null,
                insertDTO.getIdCodInt(),
                insertDTO.getIdArt());
        flag=true;
   
    return flag;

appcontext

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>

 <!-- SECCION PARA LA DECLARACION DEL JNDI -->
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName">
            <value>jdbc/SimaEspecial</value>
        </property>
    </bean>
       
                <tx:annotation-driven transaction-manager="transactionManager"/>  
       
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>  
         <tx:advice id="txAdvice">  
                  <tx:attributes>  
                                <tx:method name="insert*" rollback-for="java.lang.RuntimeException"/>  
                  </tx:attributes>  
        </tx:advice>  
       
        <bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">  
                <constructor-arg><ref bean="dataSource"/></constructor-arg>
        </bean>  

 
  <!--#lectura del fichero administrable  -->  
 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
         <property name="ignoreUnresolvablePlaceholders">  
             <value>true</value>  
         </property>  
         <property name="locations">  
             <list>  
                 <value>classpath:/Mail.properties</value>  
             </list>  
         </property>  
     </bean>
     <!--#Configuración del servicio de Spring: MailSession JNDI -->
                <!-- <bean id="mailSession"
                class="org.springframework.jndi.JndiObjectFactoryBean">
                <property name="jndiName" value="mail/Session" />
                <property name="resourceRef" value="true" />
                </bean>-->
        <!--#Configuración del servicio de Spring: MailSernder -->
         <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">  
       <property name="host" value="${host}"/>  
       <property name="port" value="${port}"/>  
       <property name="username" value="${user}"/>  
       <property name="password" value="${password}"/>  
       <property name="protocol" value="${protocol}"/>  
       <property name="defaultEncoding" value="UTF-8"/>
        <property name="javaMailProperties">
                    <props>
                        <!-- Use SMTP transport protocol -->
                        <prop key="mail.transport.protocol">${protocol}</prop>
                        <!-- Use SMTP-AUTH to authenticate to SMTP server -->
                        <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
                        <!-- Use TLS to encrypt communication with SMTP server -->
                        <prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
                        <prop key="mail.debug">true</prop>
                    </props>
                </property>
       
       <!--<property name="session" ref="mailSession" />-->
     </bean>  
 
 
  <!-- Seccion de DAO -->
    <bean id="UsuarioDAO" class="com.easywest.sima.seguridad.DAO.UsuarioDAO">
        <property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"/>
    </bean>
    <bean id="MenuDAO" class="com.easywest.sima.seguridad.DAO.MenuDAO">
        <property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"/>
    </bean>
    <bean id="PerfilDAO" class="com.easywest.sima.seguridad.DAO.PerfilDAO">
        <property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"/>
    </bean>
    <bean id="MenuPerfilDAO" class="com.easywest.sima.seguridad.DAO.MenuPerfilDAO">
        <property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"/>
    </bean>
     
    <bean id="IinvConfigDAO" class="com.easywest.sima.inventario.DAO.InvCconfigDAO">
        <property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"/>
    </bean>
   
    <bean id="FormatoTiendaDAO" class="com.easywest.sima.inventario.DAO.FormatoTiendaDAO">
        <property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"/>
    </bean>
    <bean id="MotivoDAO" class="com.easywest.sima.inventario.DAO.MotivoDAO">
        <property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"/>
    </bean>
   
    <!-- SECCION DE BO -->
    <bean id="loginBO" class="com.easywest.sima.seguridad.BO.LoginBO">
        <property name="usuarioDAO" ref="UsuarioDAO"/>
        <property name="menuDAO" ref="MenuDAO"/>
    </bean>
   <bean id="menuBO" class="com.easywest.sima.seguridad.BO.MenuBO">
        <property name="menuDAO" ref="MenuDAO"/>
        <property name="perfilDAO" ref="PerfilDAO"/>
        <property name="menuPerfilDAO" ref="MenuPerfilDAO"/>
    </bean>
    <bean id="securityBO" class="com.easywest.sima.seguridad.BO.SecurityBO">
        <property name="menuPerfilDAO" ref="MenuPerfilDAO"/>
    </bean>
    <bean id="mailBO" class="com.easywest.sima.seguridad.BO.MailBO">
        <property name="usuarioDAO" ref="UsuarioDAO"/>
        <property name="mailSender" ref="mailSender"/>
    </bean>
    <bean id="invCconfigBO" class="com.easywest.sima.inventario.BO.InvCconfigBO">
        <property name="InvCconfigDAO" ref="IinvConfigDAO"/>
        <property name="formatoTiendaDAO" ref="FormatoTiendaDAO"/>
    </bean>
     <bean id="MotivoBO" class="com.easywest.sima.inventario.BO.MotivoBO">
        <property name="motivoDAO" ref="MotivoDAO"/>
    </bean>
    <bean id="configEcBO" class="com.easywest.sima.inventario.BO.ConfigEcBO">
    </bean>
   
    <!-- SECCION DE ACTION -->
    <bean id="login" class="com.easywest.sima.seguridad.Action.LoginAction" scope="prototype">
        <property name="loginBO" ref="loginBO"/>
        <property name="menuBO" ref="menuBO"/>
    </bean>
    <bean id="closeSession" class="com.easywest.sima.seguridad.Action.CloseSession" scope="prototype" />
    <bean id="menuAction" class="com.easywest.sima.seguridad.Action.MenuAction" scope="prototype" >
        <property name="menuBO" ref="menuBO"/>
        <property name="perfilBO" ref="perfilBO"/>
        <property name="securityBO" ref="securityBO"/>
    </bean>
    <bean id="mailAction" class="com.easywest.sima.seguridad.Action.MailAction" scope="prototype">
        <property name="mailBO" ref="mailBO"/>
    </bean>
    <bean id="configuracionAction" class="com.easywest.sima.inventario.Action.ConfiguracionAction" scope="prototype">
         <property name="invCconfigBO" ref="invCconfigBO"/>
          <property name="securityBO" ref="securityBO"/>
          <property name="configEcBO" ref="configEcBO"/>
         
     </bean>
     <bean id="cfgArtAction" class="com.easywest.sima.inventario.Action.ConfArtAction" scope="prototype">
         <property name="invCconfigBO" ref="invCconfigBO"/>
         <property name="securityBO" ref="securityBO"/>
     </bean>
     <bean id="cfgSucAction" class="com.easywest.sima.inventario.Action.ConfSucAction" scope="prototype">
         <property name="invCconfigBO" ref="invCconfigBO"/>
         <property name="securityBO" ref="securityBO"/>
     </bean>
     <bean id="cfgGralAction" class="com.easywest.sima.inventario.Action.ConfGralAction" scope="prototype">
         <property name="invCconfigBO" ref="invCconfigBO"/>
         <property name="securityBO" ref="securityBO"/>
         <property name="motivoBO" ref="MotivoBO" />
     </bean>
</beans>

BO

 configDTO.setIdFolio(invCconfigBO.getIdFolio());
            if(invCconfigBO.insertConf(configDTO)){
                if(lstArticuloDTO!=null){
                    log.info("insertando configuracion por articulo");
                    for (ArticuloDTO tmp : lstArticuloDTO) {
                        InsertDTO insertTmp= new InsertDTO();
                        insertTmp.setIdFolio(configDTO.getIdFolio());
                        insertTmp.setIdArt(Long.valueOf(tmp.getCodBarras()));
                        insertTmp.setIdCodInt(tmp.getCodInterno());
                        invCconfigBO.insertArt(insertTmp);
                    }
                   
                }else{
                    log.info("Insertando configuracion por EC");
                    if(lstProveedorConfigDTO!=null){
                        for (ProveedorConfigDTO tmp : lstProveedorConfigDTO) {
                            InsertDTO insertTmp= new InsertDTO();
                            insertTmp.setIdFolio(configDTO.getIdFolio());
                            insertTmp.setId(tmp.getIdProveedor());
                            if(!String.valueOf(tmp.getB_NoResurtible()).equals("0")){
                                insertTmp.setIdP(0);
                            }else if(!String.valueOf(tmp.getB_Resurtible()).equals("0")){
                                insertTmp.setIdP(tmp.getB_Resurtible());
                            }else if(!String.valueOf(tmp.getB_TodosArt()).equals("0")){
                                insertTmp.setIdP(tmp.getB_TodosArt());
                            }
                            invCconfigBO.insertProv(insertTmp);
                           
                           
                        }
                    }
                    if(lstSeccionDTO!=null){
                        for (SeccionDTO tmp : lstSeccionDTO) {
                             InsertDTO insertTmp= new InsertDTO();
                            insertTmp.setIdFolio(configDTO.getIdFolio());
                            insertTmp.setId(tmp.getIdSeccion());
                            invCconfigBO.insertSecc(insertTmp);
                        }
                    }
                    if(lstCategoriaDTO!=null){
                        for (CategoriaDTO tmp : lstCategoriaDTO) {
                             InsertDTO insertTmp= new InsertDTO();
                            insertTmp.setIdFolio(configDTO.getIdFolio());
                            insertTmp.setId(tmp.getIdCategoria());
                            invCconfigBO.insertCat(insertTmp);
                        }
                       
                    }
                }
                if(lstSucursalDTO!=null){
                    for (SucursalDTO tmp : lstSucursalDTO) {
                       InsertDTO insertTmp= new InsertDTO();
                            insertTmp.setIdFolio(configDTO.getIdFolio());
                            insertTmp.setId(tmp.getIdSucursal());
                            invCconfigBO.insertSuc(insertTmp);
                       
                    }
                }else if(lstFromat!=null){
                    for (SucursalDTO tmp : lstFromat) {
                         InsertDTO insertTmp= new InsertDTO();
                            insertTmp.setIdFolio(configDTO.getIdFolio());
                            insertTmp.setId(tmp.getIdFormato());
                            invCconfigBO.insertFormat(insertTmp);
                       
                    }
                }else if(lstSubDir!=null){
                    for (SucursalDTO tmp : lstSubDir) {
                         InsertDTO insertTmp= new InsertDTO();
                            insertTmp.setIdFolio(configDTO.getIdFolio());
                            insertTmp.setId(tmp.getIdSubdirector());
                            invCconfigBO.insertSubDir(insertTmp);
                       
                    }
                }
            }
Imagen de ezamudio

mmmm

pues por como se ve, debería funcionar... lee bien la documentación porque tal vez sea un tema de que estás poniéndole un DataSourceTransactionManager a un DataSource del contenedor (porque lo obtienes por JNDI) y creo que en esos casos debes usar también un transactionManager del contenedor (generalmente si el contenedor maneja dataSources, tiene transactionManagers de JTA).

Imagen de ingscjoshua

Ok

Lo revisare esto corre bajo un Glasfish 3.1, pero no tengo configurado ningun JTA en el contenedor aun asi tendria que ponerle un transarciton Manager de JTA?

Imagen de ezamudio

no

El JtaTransactionManager de Spring es una especie de proxy para usar el manejador de transacciones de JTA del contenedor.

Para probar si es el DataSource, sustitúyelo por uno propio (puedes usar un BasicDataSource de apache DBCP, solamente necesitas agregar dos dependencias a tu proyecto, commons-pool y commons-dbcp, y son en runtime, no hay que recompilar nada). Si con un DataSource propio (creado dentro de tu appcontext) todo funciona OK, entonces la bronca es con el dataSource JNDI.

Que tú no hayas configurado JTA en el contenedor no quiere decir que ya venga por default... otra cosa, el driver JDBC que usas para tu base de datos de JDBC4? Porque creo que tiene que ser JDBC4 o cuando menos JDBC3 (los docs de Spring indican todo eso).

Imagen de ingscjoshua

ammm

oks, uso oracle y es ojdbc6.jar

Imagen de ezamudio

revisa

No sé qué sea eso de ojdbc6.jar pero no existe JDBC tipo 6, solamente hay tipos 1 a 4.

Imagen de ingscjoshua

okas

Pues segun ORACLE es la ultima version de su JAR De JDBC

Es la version del driver para Oracle 11.

Es un driver tipo 4 y soporta JDBC 4.0. Este driver de Oracle incluye un DataSource (oracle.jdbc.pool.OracleDataSource).