我有这个基本上查询数据库并返回所有持久化实体的Web服务。出于测试目的,我已经创建了一个TestDataManager,它在加载Spring上下文后继承了两个示例实体(BTW,我使用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" />
这就是现在的情况:
奇怪的是,在TestDataManager中,如果我从sf.openSession()
切换到sf.getCurrentSession()
,我会收到一条错误消息:&#34;没有Hibernate会话绑定到线程,并且配置不允许创建这里是非交易的&#34;。
我在这里做错了什么?为什么查询&#34;没有看到&#34;坚持不懈的实体?为什么我需要在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();
}
答案 1 :(得分:1)
(我在jpa模式下使用hibernate)
我认为您的交易注释未被正确拦截。你有没有指定HibernateVendorAdapter?在jpa + hibernate中,没有它就没有完全集成集成!很可能你错过了这个宣言。
您应该能够直接自动装配会话而不是工厂。
作为旁注。如果在代码中使用opensession,至少只调用一次并将会话保存在变量中。另外,你相信每次通话都会开一个新的。
答案 2 :(得分:1)
@PostConstruct
public void insertTestData(){
Obejct o = new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
//Your code here
}
});
}