【问题标题】:Why nothing happens when I persist?为什么当我坚持的时候什么都没有发生?
【发布时间】:2012-01-12 10:05:54
【问题描述】:

我希望我没有问你已经回答的问题,但我无法理解我的问题......我解释一下:

我使用 Spring 和 Hibernate,我有一个 Manager 接口和一个实现我的接口的 Manager。经理是这样的:

@Service
@Transactional
public class ManagerImpl implements Manager {
    @PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName="Service")
    private EntityManager em;

    public void storeHistoricMessage(...params...) throws DBException{
        HistoricMessage historicMessage = new HistoricMessage(); 
        // ... initialization of historicMessage
        try {
            em.persist(historicMessage);
        }
        catch (Exception e){
            // process the exception if exists... 
        }
    }
}

我这样称呼我的服务:

@Service
public class OtherManager {
    @Autowired
    private Manager manager;

    public void storeHistoricMessage(...params...) {
        manager.storeHistoricMessage(...params...);
    }
}

我的应用程序上下文是这样定义的:

<?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:aop="http://www.springframework.org/schema/aop"
    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-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <context:component-scan base-package="package" />

    <bean id="JDBCPropertyConfigurer_service"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="properties" ref="JDBCProperties_service" />
        <property name="ignoreUnresolvablePlaceholders" value="true" />
    </bean>

    <bean id="JDBCProperties_service"
        class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="location" value="classpath:jdbc.properties" />
    </bean>

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

    <bean id="transactionManager_service" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory_service" />
    </bean>

    <!-- datasource -->
    <bean id="dataSource_service"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${database_service.driverClassName}" />
        <property name="url" value="${database_service.url}" />
        <property name="username" value="${database_service.username}" />
        <property name="password" value="${database_service.password}" />
    </bean>

    <!-- JPA config -->
    <bean id="entityManagerFactory_service"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource_service" />
        <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
        <property name="persistenceUnitName" value="Service" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--
                    <property name="generateDdl" value="${jpa.generateDdl}" />
                    <property name="showSql" value="${jpa.showSql}" /> <property
                    name="hbm2ddl.auto" value="${jpa.hbm2ddl}" />
                -->
            </bean>
        </property>
    </bean>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>

最后,我的 persistence.xml 是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">

    <persistence-unit name="Service" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>package.HistoricMessage</class>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />
            <property name="hibernate.archive.autodetection" value="class, hbm" />
            <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.format_sql" value="false" />
            <property name="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}" />
        </properties>
    </persistence-unit> 
</persistence>

问题是当我坚持时,什么也没有发生:没有插入数据库,没有错误消息,没有异常...... 我做了很多测试,也许我有一些帮助:

  • 如果我尝试使用 em.find() 取回我的对象​​,我得到它...缓存优化?
  • 如果我捕获它,并在启动服务后重命名数据库中的表,我没有错误,他总是很高兴......
  • 如果我尝试 em.flush(),它会抛出异常,因为没有正在进行的事务...

最后,这是我可以看到的 TRACE 日志:

