Java Spring和Hibernate:多连接,线程安全
我有一个现有的项目运行良好,但现在我必须实现一个备份系统,该系统在exery-day执行,并将数据库转储到一个文件中。我想用一个Java Spring和Hibernate:多连接,线程安全,java,sql,spring,hibernate,thread-safety,Java,Sql,Spring,Hibernate,Thread Safety,我有一个现有的项目运行良好,但现在我必须实现一个备份系统,该系统在exery-day执行,并将数据库转储到一个文件中。我想用一个ScheduledTask来解决这个问题,但这意味着还有另一个线程使用Hibernate 我的问题:如何使Hibernate线程安全 我有以下代码-(片段): 在applicationContext.xml中 <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityMa
ScheduledTask
来解决这个问题,但这意味着还有另一个线程使用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
来自EntityManager工厂
如何在其他类中创建新的EntityManager
我没有persistence.xml
。我必须创建它吗?呵呵。欢迎来到地狱
主要的问题是,spring试图通过基于方面的解决方案来实现这一点。虽然这是有缺陷的(或不可调试的),但在一些琐碎的情况下它可以工作
对您的问题的一般回答是,EntityManagerFactory
可以是您软件中的全局静态对象,尽管如果我只是简单地使用它,我会大吃一惊
默认情况下,SpringAOP在部署时“编织”应用程序,通过注释查找所有数据库实体类,并包装其方法以始终提供现有的entitymanager。这就是理论。但事实并非如此
实际上,你几乎无法控制到底会发生什么
我所做的:有一个名为org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter的servlet过滤器,它可以为每个请求打开一个entitymanager,并根据需要刷新/关闭它。是的,它的名字是关于“视图”,但很快它的名字就成了它的第一个bug:实际上我们不得不称它为“requesttransactionfilter”之类的。它与MVC视图无关,它正在处理来自servlet容器的http请求实体
如果您不喜欢在spring应用程序中使用servlet过滤器,还有一个名为OpenEntityManagerViewInterceptor
的spring拦截器,其功能也非常类似
通过编程,您可以通过createEntityManager()
方法从EntityManager工厂
生成EntityManager
快乐的谷歌搜索!您正处于漫长道路的开端。Spring确保您有一个线程安全的EntityManager
它只是一个代理,可以查找线程绑定的EntityManager
或使用EntityManager工厂创建一个新的。这一点也不可怕,见鬼,它可以在全球无数的企业应用程序中运行。不涉及编织,也不涉及AspectJ。唯一的AOP部分是,您需要确保事务中的所有内容都执行并正常工作。这不是一个漫长的过程,只是一个让您的配置正确的问题,从您描述的您没有并试图解决它。OpenEntityManagerInViewInterceptor
实际上与视图无关,而是与请求和处理线程有关。但是对于后台线程来说,它没有任何作用。它是一个HandlerInterceptor
,是SpringMVC的一部分,因此与web绑定。它对于后台线程是无用的。@M.Deinum好的。对于图书馆来说,给类起误导性的名字是一个次要的问题还是一个严重的问题?如果有些东西根本不起作用(例如,典型的问题:事务/实体管理器不是以某种方式创建的),你他妈的怎么能找出必须做什么?spring/aop中根本不存在本地责任的范例。几个月以来,我一直在挖掘spring源代码,并创建了大量关于它的问题,这些问题并没有简单地得到回答。是的,因为没有。对于令人不快的spring/aop问题,真正的答案是:“深入挖掘源头并祈祷”。这一回答有一定道理。如果Spring为您创建了一个存储库,然后您将其交给一个与Spring无关的线程,那么您就有麻烦了。这样做不是个好主意。但我做到了。最后对我起作用的是删除所有@Transactional注释,切换到手动事务(TransactionTemplate),重要的是,在每个TransactionTemplate上同步[Java synchronize()]。Spring将注入一个线程绑定的EntityManger
(如文档中所述)。只要确保您所做的是在事务内部,这样就会有一个线程绑定的EntityManager
。每个线程都有自己的线程(在事务或请求期间,如果使用OpenEntityManagerInViewFilter/-Interceptor
,则不会得到一个单独的线程,但此处不适用,因为您希望使用后台线程)。但是,让数据库执行备份而不是尝试将其外部化不是更容易吗?如果事务没有启动(并且假设您有@Transactional
),请确保您有一个
来启用事务。还要确保您没有复制bean实例,在ContextLoaderListener
和DispatcherServlet
中进行组件扫描
可能会导致(取决于设置)复制bean,其中一个被代理并具有事务,而另一个没有事务。在过滤器中不应该有一个事务(还没有),因为它在执行所有其他事务之前执行,过滤器不会启动一个事务,而是将一个EntityManager
绑定到当前线程。
@PersistenceContext
protected EntityManager entityManager;