当前位置: 首页 > 知识库问答 >
问题:

EJB事务回滚导致不必要的数据库更改/对象持久性

雍俊远
2023-03-14

如果发生错误,我在回滚EJB事务时遇到了问题。以下情况:我有一个无状态的EJB,它试图在一个新事务中持久化3个对象。我使用HiberNate 5.2作为JPA提供者,使用Payara4.1.2.173作为应用程序服务器。

@Stateless
public class MyEJB {

    @PersistenceContext(unitName = "myUnit")
    private EntityManager entityManager;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void persistData() {
        this.log.info("Method start.");
        // valid
        MyObj obj1 = new MyObj();
        obj1.setField1("v1");
        obj1.setField2("v2");
        entityManager.persist(obj1);
        this.log.info("Persisted obj1");

        // valid
        MyObj obj2 = new MyObj();
        obj2.setField1("v1");
        obj2.setField2("v2");
        entityManager.persist(obj2);
        this.log.info("Persisted obj2");

        // failure
        MyObj obj3 = new MyObj();
        obj3.setField1("v1");
        obj3.setField2("FAILURE");
        entityManager.persist(obj3);
        this.log.info("Persisted obj3");

        this.log.info("Method finished.");
    }
}

由于field2上的无效值,obj3的持久性应该会失败。当从我的ejb外部调用这个方法时(例如,从另一个EJB,一个消息驱动bean,通过rest,...)执行hibernate insert语句时,日志文件中出现< code > persistence exception 。所以obj3不会持久存储在数据库中。日志文件还说“事务标记为回滚”。但是当我查看数据库时,obj1和obj2是持久的。因此,我认为回滚没有完成或不完整。我还尝试使用< code>@Transactional注释,但是行为没有变化。我也不能使用try-catch,因为在对象创建和< code>persist(obj)调用时不会出现异常。在< code>persistence.xml中,我将属性< code > hibernate . connection . auto commit 设置为< code>false。

我的persistence.xml是:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="myUnit" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jta-data-source>jdbc/name</jta-data-source>

        <properties>
            <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
            <property name = "hibernate.show_sql" value = "false" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle12cDialect" />
            <property name="hibernate.connection.autocommit" value="false" />
        </properties>
    </persistence-unit>
</persistence>

数据库连接在 Payaras 域中的池定义中完成.xml:

<resources>

    <jdbc-resource pool-name="pool-name" jndi-name="jdbc/name"></jdbc-resource>

    <jdbc-connection-pool match-connections="true" connection-leak-reclaim="true" driver-classname="" statement-leak-reclaim="true" 
                          connection-creation-retry-attempts="3" associate-with-thread="true" validation-table-name="DUAL" 
                          description="" validation-classname="" res-type="javax.sql.XADataSource" max-wait-time-in-millis="120000" 
                          fail-all-connections="true" allow-non-component-callers="true" datasource-classname="oracle.jdbc.xa.client.OracleXADataSource" 
                          is-connection-validation-required="true" transaction-isolation-level="read-committed" validate-atmost-once-period-in-seconds="30" 
                          lazy-connection-enlistment="true" connection-creation-retry-interval-in-seconds="7" max-pool-size="45" 
                          connection-leak-timeout-in-seconds="1800" statement-leak-timeout-in-seconds="900" steady-pool-size="10" 
                          name="pool-name" statement-timeout-in-seconds="900" sql-trace-listeners="" init-sql="">
      <property name="Password" value="password"></property>
      <property name="User" value="user"></property>
      <property name="URL" value="jdbc:oracle:thin:@//localhost:1521/db-identifier"></property>
    </jdbc-connection-pool>
</resources>

我失败的堆栈跟踪显示在下面的段落中。正如您所看到的,创建了3个插入语句。持久数据()代码完成后,HiberNate尝试执行这些语句,并在目标3插入时发生失败并启动回滚。但是目标1和目标2随后被持久化在数据库中。为了更好地理解,我添加了一些日志语句。

[2018-09-02T17:41:51.111+0200] [Payara 4.1] [INFO] [] [...] [tid: _ThreadID=28 _ThreadName=http-thread-pool::http-listener-1(2)] [timeMillis: 1535903502294] [levelValue: 800] [[
  Method start.]]

[2018-09-02T17:41:51.222+0200] [Payara 4.1] [INFO] [] [...] [tid: _ThreadID=28 _ThreadName=http-thread-pool::http-listener-1(2)] [timeMillis: 1535903502430] [levelValue: 800] [[
  Persisted obj1]]

[2018-09-02T17:41:51.333+0200] [Payara 4.1] [INFO] [] [...] [tid: _ThreadID=28 _ThreadName=http-thread-pool::http-listener-1(2)] [timeMillis: 1535903502431] [levelValue: 800] [[
  Persisted obj2]]

[2018-09-02T17:41:51.444+0200] [Payara 4.1] [INFO] [] [...] [tid: _ThreadID=28 _ThreadName=http-thread-pool::http-listener-1(2)] [timeMillis: 1535903502432] [levelValue: 800] [[
  Persisted obj3]]

[2018-09-02T17:41:51.555+0200] [Payara 4.1] [INFO] [] [...] [tid: _ThreadID=28 _ThreadName=http-thread-pool::http-listener-1(2)] [timeMillis: 1535903502432] [levelValue: 800] [[
  Method finished.]]

