2013-06-28 47 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

相关问题