DEBUG 12-01 10:50:01,362 (SessionImpl.java:<init>:220)  -opened session at timestamp: 13263618013
DEBUG 12-01 10:50:01,362 (JDBCTransaction.java:begin:54)  -begin
DEBUG 12-01 10:50:01,362 (ConnectionManager.java:openConnection:421)  -opening JDBC connection
DEBUG 12-01 10:50:01,363 (DriverManagerDataSource.java:getConnectionFromDriver:163)  -Creating new JDBC DriverManager Connection to [jdbc:mysql://databaseurl]
DEBUG 12-01 10:50:01,378 (JDBCTransaction.java:begin:59)  -current autocommit status: true
DEBUG 12-01 10:50:01,379 (JDBCTransaction.java:begin:62)  -disabling autocommit
TRACE 12-01 10:50:01,380 (JDBCContext.java:afterTransactionBegin:214)  -after transaction begin
DEBUG 12-01 10:50:01,380 (JpaTransactionManager.java:doBegin:348)  -Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: com.mysql.jdbc.JDBC4Connection@1ff335bb]
TRACE 12-01 10:50:01,381 (TransactionSynchronizationManager.java:bindResource:186)  -Bound value [org.springframework.jdbc.datasource.ConnectionHolder@184c9860] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@65499154] to thread [http-8001-Processor5]
TRACE 12-01 10:50:01,381 (TransactionSynchronizationManager.java:bindResource:186)  -Bound value [org.springframework.orm.jpa.EntityManagerHolder@4ca7d316] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@28ce2c57] to thread [http-8001-Processor5]
TRACE 12-01 10:50:01,381 (TransactionSynchronizationManager.java:initSynchronization:261)  -Initializing transaction synchronization
TRACE 12-01 10:50:01,382 (TransactionAspectSupport.java:prepareTransactionInfo:290)  -Getting transaction for [package.storeHistoricMessage]
storeHistoricMessage (begin of my function)
DEBUG 12-01 10:50:01,382 (EntityManagerFactoryUtils.java:doGetTransactionalEntityManager:194)  -Opening JPA EntityManager
DEBUG 12-01 10:50:01,388 (EntityManagerFactoryUtils.java:doGetTransactionalEntityManager:199)  -Registering transaction synchronization for JPA EntityManager
DEBUG 12-01 10:50:01,389 (SessionImpl.java:<init>:220)  -opened session at timestamp: 13263618013
TRACE 12-01 10:50:01,392 (TransactionSynchronizationManager.java:bindResource:186)  -Bound value [org.springframework.orm.jpa.EntityManagerHolder@69851576] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@20442c19] to thread [http-8001-Processor5]
TRACE 12-01 10:50:01,393 (IdentifierValue.java:isUnsaved:77)  -id unsaved-value strategy UNDEFINED
TRACE 12-01 10:50:01,394 (AbstractSaveEventListener.java:getEntityState:514)  -transient instance of: package.HistoricMessage
TRACE 12-01 10:50:01,394 (DefaultPersistEventListener.java:entityIsTransient:124)  -saving transient instance
DEBUG 12-01 10:50:01,397 (AbstractSaveEventListener.java:saveWithGeneratedId:112)  -generated identifier: ***identifier***, using strategy: org.hibernate.id.Assigned
TRACE 12-01 10:50:01,397 (AbstractSaveEventListener.java:performSave:153)  -saving [package.HistoricMessage#***identifier***]
end of my function
TRACE 12-01 10:50:01,399 (TransactionAspectSupport.java:commitTransactionAfterReturning:319)  -Completing transaction for [package.storeHistoricMessage]
TRACE 12-01 10:50:01,400 (AbstractPlatformTransactionManager.java:triggerBeforeCommit:903)  -Triggering beforeCommit synchronization
TRACE 12-01 10:50:01,400 (AbstractPlatformTransactionManager.java:triggerBeforeCompletion:916)  -Triggering beforeCompletion synchronization
TRACE 12-01 10:50:01,401 (TransactionSynchronizationManager.java:doUnbindResource:232)  -Removed value [org.springframework.orm.jpa.EntityManagerHolder@69851576] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@20442c19] from thread [http-8001-Processor5]
DEBUG 12-01 10:50:01,401 (EntityManagerFactoryUtils.java:closeEntityManager:313)  -Closing JPA EntityManager
TRACE 12-01 10:50:01,401 (SessionImpl.java:close:273)  -closing session
TRACE 12-01 10:50:01,402 (ConnectionManager.java:cleanup:375)  -connection already null in cleanup : no action
DEBUG 12-01 10:50:01,402 (AbstractPlatformTransactionManager.java:processCommit:730)  -Initiating transaction commit
DEBUG 12-01 10:50:01,402 (JpaTransactionManager.java:doCommit:451)  -Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@27b71c12]
DEBUG 12-01 10:50:01,403 (JDBCTransaction.java:commit:103)  -commit
TRACE 12-01 10:50:01,403 (SessionImpl.java:managedFlush:337)  -automatically flushing session
TRACE 12-01 10:50:01,403 (JDBCContext.java:beforeTransactionCompletion:205)  -before transaction completion
TRACE 12-01 10:50:01,404 (SessionImpl.java:beforeTransactionCompletion:393)  -before transaction completion
DEBUG 12-01 10:50:01,405 (JDBCTransaction.java:toggleAutoCommit:193)  -re-enabling autocommit
DEBUG 12-01 10:50:01,406 (JDBCTransaction.java:commit:116)  -committed JDBC Connection
TRACE 12-01 10:50:01,407 (JDBCContext.java:afterTransactionCompletion:219)  -after transaction completion
DEBUG 12-01 10:50:01,407 (ConnectionManager.java:aggressiveRelease:404)  -aggressively releasing JDBC connection
DEBUG 12-01 10:50:01,408 (ConnectionManager.java:closeConnection:441)  -releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
TRACE 12-01 10:50:01,408 (SessionImpl.java:afterTransactionCompletion:422)  -after transaction completion
TRACE 12-01 10:50:01,409 (AbstractPlatformTransactionManager.java:triggerAfterCommit:929)  -Triggering afterCommit synchronization
TRACE 12-01 10:50:01,409 (AbstractPlatformTransactionManager.java:triggerAfterCompletion:945)  -Triggering afterCompletion synchronization
TRACE 12-01 10:50:01,410 (TransactionSynchronizationManager.java:clearSynchronization:315)  -Clearing transaction synchronization
TRACE 12-01 10:50:01,410 (TransactionSynchronizationManager.java:doUnbindResource:232)  -Removed value [org.springframework.orm.jpa.EntityManagerHolder@4ca7d316] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@28ce2c57] from thread [http-8001-Processor5]
TRACE 12-01 10:50:01,410 (TransactionSynchronizationManager.java:doUnbindResource:232)  -Removed value [org.springframework.jdbc.datasource.ConnectionHolder@184c9860] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@65499154] from thread [http-8001-Processor5]
DEBUG 12-01 10:50:01,411 (JpaTransactionManager.java:doCleanupAfterCompletion:534)  -Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@27b71c12] after transaction
DEBUG 12-01 10:50:01,411 (EntityManagerFactoryUtils.java:closeEntityManager:313)  -Closing JPA EntityManager
TRACE 12-01 10:50:01,411 (SessionImpl.java:close:273)  -closing session
TRACE 12-01 10:50:01,412 (ConnectionManager.java:cleanup:375)  -connection already null in cleanup : no action

