Spring全局事务在获取元素后提交

发布于 2024-11-17 09:32:48 字数 5885 浏览 4 评论 0 原文

我正在使用 Spring 和 Hibernate 以及 Jta Transactions,我有 2 个数据库,并且在事务方法中遇到问题。

在这个方法中,我插入了很多对象,但抛出了一个异常来回滚插入,这里的代码按我的预期工作,因为对象没有出现在数据库中。

但是,如果我在获取同一个表的对象的方法中添加一行,则这些对象将被提交到数据库中。

我认为当我进行 SELECT 时,对象会自动提交,因为异常会再次抛出,并且对象会保留到数据库中。

我的 xml 和代码:

dao.xml

<bean
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:configuracion_dao.properties" />
</bean>

<bean name="productosDAO" class="practica1.hibernate.HibernateProductosDAOImpl"
    parent="abstractPracticaBean">
    <property name="sessionFactory" ref="hibernateSessionFactory" />
</bean>

<bean name="tercerosDAO" class="${tercerosDAO.classname}" parent="abstractPracticaBean">
    <property name="dataSource" ref="dataSourceDatos" />
</bean>

<bean name="auditoriaDAO" class="practica1.hibernate.HibernateAuditoriaDAOImpl" parent="abstractPracticaBean">
    <property name="sessionFactory" ref="hibernateSessionFactory2" />
</bean>


<bean id="hibernateSessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSourceDatos" />
    <property name="mappingResources">
        <list>
            <value>hibernate-mappings.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.HSQLDialect
  </value>
    </property>
</bean>

<bean id="hibernateSessionFactory2"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSourceAuditoria" />
    <property name="mappingResources">
        <list>
            <value>hibernate-mappings-auditoria.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.HSQLDialect
  </value>
    </property>
</bean>


<bean name="dataSourceDatos" class="org.enhydra.jdbc.standard.StandardXADataSource">
    <property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
    <property name="url" value="jdbc:derby:/tmp/datos.db;create=true" />
    <property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>

<jdbc:initialize-database data-source="dataSourceDatos"
    ignore-failures="ALL">
    <jdbc:script location="classpath:practica1/sql/creacion_derby.sql" />
    <jdbc:script location="classpath:practica1/sql/datos.sql" />
</jdbc:initialize-database>

<bean name="dataSourceAuditoria" class="org.enhydra.jdbc.standard.StandardXADataSource">
    <property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
    <property name="url" value="jdbc:derby:/tmp/auditoria.db;create=true" />
    <property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>

<jdbc:initialize-database data-source="dataSourceAuditoria"
    ignore-failures="ALL">
    <jdbc:script location="classpath:practica1/sql/creacion_auditoria_derby.sql" />
</jdbc:initialize-database>

<bean id="txManager"
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" value="#{jotm.transactionManager}" />
    <property name="userTransaction" value="#{jotm.userTransaction}" />
</bean>

<bean id="jotm" class="org.objectweb.jotm.Jotm" destroy-method="stop">
    <constructor-arg value="true" />
    <constructor-arg value="false" />
</bean>

<tx:annotation-driven transaction-manager="txManager" />

bo.xml

<bean name="tercerosBO" class="practica1.impl.TercerosBOImpl"
    parent="abstractPracticaBean" autowire="constructor">

</bean>
<bean name="productosBO" class="practica1.impl.ProductosBOImpl"
    parent="abstractPracticaBean">
    <property name="productosDAO" ref="productosDAO" />
    <property name="auditoriaDAO" ref="auditoriaDAO" />
</bean>

aplicacion.xml

<bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames" value="mensajes" />
</bean>

<bean id="abstractPracticaBean" class="practica1.impl.AbstractPracticaBean" abstract="true">
    <property name="messageSource" ref="messageSource"></property>
</bean>

<import resource="bo.xml" />
<import resource="dao.xml" />

事务方法:

