Atomikos:使用PostgreSQL时无法保存数据

信息01

使用Atomikos时遇到一个奇怪的问题

我有一个小型测试应用程序(Spring + Hibernate)。它使用两个不同的数据源,我需要在非Java EE容器(本例中为Tomcat)上测试JTA功能。

当我将MySQL用作数据库时,所有内容都会毫无问题地保存下来。但是当我切换到PostgreSQL时,数据不会保存到数据库中。

有趣的是,如果我没有使用@Transactional并手动开始和提交事务,那么一切正常。但是,使用@Transactional-时,不会保存数据。我可以看到hibernate_sequence表确实在数据库中被更新了(数字增加了),而只有数据本身没有被更新。尽管我在Atomikos日志中看到数据已提交等事实,但所有这一切。同样,SAME代码在MySQL上也能正常工作。仅当使用PostgreSQL时才会发生此问题。

我已经在PostgreSQL版本9.4(Linux上为64位)和9.5(Windows 10上为64位)以及使用不同的PostgreSQL JDBC驱动程序版本(JDBC4和JDBC3)都对其进行了测试。

经过测试的Atomikos版本:4.0.4(截止到目前)和3.9.3
春季版本:4.0.9
休眠版本:3.6.10.Final

注意
我需要那些确切的Spring和Hibernate版本来模拟需要Atomikos集成到的工作应用程序。


配置和代码示例

这是我的spring.xml配置文件:

<?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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <tx:annotation-driven />
    <tx:jta-transaction-manager />

    <context:component-scan base-package="com.byteslounge.spring.tx.service.impl" />
    <context:component-scan base-package="com.byteslounge.spring.tx.servlet" />
    <context:component-scan base-package="com.byteslounge.spring.tx.entity" />

    <bean id="sessionFactory1" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="annotatedClasses">
            <list>
                <value>com.byteslounge.spring.tx.entity.TableOne</value>
            </list>
        </property>
        <property name="dataSource" ref="dataSource1" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.connection.autocommit">false</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>

                <prop key="hibernate.current_session_context_class">jta</prop>
                <prop key="javax.persistence.transactionType">jta</prop>
                <prop key="hibernate.transaction.factory_class">com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory </prop>
                <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
        <property name="uniqueResourceName" value="DataSource1" />
        <property name="xaDataSource" ref="dataBase1" />
        <property name="maxPoolSize" value="20" />
        <property name="minPoolSize" value="10"/>
    </bean>
    <bean id="dataBase1" class="org.postgresql.xa.PGXADataSource" lazy-init="true">
        <property name="user" value="tester1" />
        <property name="password" value="123456" />
        <property name="serverName" value="localhost" />
        <property name="portNumber" value="5432" />
        <property name="databaseName" value="test_db1" />
        <property name="url" value="jdbc:postgresql://localhost:5432/test_db1" />
    </bean>


    <bean id="sessionFactory2" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="annotatedClasses">
            <list>
                <value>com.byteslounge.spring.tx.entity.TableTwo</value>
            </list>
        </property>
        <property name="dataSource" ref="dataSource2" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.connection.autocommit">false</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>

                <prop key="hibernate.current_session_context_class">jta</prop>
                <prop key="javax.persistence.transactionType">jta</prop>
                <prop key="hibernate.transaction.factory_class">com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory </prop>
                <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
        <property name="uniqueResourceName" value="DataSource2" />
        <property name="xaDataSource" ref="dataBase2" />
        <property name="maxPoolSize" value="20" />
        <property name="minPoolSize" value="10"/>
    </bean>
    <bean id="dataBase2" class="org.postgresql.xa.PGXADataSource" lazy-init="true">
        <property name="user" value="tester2" />
        <property name="password" value="123456" />
        <property name="serverName" value="localhost" />
        <property name="portNumber" value="5432" />
        <property name="databaseName" value="test_db2" />
        <property name="url" value="jdbc:postgresql://localhost:5432/test_db2" />
    </bean>

    <!-- Atomikos -->
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
        <property name="forceShutdown" value="false" />
    </bean>
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout" value="3000" />
    </bean>
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" depends-on="atomikosTransactionManager,atomikosUserTransaction">
        <property name="transactionManager" ref="atomikosTransactionManager" />
        <property name="userTransaction" ref="atomikosUserTransaction" />
        <property name="allowCustomIsolationLevels" value="true" />
    </bean>


    <!-- DAO -->
    <bean id="tableOneDao" class="com.byteslounge.spring.tx.dao.impl.TableOneDaoImpl">
        <property name="sessionFactory" ref="sessionFactory1" />
    </bean>
    <bean id="tableTwoDao" class="com.byteslounge.spring.tx.dao.impl.TableTwoDaoImpl">
        <property name="sessionFactory" ref="sessionFactory2" />
    </bean>

