【问题标题】:Trying to load lazy relationships after EntityManager closesEntityManager 关闭后尝试加载惰性关系
【发布时间】:2012-08-01 10:30:36
【问题描述】:

我有三个spring+JPA项目...一个基础项目A,一个插件项目B和实际项目C。在C中,其他两个项目都导入为A.jar和B.jar。每个项目都有自己的 ApplicationContext.xml。叶项目,即 C 在自定义位置有它的 persistence.xml,如 proeject-A 中的 appcontext.xml 中所述(启动项目 A 在整个类路径中查找 appcontext.xml 和 persistence.xml,因此能够从 B 加载 xml和 C)。

下面是我的配置, ApplicationContext.xml - 在项目 A 中

<bean id="jpaQueryManager" class="com.motherframework.base.dao.jpa.JPAQueryManager">
    <property name="jpaTemplate" ref="jpaTemplate"/>
</bean>

<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <!-- <property name="persistenceUnitManager" ref="pum"/>
    <property name="persistenceUnitName" value="SchoolWebsitePersistenceUnit"/> -->
    <property name="persistenceXmlLocation" value="classpath*:configuration/xml/persistence.xml"/>
    <!-- <property name="persistenceUnitPostProcessors">
      <list>
        <bean class="com.motherframework.base.dao.jpa.EntityScanner"/>
      </list>
    </property> -->
    <property name="dataSource"><ref bean="dataSource"/></property>
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true"/>
        <property name="generateDdl" value="true"/>
        <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
      </bean>
    </property>
</bean>

这是我的persistence.xml

<persistence-unit name="SchoolWebsitePersistenceUnit" transaction-type="RESOURCE_LOCAL">

    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.motherframework.plugin.school.entity.Account</class>
    <class>com.motherframework.plugin.school.entity.Module</class>
    <class>com.motherframework.plugin.school.entity.NavigationMenu</class>
    <class>com.motherframework.plugin.school.entity.User</class>


    <properties>
        <property name="dialect" value="org.hibernate.dialect.SQLServerDialect"/>
        <property name="hibernate.connection.autocommit" value="true"/>
        <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.archive.autodetection" value="class, hbm"/>
    </properties>

</persistence-unit>

现在我正在使用@transactional Service-DAO 层从我的客户端类(主要方法)获取实体(例如用户)。

User u = ((TestService) ApplicationContext.getBean("testService")).fetchUser();
// FROM User u WHERE u.id=1  (Note: no INNER JOIN u.account)

print(u.getAccount())

它应该给我NULL,但它抛出异常,

DEBUG DefaultListableBeanFactory:241 - Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
 DEBUG AnnotationTransactionAttributeSource:106 - Adding transactional method 'fetchUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
DEBUG DefaultListableBeanFactory:241 - Returning cached instance of singleton bean 'jpaTxManager'
DEBUG JpaTransactionManager:365 - Creating new transaction with name [com.motherframework.plugin.test.service.TestService.fetchUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
DEBUG JpaTransactionManager:323 - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@d964af] for JPA transaction
DEBUG JpaTransactionManager:355 - Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: jdbc:mysql://localhost:3306/schooldb, UserName=scott@localhost, MySQL-AB JDBC Driver]
DEBUG TransactionSynchronizationManager:183 - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@45378f] for key [org.apache.commons.dbcp.BasicDataSource@181b3d4] to thread [main]
DEBUG TransactionSynchronizationManager:183 - Bound value [org.springframework.orm.jpa.EntityManagerHolder@29d65b] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@b8176d] to thread [main]
DEBUG TransactionSynchronizationManager:258 - Initializing transaction synchronization
DEBUG TransactionInterceptor:381 - Getting transaction for [com.motherframework.plugin.test.service.TestService.fetchUser]
DEBUG TransactionSynchronizationManager:139 - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@29d65b] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@b8176d] bound to thread [main]
DEBUG TransactionSynchronizationManager:139 - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@29d65b] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@b8176d] bound to thread [main]
DEBUG TransactionSynchronizationManager:139 - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@29d65b] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@b8176d] bound to thread [main]
Hibernate: select user0_.id as id3_, user0_.accountId as accountId3_, user0_.email as email3_, user0_.loginId as loginId3_, user0_.name as name3_, user0_.password as password3_ from User user0_ where user0_.id=1
DEBUG TransactionInterceptor:410 - Completing transaction for [com.motherframework.plugin.test.service.TestService.fetchUser]
DEBUG JpaTransactionManager:925 - Triggering beforeCommit synchronization
DEBUG JpaTransactionManager:938 - Triggering beforeCompletion synchronization
 DEBUG JpaTransactionManager:752 - Initiating transaction commit
