2014-10-07 46 views
2

我有一个现有的项目工作正常,但现在我必须实现一个备份系统执行exery日,并将数据库转储到文件。我想用ScheduledTask解决这个问题,但这意味着有另一个Thread使用Hibernate。春天和休眠:多个连接,线程安全

我的问题:究竟如何让Hibernate线程安全?

我有以下的代码 - (摘录):

在applicationContext.xml中

<bean id="myEmf" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dbDataSource" /> 
    <property name="packagesToScan" value="redb.main.core.model" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
    </property> 
    <property name="jpaProperties"> 
     <props> 
      <prop key="hibernate.hbm2ddl.auto">validate</prop> 
      <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop> 
      <!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> --> 
     </props> 
    </property> 
</bean> 

<!-- Transaction Management --> 
<tx:annotation-driven transaction-manager="txManager" /> 
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="myEmf" /> 
</bean> 

<bean id="persistenceExceptionTranslationPostProcessor" 
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 

这样我就可以得到EntityManager通过

@PersistenceContext 
protected EntityManager entityManager; 

但是,如果我的理解是正确的,每个Thread需要自己的EntityManagerEntityManagerFactory

如何在其他课程中创建新的EntityManager?我有persistence.xml。我必须创建它吗?

+1

Spring将注入一个线程绑定'EntityManger'(如文档中所述)。只要确保你所做的是在一个事务中,这样就会有一个线程绑定'EntityManager'。你没有得到一个单独的线程,每个线程都有它自己的(如果你使用'OpenEntityManagerInViewFilter/-Interceptor',那么在事务或者请求期间,但在这里不适用,因为你需要我们后台线程)。但是,让数据库执行备份而不是尝试外部化它不是更容易吗? – 2014-10-07 18:20:20

+1

如果事务没有开始(假设你有'@ Transactional'),确保你有一个''来启用事务。还要确保你没有复制bean实例,在你的'ContextLoaderListener'和'DispatcherServlet'中有'component-scan'可能会导致(取决于设置)重复bean,其中一个被代理并且有事务,另一个不。在过滤器中不应该有一个事务(还),因为它在其他事务之前执行,过滤器不会启动事务,而是将一个EntityManager绑定到当前线程。 – 2014-10-08 07:55:56

回答

0

他 - 他。欢迎来到地狱。

主要问题是,春天试图用基于方面的解决方案来做到这一点。虽然这是错误的(或不可破坏的),但在微不足道的情况下它可以工作。

您的问题的一般答案是,EntityManagerFactory可以是软件中的全局静态对象,尽管如果我简单地使用了这个对象,我就会被扔石头。

默认情况下,spring aop会在应用程序中“编织”部署,通过注释查找所有数据库实体类,并封装其方法以始终提供现有的entitymanager。这是理论。但这不是实践。

实践是,你几乎不能控制究竟会发生什么。

我做了什么:有一个名为org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter的servlet过滤器,它可以为每个请求打开一个entitymanager,并根据需要刷新/关闭该过滤器。是的,它的名字是关于“意见”的,但它的名字很快就是它的第一个bug:实际上我们不得不称之为“requesttransactionfilter”等等。它没有任何MVC视图可以做,它正在处理来自servlet容器的http请求实体。

如果你不喜欢在spring应用程序中使用servlet过滤器,那么也有一个名为OpenEntityManagerInViewInterceptor的弹簧拦截器也具有非常相似的功能。

以编程方式,您可以通过createEntityManager()方法从EntityManagerFactory生成EntityManager

快乐的谷歌搜索!你正处在一个漫长的道路上。

+1

Spring确保您有一个线程安全的'EntityManager'它只是一个代理,它查找绑定EntityManager的线程或使用EntityManagerFactory创建一个新线程。没有什么可怕的,而且它可以在全球范围内的无数企业应用中发挥作用。没有涉及编织,也没有涉及AspectJ。唯一的AOP部分是您需要确保所有内容都在事务内部执行并且可以正常工作。这并不是一个漫长的过程,它只是一个让你的配置正确的问题,并且从你描述的你没有的东西开始,并试图解决它。 – 2014-10-07 18:18:22

+1

'OpenEntityManagerInViewInterceptor'确实与视图无关,但与请求和处理线程无关。但对于后台线程来说,它并没有做任何事情。它是一个'HandlerInterceptor',并且是Spring MVC的一部分,因此绑定到了Web上。后台线程无用。 – 2014-10-08 05:32:46

+1

@ M.Deinum好吧。给图书馆带来误导性的名字是一个小问题还是一个严重的问题?如果某些东西根本不起作用(例如,最终的问题:事务/ EntityManager不是以某种方式创建的),那么你究竟能够挖掘出什么_had_ __ __ _ _done_?春天/时间不存在地方责任范式。几个月以来,我一直在挖掘泉源,并在那里创造了一些关于那些不是简单回答的问题。是的,因为没有。令人不愉快的春/ a问题的真正答案是:“深入挖掘资源并祈祷”。 – peterh 2014-10-08 07:16:45