</beans>


这是一个代码示例,用于说明如何保存数据:

@Transactional(rollbackFor=Exception.class)
public void persist(TableOne tableOne, TableTwo tableTwo) throws Exception {
    tableOneDao.save(tableOne);
    tableTwoDao.save(tableTwo);
}

DAO类具有相同的保存逻辑:

@Service
public class TableOneDaoImpl extends HibernateDaoSupport implements TableOneDao  {

    @Override
    public void save(TableOne tableOne) throws Exception {
        Session session = null;
        try {
            session = getSessionFactory().openSession();

            session.save(tableOne);
        } catch (Exception e) {
            throw new Exception("Could not save tableOne!", e);
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

}


听听执行数据保存逻辑时得到的日志:

13:48:58.521 [http-bio-8080-exec-3] DEBUG com.atomikos.icatch.imp.CompositeTransactionManagerImp - createCompositeTransaction ( 10000 ): created new ROOT transaction with id 192.168.50.67.tm147946973850200001
13:48:58.605 [http-bio-8080-exec-3] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 14794697385
13:48:58.610 [http-bio-8080-exec-3] DEBUG com.atomikos.icatch.imp.CompositeTransactionImp - registerSynchronization ( com.atomikos.icatch.jta.Sync2Sync@57e48ad3 ) for transaction 192.168.50.67.tm147946973850200001
13:48:58.610 [http-bio-8080-exec-3] DEBUG org.hibernate.jdbc.JDBCContext - successfully registered Synchronization
13:48:58.612 [http-bio-8080-exec-3] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
13:48:58.612 [http-bio-8080-exec-3] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
13:48:58.612 [http-bio-8080-exec-3] DEBUG com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'DataSource1': getConnection()...
13:48:58.612 [http-bio-8080-exec-3] INFO  com.atomikos.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'DataSource1': init...
13:48:58.613 [http-bio-8080-exec-3] DEBUG org.hibernate.SQL - select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
13:48:58.616 [http-bio-8080-exec-3] DEBUG com.atomikos.icatch.imp.CompositeTransactionImp - addParticipant ( XAResourceTransaction: 3139322E3136382E35302E36372E746D313437393436393733383530323030303031:3139322E3136382E35302E36372E746D31 ) for transaction 192.168.50.67.tm147946973850200001
13:48:58.616 [http-bio-8080-exec-3] DEBUG com.atomikos.datasource.xa.XAResourceTransaction - XAResource.start ( 3139322E3136382E35302E36372E746D313437393436393733383530323030303031:3139322E3136382E35302E36372E746D31 , XAResource.TMNOFLAGS ) on resource DataSource1 represented by XAResource instance org.postgresql.xa.PGXAConnection@7b57a36a
13:48:58.617 [http-bio-8080-exec-3] DEBUG com.atomikos.icatch.imp.CompositeTransactionImp - registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@ede1e016 ) for transaction 192.168.50.67.tm147946973850200001
13:48:58.617 [http-bio-8080-exec-3] DEBUG com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for Pooled connection wrapping physical connection org.postgresql.jdbc3g.Jdbc3gConnection@2a39bdf5: calling prepareStatement(select nextval ('hibernate_sequence'))...
13:48:58.627 [http-bio-8080-exec-3] DEBUG org.hibernate.id.SequenceGenerator - Sequence identifier generated: BasicHolder[java.lang.Integer[43]]
13:48:58.627 [http-bio-8080-exec-3] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
13:48:58.627 [http-bio-8080-exec-3] DEBUG org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
13:48:58.627 [http-bio-8080-exec-3] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
13:48:58.627 [http-bio-8080-exec-3] DEBUG com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for Pooled connection wrapping physical connection org.postgresql.jdbc3g.Jdbc3gConnection@2a39bdf5: isClosed()...
13:48:58.627 [http-bio-8080-exec-3] DEBUG com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for Pooled connection wrapping physical connection org.postgresql.jdbc3g.Jdbc3gConnection@2a39bdf5: calling getWarnings...
13:48:58.627 [http-bio-8080-exec-3] DEBUG com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for Pooled connection wrapping physical connection org.postgresql.jdbc3g.Jdbc3gConnection@2a39bdf5: calling clearWarnings...
13:48:58.627 [http-bio-8080-exec-3] DEBUG com.atomikos.jdbc.AtomikosConnectionProxy - atomikos connection proxy for Pooled connection wrapping physical connection org.postgresql.jdbc3g.Jdbc3gConnection@2a39bdf5: close()...
13:48:58.627 [http-bio-8080-exec-3] DEBUG com.atomikos.datasource.xa.XAResourceTransaction - XAResource.end ( 3139322E3136382E35302E36372E746D313437393436393733383530323030303031:3139322E3136382E35302E36372E746D31 , XAResource.TMSUCCESS ) on resource DataSource1 represented by XAResource instance org.postgresql.xa.PGXAConnection@7b57a36a
13:48:58.628 [http-bio-8080-exec-3] DEBUG org.hibernate.event.def.AbstractSaveEventListener - generated identifier: 43, using strategy: org.hibernate.id.SequenceGenerator
13:48:58.638 [http-bio-8080-exec-3] DEBUG com.atomikos.icatch.jta.Sync2Sync - beforeCompletion() called on Synchronization: org.hibernate.transaction.synchronization.HibernateSynchronizationImpl@3aa81ddb
13:48:58.638 [http-bio-8080-exec-3] DEBUG com.atomikos.icatch.imp.CompositeTransactionImp - commit() done (by application) of transaction 192.168.50.67.tm147946973850200001
13:48:58.641 [http-bio-8080-exec-3] DEBUG com.atomikos.datasource.xa.XAResourceTransaction - XAResource.commit ( 3139322E3136382E35302E36372E746D313437393436393733383530323030303031:3139322E3136382E35302E36372E746D31 , true ) on resource DataSource1 represented by XAResource instance org.postgresql.xa.PGXAConnection@7b57a36a
13:48:58.643 [http-bio-8080-exec-3] DEBUG com.atomikos.icatch.jta.Sync2Sync - afterCompletion ( STATUS_COMMITTED ) called  on Synchronization: org.hibernate.transaction.synchronization.HibernateSynchronizationImpl@3aa81ddb


我还已将postgresql.conf中max_prepared_transactions参数设置为至少与在PostgreSQL的相关Atomikos文档页面上建议max_connections一样


再次强调一下,同样的代码在MySQL上也能正常工作仅当将此Web应用程序配置为使用PostgreSQL时,才会发生此奇怪的问题。

有人知道可能是个问题吗?

信息01

OK,谜团解决了!原来,我需要会话对象显式调用flush()

以下答案给了我一个提示:
Hibernate不能在数据库中保存对象吗?


这是一个工作示例(要注意session.flush(),必须被称为收盘前一个会话):

@Service
public class TableOneDaoImpl extends HibernateDaoSupport implements TableOneDao  {