[2018-09-02T17:41:51.789+0200] [Payara 4.1] [INFO] [] [] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911789] [levelValue: 800] [[
  Hibernate: insert into ... // obj1

[2018-09-02T17:41:51.929+0200] [Payara 4.1] [INFO] [] [] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911929] [levelValue: 800] [[
  Hibernate: insert into ... // obj2

[2018-09-02T17:41:51.931+0200] [Payara 4.1] [INFO] [] [] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911931] [levelValue: 800] [[
  Hibernate: insert into ... // obj3

[2018-09-02T17:41:51.939+0200] [Payara 4.1] [WARN] [] [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911939] [levelValue: 900] [[
  SQL Error: 12899, SQLState: 72000]]

[2018-09-02T17:41:51.939+0200] [Payara 4.1] [ERROR] [] [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911939] [levelValue: 1000] [[
  ORA-12899: Wert zu groß für Spalte "FIELD2" (aktuell: 7, maximal: 1)
]]

[2018-09-02T17:41:51.941+0200] [Payara 4.1] [INFO] [] [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911941] [levelValue: 800] [[
  HHH000010: On release of batch it still contained JDBC statements]]

[2018-09-02T17:41:51.946+0200] [Payara 4.1] [ERROR] [] [org.hibernate.internal.ExceptionMapperStandardImpl] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911946] [levelValue: 1000] [[
  HHH000346: Error during managed flush [org.hibernate.exception.GenericJDBCException: could not execute statement]]]

[2018-09-02T17:41:51.946+0200] [Payara 4.1] [WARNING] [] [javax.enterprise.resource.jta.com.sun.enterprise.transaction] [tid: _ThreadID=27 _ThreadName=http-thread-pool::http-listener-1(1)] [timeMillis: 1535902911946] [levelValue: 900] [[
  DTX5014: Caught exception in beforeCompletion() callback:
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:147)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1434)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:484)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3190)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2404)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
    at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:320)
    at org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47)
    at org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)
    at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:452)
    at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:879)
    at com.sun.ejb.containers.EJBContainerTransactionManager.completeNewTx(EJBContainerTransactionManager.java:721)
    at com.sun.ejb.containers.EJBContainerTransactionManager.postInvokeTx(EJBContainerTransactionManager.java:505)
    at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4536)
    at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2023)
    at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1994)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:220)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:90)
    at com.sun.proxy.$Proxy406.testImport(Unknown Source)
    at ...
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1606)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:258)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:654)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:593)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:480)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:180)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207)
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3001)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3501)
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:89)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:586)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:460)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1428)
    ... 72 more
Caused by: java.sql.SQLException: ORA-12899: Wert zu groß für Spalte "FIELD2" (aktuell: 7, maximal: 1)

    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399)
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1059)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:522)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:257)
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:587)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:225)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:53)
    at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:943)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1150)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:4798)
    at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:4875)
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1361)
    at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:125)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
    ... 81 more
]]

有人能解释一下为什么有效的插入语句被执行而不是回滚吗?我能做些什么来实现完全回滚?我想要的行为是在我的事务中将所有条目插入数据库,或者根本没有条目(以防任何错误)。

共有1个答案

晋骏喆
2023-03-14

最后我解决了我的问题。问题是在我使用的Payara服务器配置中没有注册jdbc-资源。将其添加到domain.xml中的服务器配置后,一切都按预期工作。

<resources>
    <jdbc-resource pool-name="pool-name" jndi-name="jdbc/name"></jdbc-resource>
    <jdbc-connection-pool ...> </jdbc-connection-pool>
</resources>
...
<servers>
  <server config-ref="server-config" name="server">
    ...
    <resource-ref ref="jdbc/name"></resource-ref>
  </server>
</servers>
 类似资料:
  • Spring 4.1.4 Hibernate 4.2.0 JDK 1.8 我的上下文:我有一个控制器调用-->Service-->调用Dao业务功能是删除(在1到许多DB关系中)一些子级,但不是所有子级。然后,在删除了一些子项之后,我尝试删除父项,然后我得到了java.sql.SqlIntegrityConstraintViolationException

  • 情景故事时间: 我“继承”了一个程序,一个用于访问数据库的相当简单的webservice。该程序在某个地方有一个缺陷:它试图更新一个没有更新授权的表。该程序只具有更新数据库队列的权限(Oracle),以保存谁访问了什么信息。这是不受欢迎的行为,现在我纠正了它。注意:这与这个问题本身无关,它只是导致我提出这个问题的原因。 该程序使用Spring+Hibernate来管理和访问数据和事务。 因为程序的

  • 我试图编写一个spring-cloud-stream函数(spring-starter-parent 2.5.3,java 11,spring-cloud-version 2020.0.3),该函数同时具有Kafka和Postgres事务。每当使用的消息以字符串“fail”开始时,该函数将引发一个模拟错误,我希望这将导致数据库事务回滚,然后导致kafka事务回滚。(我知道Kafka交易不是XA,这

  • public void A()抛出ApplicationException{ } 这是方法B(): } 显然,如果删除方法B()中的catch块,就不会出现这种行为。现在,我想知道是否有一种方法可以回滚我的事务,即使我捕捉到方法B()中的异常。谢谢!!!!

  • 问题内容: 我正在尝试更改持久对象的ID。我在Hibernate和MySQL中使用JPA。我执行代码时遇到的错误是:org.hibernate.HibernateException:com.tutorial.jpa.certification.listing5_18.AA实例的标识符从2更改为99 我找不到此问题的答案,因此在此感谢您的帮助。代码为: 问题答案: 您永远不要修改实体的主键 -这定义

  • 我正在与用propagation.requires_new注释的方法的奇怪行为作斗争。 以下是TransactionManager的日志: