2011-02-27 105 views
10

在我的項目中,我使用Hibernate和編程事務劃分。 每次在我的服務方法我寫一些類似的東西。Spring中的Hibernate事務管理器配置

Session session = HibernateUtil.getSessionFactory().openSession(); 
session.beginTransaction(); 
.. perform operation here 
session.getTransaction().commit(); 

現在我要用聲明式事務管理重構我的代碼。我現在有...

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

    <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> 
    <property name="configurationClass"> 
     <value>org.hibernate.cfg.AnnotationConfiguration</value> 
    </property> 
    </bean> 

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


    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory"> 
     <ref local="mySessionFactory"/> 
    </property> 
    </bean> 

服務類:

@Service 
public class TransactionalService { 

    @Autowired 
    private SessionFactory factory; 

    @Transactional 
    public User performSimpleOperation() { 
     return (User)factory.getCurrentSession().load(User.class, 1L); 
    } 
} 

而且簡單的測試 -

@Test 
public void useDeclarativeDem() { 
    FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("spring-config.xml"); 
    TransactionalService b = (TransactionalService)ctx.getBean("transactionalService"); 
    User op = b.performSimpleOperation(); 
    op.getEmail(); 

當我試圖讓交易法以外的用戶的電子郵件,因爲我懶初始化異常,電子郵件是我的情況是簡單的字符串。 Hibernate甚至不執行sql查詢,直到我調用POJO上的任何getter。

1)我在這裏做錯了什麼?

2)這種方法是否有效?

3)你可以推薦任何opensource項目,這些項目在spring/hibernate上使用基於註釋的配置嗎?

更新

出於某種原因,如果我更換的getCurrentSession的openSession這個代碼工作正常。有人可以解釋嗎?

謝謝

+0

是不同表中的用戶的電子郵件地址? – 2011-02-27 19:10:01

+0

同一表中的簡單字符串 – user12384512 2011-02-27 19:11:44

回答

10

好吧,最後我意識到什麼是問題。在上面的代碼中,我使用load來代替get。 Session.load實際上並沒有打到數據庫。這就是爲什麼我懶惰初始化異常之外@Transactional方法

如果我使用openSession而不是getCurrentSession,會話是在作用域彈簧容器之外打開的。至於結果會不近也讓我@Transactional方法

2

,直到您叫干將,是因爲我相信FetchType設置爲LAZY Hibernate的原因不執行任何SQL查詢。爲了解決這個問題,你需要改變FetchType到渴望你的POJO:

@Entity 
@Table(name = "user") 
public class User { 

    /*Other data members*/ 

    @Basic(fetch = FetchType.EAGER) 
    private String email; 

} 

我個人從來沒有指定基本類型有一個熱心FetchType所以我不能完全肯定,爲什麼你的配置需要這一點。如果僅在您的測試中它可能是由於您配置了JUnit測試的方式。它應該有類聲明是這樣的:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration({"/test-app-config.xml"}) 
@Transactional 
public class UserServiceTest { 

} 

作爲一個很好的資源我總是發現SpringByExample是有益的。

編輯

所以我不完全知道什麼是錯的配置。它不同於我設置的方式,所以這裏是我的典型配置,希望它有所幫助。 hibernate.transaction.factory_class可能是您錯過的關鍵屬性。我也使用AnnotationSessionFactoryBean

<!-- DataSource --> 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" 
    p:driverClassName="com.mysql.jdbc.Driver" 
    p:url="jdbc:mysql://localhost/dbname" 
    p:username="root" 
    p:password="password"/> 

<!-- Hibernate session factory --> 
<bean id="sessionFactory" 
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" 
    p:dataSource-ref="dataSource"> 
    <property name="packagesToScan" value="com.beans"/> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop> 
     </props> 
    </property> 
</bean> 

<!-- Transaction Manager --> 
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory"> 
     <ref bean="sessionFactory" /> 
    </property> 
</bean> 

<tx:annotation-driven transaction-manager="transactionManager"/> 
+0

感謝您的回答,實際上在用戶的任何字段中都沒有延遲初始化,當然,我也沒有爲簡單字符串指定獲取策略。我相信這個問題是在春季配置 – user12384512 2011-02-27 19:47:58

+0

你可以請你發佈LazyInitializationException的堆棧跟蹤?看起來奇怪的是,如果這是你所得到的例外,那麼就不會有某種形式的延遲初始化。 – 2011-02-27 19:52:55

+0

錯誤org.hibernate.LazyInitializationException - 無法初始化代理 - 沒有會話 org.hibernate.LazyInitializationException:無法初始化代理 - 沒有會話 \t在org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132) \t at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174) \t at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190) – user12384512 2011-02-27 19:57:54

0

的外部讀取對象屬性Hibernate文檔https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch11.html#objectstate-loading

注意,load()方法將拋出一個不可恢復的異常,如果沒有匹配的數據庫記錄。如果類使用代理映射,則load()只會返回一個未初始化的代理,並且在調用代理的方法之前實際上不會訪問數據庫。如果您希望創建與對象的關聯而不實際從數據庫中加載對象,這很有用。如果爲類映射定義了批處理大小,它還允許將多個實例作爲批處理加載。

從你的案例bean的上面的文檔映射到Spring代理,所以加載只是返回。因此你需要使用get()而不是load(),它總是碰到數據庫。