Spring 尝试在EntityManager关闭后加载惰性关系

Spring 尝试在EntityManager关闭后加载惰性关系,spring,hibernate,jpa,lazy-loading,entitymanager,Spring,Hibernate,Jpa,Lazy Loading,Entitymanager,我有三个spring+JPA项目……一个基础项目a、一个插件项目B和实际项目C。在C中,其他两个项目都作为a.jar和B.jar导入。每个项目都有自己的ApplicationContext.xml。leaf项目i.e.C的persistence.xml位于proeject-A中appcontext.xml提到的自定义位置(而启动项目A在整个类路径中查找appcontext.xml和persistence.xml,因此能够从B和C加载xml) 下面是我的配置, ApplicationContext

我有三个spring+JPA项目……一个基础项目a、一个插件项目B和实际项目C。在C中,其他两个项目都作为a.jar和B.jar导入。每个项目都有自己的ApplicationContext.xml。leaf项目i.e.C的persistence.xml位于proeject-A中appcontext.xml提到的自定义位置(而启动项目A在整个类路径中查找appcontext.xml和persistence.xml,因此能够从B和C加载xml)

下面是我的配置, 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>
它应该给我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是否适合于生产环境(以及Tomcat7)中的公共Web应用程序

提前感谢……)

谢谢你…你是说我的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}" />


但是你想说的是,尽管持久性上下文是关闭的,“user”对象仍然拥有一些属性,这使得它不同于普通的POJO类吗?

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

它不能返回null:返回null意味着:该用户没有帐户,这是错误的

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

关于您的配置,不,尚未准备好进行生产:

  • showSql应该为false
  • hibernate.show\u sql应为false
  • generateDdl应该为false
  • hibernate.connection.autocommit应为false
  • 您还没有显示数据源定义,这是一个非常重要的部分

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

它不能返回null:返回null意味着:该用户没有帐户,这是错误的

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

关于您的配置,不,尚未准备好进行生产:

  • showSql应该为false
  • hibernate.show\u sql应为false
  • generateDdl应该为false
  • hibernate.connection.autocommit应为false
  • 您还没有显示数据源定义,这是一个非常重要的部分

谢谢Nizet..请在我的原始问题中找到更新的DS信息…我更新了它,这不是数据源定义。这是事务管理器的定义。关于您的问题:您的实体已分离,您需要user.getAccount().getName()?让我们使用另一个例子:
abhishek.getDisease().isCancer()
。如果忘记初始化疾病,您希望此方法执行什么操作<代码>错误:医生会认为你没有癌症,但也许你有一个<代码>正确:即使你没有癌症,医生也会治好你的。最好的方法是抛出一个异常并发出有错误的信号:代码从一个未初始化的对象获取属性。再次感谢Nizet..我不理解你要求的是实际的DS bean..请在我的原始问题中找到更新的DS信息…我已经更新了它-请参阅:默认的最大连接数是8。此设置最多有8个并发事务。谢谢Nizet..请在我的原始问题中找到更新的DS信息…我更新了它,这不是数据源定义。这是事务管理器的定义。关于您的问题:您的实体已分离,您需要user.getAccount().getName()?让我们使用另一个例子:
abhishek.getDisease().isCancer()
。如果忘记初始化疾病,您希望此方法执行什么操作<代码>错误:医生会认为你没有癌症,但也许你有一个<代码>正确:即使你没有癌症,医生也会治好你的。最好的方法是抛出一个异常并发出有错误的信号:代码从一个未初始化的对象获取属性。再次感谢Nizet..我不理解你要求的是实际的DS bean..请在我的原始问题中找到更新的DS信息…我已经更新了它-请参阅:默认的最大连接数是8。在此设置中,最多有8个并发事务。
<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>
<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}" />