@Transactional
@Override
public void actualizaPrecio(double porcentaje) {
    internalActualizaPrecio(porcentaje);
}
private void internalActualizaPrecio(double porcentaje) {
    auditoriaDAO.insertAuditoria(getMessageSource().getMessage(
            "mensaje.actualizar_productos", new Object[] { porcentaje },
            null));
    int i = 0;
    auditoriaDAO.getAuditorias(); // Without this line its works like I expected
    List<Producto> productos = productosDAO.getProductos();
    for (Producto producto : productos) {
        i++;
        if (i > 3)
            throw new UnsupportedOperationException(
                    "Error para que veamos las transacciones");
        producto.setPrecio(producto.getPrecio().multiply(
                new BigDecimal(porcentaje).divide(new BigDecimal(100))));
        productosDAO.updateProducto(producto);
    }
}

我意识到,如果我使用auditeriaDAO.getAuditorias(),回滚只会影响Producto,但如果我使用productoDAO.getProductos(),回滚只会影响Auditoria。 ..

I am using Spring and Hibernate with Jta Transactions, I have 2 databases, and I have a problem in a transactional method.

In this method I insert a lot of objects but I throws an exception to rollback the insertions, here the code works as I expected because the objects dont appear into the database.

But if I add a line in the method that get the objects of the same table, the objects are committed into the database.

I think that when I make a SELECT the objects are auto-committed, because the exception its thrown again and the objects persists into the database.

My xml and code:

dao.xml

<bean
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:configuracion_dao.properties" />
</bean>

<bean name="productosDAO" class="practica1.hibernate.HibernateProductosDAOImpl"
    parent="abstractPracticaBean">
    <property name="sessionFactory" ref="hibernateSessionFactory" />
</bean>

<bean name="tercerosDAO" class="${tercerosDAO.classname}" parent="abstractPracticaBean">
    <property name="dataSource" ref="dataSourceDatos" />
</bean>

<bean name="auditoriaDAO" class="practica1.hibernate.HibernateAuditoriaDAOImpl" parent="abstractPracticaBean">
    <property name="sessionFactory" ref="hibernateSessionFactory2" />
</bean>


<bean id="hibernateSessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSourceDatos" />
    <property name="mappingResources">
        <list>
            <value>hibernate-mappings.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.HSQLDialect
  </value>
    </property>
</bean>

<bean id="hibernateSessionFactory2"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSourceAuditoria" />
    <property name="mappingResources">
        <list>
            <value>hibernate-mappings-auditoria.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.HSQLDialect
  </value>
    </property>
</bean>


<bean name="dataSourceDatos" class="org.enhydra.jdbc.standard.StandardXADataSource">
    <property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
    <property name="url" value="jdbc:derby:/tmp/datos.db;create=true" />
    <property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>

<jdbc:initialize-database data-source="dataSourceDatos"
    ignore-failures="ALL">
    <jdbc:script location="classpath:practica1/sql/creacion_derby.sql" />
    <jdbc:script location="classpath:practica1/sql/datos.sql" />
</jdbc:initialize-database>

<bean name="dataSourceAuditoria" class="org.enhydra.jdbc.standard.StandardXADataSource">
    <property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
    <property name="url" value="jdbc:derby:/tmp/auditoria.db;create=true" />
    <property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>

<jdbc:initialize-database data-source="dataSourceAuditoria"
    ignore-failures="ALL">
    <jdbc:script location="classpath:practica1/sql/creacion_auditoria_derby.sql" />
</jdbc:initialize-database>

<bean id="txManager"
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" value="#{jotm.transactionManager}" />
    <property name="userTransaction" value="#{jotm.userTransaction}" />
</bean>

<bean id="jotm" class="org.objectweb.jotm.Jotm" destroy-method="stop">
    <constructor-arg value="true" />
    <constructor-arg value="false" />
</bean>

<tx:annotation-driven transaction-manager="txManager" />

bo.xml

<bean name="tercerosBO" class="practica1.impl.TercerosBOImpl"
    parent="abstractPracticaBean" autowire="constructor">

