2013-06-28 79 views
2

我有這個基本上查詢數據庫並返回所有持久實體的Web服務。爲了測試的目的,我創建了一個TestDataManager,它在加載Spring上下文後保留2個示例實體(順便說一下,我正在使用JAX-WS,Spring,Hibernate和HSQLDB)。爲什麼我不能檢索我剛纔堅持的實體?

我TestDataManager看起來是這樣的:

@Component 
public class TestDataManager { 

@Resource 
private SessionFactory sf; 

@PostConstruct 
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 
public void insertTestData(){ 
    sf.openSession(); 
    sf.openSession().beginTransaction(); 
    sf.openSession().persist(new Site("site one")); 
    sf.openSession().persist(new Site("site two")); 
    sf.openSession().flush(); 
} 
} 

我的JAX-WS端點看起來是這樣的:

@WebService 
public class SmartBrickEndpoint { 

@Resource 
private WebServiceContext context; 

public Set<Site> getSitesForUser(String user){ 
    return getSiteService().findByUser(new User(user)); 
} 

private ISiteService getSiteService(){ 
    ServletContext servletContext = (ServletContext) context.getMessageContext().get("javax.xml.ws.servlet.context"); 
    return (ISiteService) BeanRetriever.getBean(servletContext, ISiteService.class); 
} 
} 

這是我的服務類:

@Component 
@Transactional(readOnly = true) 
public class SiteService implements ISiteService { 

@Resource 
private ISiteDao siteDao; 

@Override 
public Set<Site> findByUser(User user) { 
    return siteDao.findByUser(user); 
} 
} 

這是我的DAO:

@Component 
@Transactional(readOnly = true) 
public class SiteDao implements ISiteDao { 

@Resource 
private SessionFactory sessionFactory; 

@Override 
public Set<Site> findByUser(User user) { 
    Set<Site> sites = new LinkedHashSet<Site>(sessionFactory.getCurrentSession().createCriteria(Site.class).list()); 

    return sites; 
} 
} 

這是我的applicationContext.xml:

<context:annotation-config /> 
<context:component-scan base-package="br.unirio.wsimxp.dao"/> 
<context:component-scan base-package="br.unirio.wsimxp.service"/> 
<context:component-scan base-package="br.unirio.wsimxp.spring"/> 

<bean id="applicationDS" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> 
    <property name="url" value="jdbc:hsqldb:file:sites"/> 
</bean> 

<bean id="sessionFactory" 
     class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="dataSource" ref="applicationDS" /> 

    <property name="configLocation"> 
     <value>classpath:hibernate.cfg.xml</value> 
    </property> 

    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.format_sql">true</prop> 
      <prop key="hibernate.connection.release_mode">on_close</prop> 
      <!--<prop key="hibernate.current_session_context_class">thread</prop>--> 
      <prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop> 
      <prop key="hibernate.hbm2ddl.auto">create-drop</prop> 
     </props> 
    </property> 
</bean> 

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

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

這就是現在事情:

  1. 當應用程序部署,TestDataManager#insertTestData踢入(因@PostConstruct)和堅持不會引發任何異常。到目前爲止,我應該在數據庫中擁有2個實體。
  2. 之後,我通過SOAP客戶端調用端點,並且請求一直到達到DAO。 Hibernate調用不會引發任何異常,但返回的列表是空的。

奇怪的是,在TestDataManager,如果切換從sf.openSession()sf.getCurrentSession(),我得到一個錯誤信息:「沒有Hibernate的Session綁定到線程,配置不允許非事務之一創建這裏」。

我在做什麼錯在這裏?爲什麼查詢「沒有看到」持久實體?爲什麼我需要在TestDataManager上調用sf.openSession(),儘管它的註釋是@Transactional

我已經在application.xml中用hibernate.current_session_context_class=thread做了一些測試,但是我只是在每個類中切換問題。我想不需要手動調用sf.openSession()並讓Hibernate保持小心。

非常感謝您的幫助!

+0

你有沒有解決問題了嗎?您是否嘗試過下面的解決方案? –

回答

1

我認爲你需要提交上insertTestData交易:

@PostConstruct 
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 
public void insertTestData(){ 
    Session session = sf.openSession(); 

    session.persist(new Site("site one")); 
    session.persist(new Site("site two")); 
    session.flush(); 
    session.close(); 
} 
+0

我還沒有嘗試過,我不得不把它放在一邊,用不同的方法繼續前進,但奇怪的是:爲什麼我需要打開一個會話並開始一個txn,如果我使用@Transactional註釋它呢?這對我來說沒有任何意義,畢竟@PostConstruct被調用,這讓我認爲spring的配置沒問題,並且這個類是一個「正確的」bean。它有任何意義嗎? – felipecao

+0

不需要你開始一個事務並且同時使用'@Transactional',如果你想要的只是堅持一些實體。我的回答只是解決了你打開5個會話而不是進行內部交易的事實。我編輯瞭解決方案並刪除了'session.beginTransaction()'和'tx.commit()'。請嘗試讓我們知道。 –

+0

工作正常!謝謝! – felipecao

1

(我使用休眠JPA的模式)

我想你的事務性註釋不正確攔截。你有沒有指定HibernateVendorAdapter?在jpa + hibernate中,沒有它,集成並沒有完全設置!很可能你錯過了這個聲明。

之後您應該能夠直接自動裝配會話而不是工廠。

作爲一個側面說明。如果在代碼中使用opensession,至少只需調用一次,並將會話保存在變量中。否則,你總是在每次打電話時都打開一個新的電話,我相信。

1
@PostConstruct 
public void insertTestData(){ 
    Obejct o = new TransactionTemplate(transactionManager).execute(new TransactionCallback() { 
    public Object doInTransaction(TransactionStatus status) { 
     //Your code here 
    } 
    }); 
} 

來源:http://forum.springsource.org/showthread.php?58337-No-transaction-in-transactional-service-called-from-PostConstruct&p=194863#post194863

+0

我試過了,但數據只是不顯示在數據庫上,我是否錯過了一些東西? https://gist.github.com/felipecao/5968341 – felipecao

+0

是的,你缺少session.persist。哪裏? – Igochan

相關問題