2012-08-03 33 views
1

我有三个spring + JPA项目...一个基础项目A,一个插件项目B和实际项目C.在C中,其他两个项目都以导入为A.jar和B.jar。每个项目都有自己的ApplicationContext.xml。叶子项目(即C)在proeject-A的appcontext.xml中提到了自定义位置的persistence.xml(启动项目A在整个类路径中查找appcontext.xml和persistence.xml,因此可以从B加载xml和C)。尝试在EntityManager关闭后加载懒惰关系

下面

是我的配置, applicationContext.xml中 - 在项目中的

<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 [[email protected]] for JPA transaction 
DEBUG JpaTransactionManager:355 - Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: jdbc:mysql://localhost:3306/schooldb, [email protected], MySQL-AB JDBC Driver] 
DEBUG TransactionSynchronizationManager:183 - Bound value [[email protected]] for key [[email protected]] to thread [main] 
DEBUG TransactionSynchronizationManager:183 - Bound value [[email protected]] for key [org[email protected]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 [[email protected]] for key [org[email protected]b8176d] bound to thread [main] 
DEBUG TransactionSynchronizationManager:139 - Retrieved value [[email protected]] for key [org[email protected]b8176d] bound to thread [main] 
DEBUG TransactionSynchronizationManager:139 - Retrieved value [[email protected]] for key [org[email protected]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 [[email protected]] 
DEBUG JpaTransactionManager:951 - Triggering afterCommit synchronization 
DEBUG JpaTransactionManager:967 - Triggering afterCompletion synchronization 
DEBUG TransactionSynchronizationManager:311 - Clearing transaction synchronization 
DEBUG TransactionSynchronizationManager:229 - Removed value [[email protected]] for key [org[email protected]b8176d] from thread [main] 
DEBUG TransactionSynchronizationManager:229 - Removed value [[email protected]] for key [[email protected]] from thread [main] 
DEBUG JpaTransactionManager:548 - Closing JPA EntityManager [[email protected]] 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 

你可以找到我的实体管理器是关闭的,所以它会给出一个异常,如果它试图在用户获取帐户....我明白...但如果entitymanager关闭,那么为什么它试图做到这一点?如何阻止它?配置有问题吗?

还有一件事,我正在使用的entitymanagerfactory适用于生产环境(和tomcat 7)中的公共web应用程序?

在此先感谢.. :)

感谢Nizet..you意味着我PersistenceContext已经为EntityManager的关闭关闭。但是,如果entity实际上超出了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不同类?

回答

5

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

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

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

关于你的配置,不,它不是为生产做好准备:

  • showSql应该是假的
  • hibernate.show_sql应该是假的
  • generateDdl应该是假的
  • hibernate.connection.autocommit应该是假的
  • 你还没有显示你的数据源定义,这是一个非常重要的部分
+0

感谢Nizet ..请在我的原始问题中找到更新的DS信息...我更新了它 – 2012-08-06 12:15:47

+0

这不是一个数据源定义。这是一个事务管理器的定义。关于你的问题:你的实体是分离的,并且你要求提供user.getAccount()。getName()?让我们用另一个例子:'abhishek.getDisease()。isCancer()'。如果您忘记初始化该疾病,您更喜欢这种方法吗? '假':医生会认为你没有癌症,但也许你有一个。 “真的”:即使你没有一个,医生也会治愈你的癌症。最好的办法是抛出一个异常,并指出存在一个错误:代码从非初始化对象获取属性。 – 2012-08-06 12:34:18

+0

再次感谢Nizet ..我没有承受,你是要求实际的DS豆....请在我原来的问题中找到更新的DS信息...我更新了它 - – 2012-08-07 04:45:34