</bean>
<bean name="productosBO" class="practica1.impl.ProductosBOImpl"
    parent="abstractPracticaBean">
    <property name="productosDAO" ref="productosDAO" />
    <property name="auditoriaDAO" ref="auditoriaDAO" />
</bean>

aplicacion.xml

<bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames" value="mensajes" />
</bean>

<bean id="abstractPracticaBean" class="practica1.impl.AbstractPracticaBean" abstract="true">
    <property name="messageSource" ref="messageSource"></property>
</bean>

<import resource="bo.xml" />
<import resource="dao.xml" />

Transactional method:

@Transactional
@Override
public void actualizaPrecio(double porcentaje) {
    internalActualizaPrecio(porcentaje);
}
private void internalActualizaPrecio(double porcentaje) {
    auditoriaDAO.insertAuditoria(getMessageSource().getMessage(
            "mensaje.actualizar_productos", new Object[] { porcentaje },
            null));
    int i = 0;
    auditoriaDAO.getAuditorias(); // Without this line its works like I expected
    List<Producto> productos = productosDAO.getProductos();
    for (Producto producto : productos) {
        i++;
        if (i > 3)
            throw new UnsupportedOperationException(
                    "Error para que veamos las transacciones");
        producto.setPrecio(producto.getPrecio().multiply(
                new BigDecimal(porcentaje).divide(new BigDecimal(100))));
        productosDAO.updateProducto(producto);
    }
}

I realised that if I use auditoriaDAO.getAuditorias() the rollback only affects to Producto but if I use productoDAO.getProductos() the rollback only affects to Auditoria...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无可置疑 2024-11-24 09:32:48

您可能会在这里混淆 flushcommit:SELECT 语句通常会刷新所有先前的 SQL 语句,以便获取最新数据(关于您之前所做的更改)德克萨斯州制造)。有可能在这样的 SELECT 语句完成之前(如果我没记错的话,下面的 DAO 调用是对 2nd sessionFactory 进行的),异常退出该方法时没有 flush< /em>.因此数据库中没有任何修改。

所以问题是:你确定你正在有效地回滚交易吗?我看到您注释了一个 private 方法:Spring AOP 基于代理的机制无法处理该方法!由于这种基于代理的机制,您必须注释 public 方法并从注释方法的类外部调用它。请参阅 文档

另一个线索:你有 2 个 sessionFactories,所以我假设你正在使用 XA 事务/数据源:你确定这部分的配置没问题吗?

You may be mixing up flush and commit here: a SELECT statement usually flushes all previous SQL statements, in order to fetch up-to-date data (regarding the previous changes you made in the tx). It may be possible that before such a SELECT statement is done (the following DAO calls are made to the 2nd sessionFactory if I'm not mistaken), the exception exits the method without a flush. Hence no modification in database.

So the question is: are you sure you're rollbacking the tx effectively? I see you've annotated a private method: the proxy-based mechanism of Spring AOP don't handle that! You must annotate a public method and call it from outside the annotated method's class, due to this very proxy-based mechanism. See the "Method visibility and @Transactional" block in the documentation.

Another lead: you have 2 sessionFactories, so I assume you're using XA transactions/datasources: are you sure this part of the conf is OK?

忆梦 2024-11-24 09:32:48

请检查auditoriaDAOproductosDAO搜索其他事务注释。我认为在某处创建了一个新事务,并且 UnsupportedException 仅回滚最后一个事务,并且提交了父事务。希望我有帮助!

我找到了两个例子。请检查一下。

JOTM 交易spring 和 hibernate

使用 Spring 3、Hibernate 3 和 Atomikos 访问多个数据库

Please check auditoriaDAO and productosDAO and search for other transactional annotation. I think a new transaction is created somewhere and the UnsupportedException rollbacks only the last transaction, and the parent transaction is committed. Hope I helped!

I have found two example. Please check it.

JOTM transactions in spring and hibernate

Access Multiple Database Using Spring 3, Hibernate 3 and Atomikos

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文