非常感谢您的帮助!

编辑: 非常抱歉,我明白发生了什么,但您找不到,因为我确实简化了项目的架构,但我没有告诉您原因: 在这个项目中,我有几个应用程序上下文文件和几个数据源,所以我使用了好几次......而在 Spring 2.5 中,你只能有一个! 所以我不能在我的第二个服务中使用交易...... 为了解决这个问题,我使用了这样的 aop:

<tx:advice id="txAdviceSelfCare" transaction-manager="transactionManager_service">
    <!-- the transactional semantics... -->
    <tx:attributes>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="*" />
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="ServiceManagerOperations"
        expression="execution(* package.ServiceManager.*(..))" />
    <aop:advisor advice-ref="txAdviceService"
        pointcut-ref="ServiceManagerOperations" />
</aop:config>

<!-- a PlatformTransactionManager is still required -->
<bean id="transactionManager_service" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory_service" />
</bean>

感谢大家的帮助!

【问题讨论】:

  • 你真的压制了持久操作期间抛出的任何异常吗?

标签: java hibernate spring jpa persist


【解决方案1】:

你能试着检查一下你的数据库到底发生了什么吗? 尝试激活该数据库上的日志设施,如果您安装了这样的工具来嗅探 Java 代码和数据库服务器之间的网络流量......它可能很有用...... 您可以要求您的 JPA 层显示生成的 SQL,它可以为您提供有趣的数据... 我的 2 件 杰罗姆