    @Override
    public void save(TableOne tableOne) throws Exception {
        Session session = null;
        try {
            session = getSessionFactory().openSession();

            session.save(tableOne);
            session.flush();
        } catch (Exception e) {
            throw new Exception("Could not save tableOne!", e);
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

}


同样,使用MySQL时,无需显式刷新即可正常工作


有趣的观察

上面提到的测试Web应用程序使用了纯Hibernate配置和Hibernate的SessionFactory(即,没有persistence.xml和JPA entityManager)。但是我也将相同的测试应用程序配置为使用JPA而且在该应用程序中,即使不使用MySQL和PostgreSQL进行显式刷新,所有内容也可以正常工作。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

春天的数据无法读取PostgreSQL中使用UUID记录

为什么在使用SavedStateHandle之后我的数据仍然无法保存?

PostgreSQL 9.4数据库无法使用pgAdmin 3保存(Windows 8.1)

PostgreSQL-当涉及多个列时,无法使用PARTITION BY

使用PostgreSQL数据库时,uwsgi下的django应用无法启动

无法使用默认的PostgreSQL Docker映像创建数据库

无法在Android(Kotlin)上使用ObjectBox保存相同的数据

无法使用PHP将数据从javascript保存到MySql

使用python ffmpeg转换视频文件时无法保存元数据

数据验证无法保存

无法使用Laravel Api保存到数据库

我无法从数据框保存到Postgresql

使用Spring Batch时Spring Data JPA无法保存到数据库

无法使用余烬数据保存/更新记录

当引擎为InnoDB时无法保存数据,而当MyISAM时无法成功保存数据

使用表单时无法将多对多项目保存到数据库

无法使用休眠保存子表数据

Rails无法将数据保存在DB中(使用Angular)

我无法使用保存按钮django保存数据

数据未使用 Python 保存在 Postgresql 中

从postgresql读取数据时,无法在flink中获取Json数据

在 AEM Communities 中使用扩展的 Jouranl 组件时无法保存数据

无法使用 wix 工具集创建 postgresql 数据库

使用函数时无法正确保存 Matplotlib 图

当数据包含日语字符时,无法使用 org.postgresql.copy.CopyManager 插入数据库

将行数据从 csv 导入 postgresql 时无法使用字符串

使用 TypeORM 保存实体时无法确定实体错误

无法使用 Django 表单保存数据

js 在页面卸载时保存数据无法按预期工作