2012-08-03 49 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