【讨论】:

  • 很抱歉,我没有安装任何工具,也无法自己安装。我已经启用了 show sql,但它没有任何改变。
【解决方案2】:

更改你的 catch 块来做一些事情并观察它打印的内容。

    try {
        em.persist(historicMessage);
    }
    catch (Exception e){
        e.printStackTrace(); // use a logger if available
    }

您还可以将以下属性更改为true 以查看发生了什么。

<property name="hibernate.show_sql" value="true" />

另外,养成使用合适的日志框架(例如SLF4J)跟踪方法进入/退出的习惯。

【讨论】:

  • 我试图这样做,但它什么也没捕获(显然什么也不打印)我已经启用了 show sql,但它什么也没改变,没有请求出现!
  • 在这种情况下,我猜交易由于某种原因没有开始。使其成为非事务性的,看看它是否仍然无法排除这种猜测。如果它有效,我们还有其他问题。
  • 这个 try-catch 块没有意义。数据保留在方法的末尾而不是 em.persist。尝试在 em.persist 之后添加 em.flush()
  • 好的,我知道我的 try catch 没用,我要删除它,谢谢你的回报。正如我在帖子中解释的那样,我尝试刷新,但由于“没有正在进行的事务”而引发异常
【解决方案3】:

请注意,实际插入不会发生在 em.persist 语句中,因为调用是事务性的,因此您的 try/catch 根本不会做太多事情。实际持久化在事务结束时完成,即服务层调用完成时(从您的方法返回后)。在调试持久性时,这些知识至关重要。

【讨论】:

    【解决方案4】:

    验证您正在查看详细信息的数据库。日志清楚地表明提交已完成..

    DEBUG 12-01 10:50:01,403 (JDBCTransaction.java:commit:103) -commit TRACE 12-01 10:50:01,403 (SessionImpl.java:managedFlush:337) -automatically flushing session TRACE 12-01 10:50:01,403 (JDBCContext.java:beforeTransactionCompletion:205) -before transaction completion TRACE 12-01 10:50:01,404 (SessionImpl.java:beforeTransactionCompletion:393) -before transaction completion DEBUG 12-01 10:50:01,405 (JDBCTransaction.java:toggleAutoCommit:193) -re-enabling autocommit DEBUG 12-01 10:50:01,406 (JDBCTransaction.java:commit:116) -committed JDBC Connection

    【讨论】:

      【解决方案5】:

      将您的方法调用放在 try catch 中

      public void storeHistoricMessage(...params...) {
          try {
             manager.storeHistoricMessage(...params...);
          } catch (Exception e) {
             e.printStackTrace(); // use a logger if available
          }
      }
      

      数据应该在 manager.storeHistoricMessage 方法调用结束时(通过事务管理代理)而不是在 em.persist 调用中持久化。你也可以试试 em.flush:

      try {
              em.persist(historicMessage);
              em.flush(); //force DB insert
          }...
      

      您似乎没有看到可能由事务管理器抛出的异常。

      【讨论】:

      • 我更正了我的代码以捕获异常,但它什么也没改变。接下来我添加了刷新,并捕获了以下异常:javax.persistence.TransactionRequiredException: no transaction is in progress at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:301)
      • 这是东西。尝试为该方法添加 @Transactional(propagation=Propagation.REQUIRES_NEW) 。如果事务管理器或代理有问题,您应该得到更详细的异常。
      • 我尝试做了一个差异来与之前的异常进行比较:它非常相似..
      • 您是否已将 Transational 从类的顶部删除?将 Transactional 保留在方法级别。您的事务配置看起来不错。持久性在其他任何地方都有效吗?
      • 是的,我有,但没有任何改变。不,我只有一种方法可以插入到这个数据库中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 2017-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多