DEBUG JpaTransactionManager:462 - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@d964af]
DEBUG JpaTransactionManager:951 - Triggering afterCommit synchronization
DEBUG JpaTransactionManager:967 - Triggering afterCompletion synchronization
DEBUG TransactionSynchronizationManager:311 - Clearing transaction synchronization
DEBUG TransactionSynchronizationManager:229 - Removed value [org.springframework.orm.jpa.EntityManagerHolder@29d65b] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@b8176d] from thread [main]
DEBUG TransactionSynchronizationManager:229 - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@45378f] for key [org.apache.commons.dbcp.BasicDataSource@181b3d4] from thread [main]
DEBUG JpaTransactionManager:548 - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@d964af] after transaction
DEBUG EntityManagerFactoryUtils:329 - Closing JPA EntityManager
856 [main] ERROR org.hibernate.LazyInitializationException - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at            org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)
at     org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at      com.motherframework.plugin.school.entity.Account_$$_javassist_3.toString(Account_$$_javassist_3.java)
at java.lang.String.valueOf(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at 

您会发现我的实体管理器已关闭,因此如果它尝试获取用户帐户,它会给出异常......我理解......但如果实体管理器已关闭,那么它为什么要这样做那?如何阻止它?配置有问题吗?

还有一件事,我使用的 entitymanagerfactory 是否适合生产环境中的公共 Web 应用程序(以及在 tomcat 7 中)?

提前谢谢..:)

谢谢 Nizet..你的意思是我的 PersistenceContext 已经关闭,因为 EntityManager 已关闭。但是,如果实体真的不在 PersistenceContext 之外,那么它为什么要尝试获取它的关系呢?..它是一个简单的 POJO,不再是 @Entity..对吗?对于第二个问题,是的,我错过了

<tx:annotation-driven transaction-manager="jpaTxManager"/>
<bean id="jpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory"><ref bean="entityManagerFactory"/></property>
    <property name="dataSource"><ref bean="dataSource"/></property>
</bean>

请检查我的 Entitymanager 类型和 transactionmanager...它们是否适合生产?

这是我的 DS:

<bean id="dataSource" destroy-method="close"   class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${motherframework.configuration.db.driver}" />
<property name="url" value="${motherframework.configuration.db.url}" />
<property name="username" value="${motherframework.configuration.db.username}" />
<property name="password" value="${motherframework.configuration.db.password}" />

但是你的意思是说,尽管持久性上下文关闭了,“用户”对象仍然拥有一些使其不同于普通 POJO 类的属性?

【问题讨论】:

    标签: spring hibernate jpa lazy-loading entitymanager


    【解决方案1】:

    您的用户与一个帐户有关联。该帐户是延迟加载的。这意味着你第一次调用帐户(user.getAccount().getName())上的任何方法时,Hibernate 将从数据库中加载帐户的状态,并返回帐户的名称。并且它只能在实体管理器打开时执行此操作,否则它不再与数据库建立任何连接。

    它不能返回null:返回null意味着:这个用户没有账号,这是错误的。

    如果要在实体管理器关闭后访问账户,则需要在关闭之前初始化账户。没有办法。

    关于你的配置,不,它还没有准备好投入生产:

    • showSql 应该是假的
    • hibernate.show_sql 应该是假的
    • generateDdl 应该是假的
    • hibernate.connection.autocommit 应该是 false
    • 您没有显示您的数据源定义,这是非常重要的部分

    【讨论】:

    • 感谢 Nizet..请在我原来的问题中找到更新后的 DS 信息...我已经更新了它
    • 这不是数据源定义。那是事务管理器的定义。关于您的问题:您的实体已分离,您要求 user.getAccount().getName()?让我们用另一个例子:abhishek.getDisease().isCancer()。如果您忘记初始化疾病,您更喜欢这种方法做什么? false:医生会认为你没有癌症,但也许你有癌症。 true:医生会治好你的癌症,即使你没有癌症。最好的办法是抛出异常并表明存在错误:代码从未初始化的对象中获取属性。
    • 再次感谢 Nizet..我不明白你要的是实际的 DS bean....请在我原来的问题中找到更新后的 DS 信息...我已经更新了它 -跨度>
    • 请参阅commons.apache.org/dbcp/configuration.html:默认最大连接数为 8。使用此设置,您最多可以有 8 个并发事务。
    猜你喜欢
    • 1970-01-01
    • 2012-09-08
    • 2021-03-13
    • 1970-01-01
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多