- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我们目前正在将一个用 Spring/Hibernate
编写的遗留应用程序迁移到 Spring Boot
(为了减少冗长的配置和其他好处)。
因为 Spring Boot
遵守 JPA
,我们必须“迁移”我们的遗留代码 - 用 native Hibernate
(版本 5)编写 - 到 JPA
。
我们现在面临一个问题,即 Hibernate 在触发查询之前不会刷新 session ,即使定义了 FlushMode
AUTO
配置如下:
1) Main Spring Boot Config,即应用的入口
@Configuration
@EnableAutoConfiguration
@ComponentScan
@Slf4j(topic = "system")
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
2)持久化配置:
- 创建一个 JPA 事务管理器
;
- 创建一个 HibernateJpaSessionFactoryBean
以防止我们不必调整 EntityManagerFactory
使用(和 Autowiring )SessionFactory
的所有地方并确保SessionFactory
和 EntityManagerFactory
都参与相同的 (JPA) Transaction
。
@Configuration
public class PersistenceConfig {
@Bean
public PlatformTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactoryBean.getObject());
transactionManager.setDefaultTimeout(30);
return transactionManager;
}
@Bean
public HibernateJpaSessionFactoryBean sessionFactory(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
HibernateJpaSessionFactoryBean sessionFactoryBean = new HibernateJpaSessionFactoryBean();
sessionFactoryBean.setEntityManagerFactory(entityManagerFactoryBean.getObject());
return sessionFactoryBean;
}
}
产生问题的负责代码如下:
@Override
public void deletePossibleAnswerAndRemoveFromQuestion(Long definitionId, Long questionId, Long possibleAnswerId) {
Definition definition = checkEntity(Definition.class, definitionId);
Question question = checkEntity(Question.class, questionId);
PossibleAnswer possibleAnswer = checkEntity(PossibleAnswer.class, possibleAnswerId);
question.remove(possibleAnswer);
if (definition.isHasRefinement()) {
// this fires a 'select count(*) ...' query
if (!possibleAnswerRepository.existsByType(definitionId, QuestionType.REFINE)) {
definition.markNoRefinementsPresent();
}
}
}
通过执行级联删除从问题(父)实体中删除 PossibleAnswer(子)实体,如下面的代码所示:
@Table(name = "questions")
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Question extends AbstractEntity {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<PossibleAnswer> possibleAnswers = new HashSet<>();
public void remove(PossibleAnswer possibleAnswer) {
getPossibleAnswers().remove(possibleAnswer);
possibleAnswer.setQuestion(null);
}
remove
方法是一种确保双向关联两端解耦的便捷方法。
现在的大问题是 question.remove(possibleAnswer)
在提交时间之前传播到数据库。
换句话说:级联删除生成一个删除查询,该查询在“count”查询之后触发,导致过时的结果,因为它取决于被删除的 PossibleAnswer。
我们检查的事情:
1) Session
的FlushMode
和SessionFactory
/EntityManagerFactory
的默认FlushMode
->两者都设置为 AUTO
2) 在触发查询之前手动添加 session.flush()
-> 这给出了期望的结果,其中 question.remove(possibleAnswer)
在触发查询之前传播到 DB
3) 在运行 native Hibernate
有谁知道为什么我们会遇到这种奇怪的行为???
-- 更新 1--
我检查过的东西:
1) 在 EntityManager 上正确设置了默认的 FlushMode 'AUTO';
2) 在级联删除之前执行“计数”查询。
-- 更新 2--
似乎在执行“计数”查询时,Hibernate 首先检查(如下所示的代码)是否必须在真正执行查询之前刷新 session 。
protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
errorIfClosed();
if ( !isTransactionInProgress() ) {
// do not auto-flush while outside a transaction
return false;
}
AutoFlushEvent event = new AutoFlushEvent( querySpaces, this );
listeners( EventType.AUTO_FLUSH );
for ( AutoFlushEventListener listener : listeners( EventType.AUTO_FLUSH ) ) {
listener.onAutoFlush( event );
}
return event.isFlushRequired();
}
方法 isTransactionInProgress
确定是否必须执行刷新。实现如下所示:
@Override
public boolean isTransactionInProgress() {
checkTransactionSynchStatus();
return !isClosed() && transactionCoordinator.getTransactionDriverControl()
.getStatus() == TransactionStatus.ACTIVE && transactionCoordinator.isJoined();
}
看来 transactionCoordinator.getTransactionDriverControl().getStatus()
返回 NOT_ACTIVE
并且 transactionCoordinator.isJoined()
返回 false
。
这导致在触发查询之前未执行级联删除的问题。
我真的不知道为什么基础交易不是进展。
我的设置是普通的 Spring Boot 和 Hibernate,其中我有一个 Service
注释方法 @Transactional
所以所有底层数据库调用都应该在一个事务中执行。
最佳答案
Hibernate legacy FlushMode
之间存在差异和 JPA 规范。
如果您升级到 Hibernate 5.2,这完全取决于您如何引导 Hibernate。如果您使用 JPA 方式(例如 persistence.xml
)进行引导,那么将使用 JPA 行为。如果您通过 SessionFactoryBuilder
进行引导,则会考虑遗留行为。
我怀疑 count
查询是 native SQL 查询,因为实体查询应该在旧模式和 JPA 模式下触发刷新。
因此,您有多种选择:
LocalEntityManagerFactoryBean
而不是 LocalSessionFactoryBean
。FlushMode.ALWAYS
.确保每个新的 Session
都设置了 FlushMode.ALWAYS
:sessionFactory.getCurrentSession().setFlushMode(FlushMode.ALWAYS);
<session.flush()
。It seems thattransactionCoordinator.getTransactionDriverControl().getStatus()returns NOT_ACTIVE and transactionCoordinator.isJoined() returnsfalse.
很可能是 Spring 事务管理配置有问题。确保 Spring 框架版本与您使用的 Hibernate 5 兼容。
此外,如果 TransactionInterceptor
存在,请检查调试堆栈跟踪。如果不是,那么您就没有在事务上下文中运行。
关于java - FlushMode AUTO 不适用于 JPA 和 Hibernate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42253404/
已经通过 FlushMode 的 hibernate api 规范,但没有得到确切的区别。所以请帮忙。 最佳答案 如果在触发任何查询之前刷新模式为“AUTO”,则 hibernate 将检查是否有任何
好吧,我看到一些帖子问几乎相同的事情,但要点有点不同。 这是一个经典案例:我正在保存/更新一个实体,并且在 中相同的 session ,我正在尝试使用 FlushMode = Auto 从数据库中获取
在 Hibernate 中,我想知道当 flushMode 为 AUTO 时哪些条件会触发刷新?它可能很复杂(或“神奇”),但基本条件是什么? 谢谢 最佳答案 当 flush mode是 FlushM
您能给我一些在 Hibernate session 中使用 FlushMode.ALWAYS 的实际示例吗? 谢谢 最佳答案 这几乎总是不必要的。如果在 session 中进行的修改在刷新到数据库时导
根据 Session.setFlushMode(FlushMode)我们可以将 FlushMode 设置为 session 。现在我正在尝试测试Flushmode.COMMIT如何模式适用于一个小例子
我真的是 Spring 的新手我正在使用 JSF+Hibernate+Spring 开发一个简单的 JEE 应用程序我在尝试更新 DAO 上的值时遇到了一些问题我确定问题与 Spring 配置 xml
我已经将 NHibernate session 的 FlushMode 属性设置为 FlushMode.Never,但是当我调用 session.Save(User) 时,无论如何都会对数据库进行调用
我花了一些时间搜索如何配置 NHibernate 的 FlushMode,以便它只能保存我明确称为 Save/Update/Delete 的对象,但我发现我不能这样做。取而代之的是,当我使用 NHib
Grails 1.3.7 我们有一个合并2个用户的服务方法。由于数据量大,因此有很多内容,因此需要进行大量的读取,更新和写入。服务中有transactional = true。我了解Grails的默认
这个问题已经有答案了: EntityManger flushmode in JDBC (1 个回答) 已关闭 9 年前。 entityManager.setFlushMode(FlushModeTyp
我已将 spring security 插件与我的 grails 应用程序集成,该应用程序将 hibernate 作为 ORM 工具... 使用 Spring Security 插件,我的应用程序一切
帮助设置 hibernate 的刷新属性。 我遇到了错误。 在只读模式 (FlushMode.MANUAL) 下不允许写入操作:将您的 Session 转换为 FlushMode.COMMIT/AUT
我正在努力提高异步事务方法的性能。 在这个任务中,我必须从一个表中读取近 7500 条记录,对其进行详细说明,然后在另一个表中插入/更新相应的行。 我在 hibernate 中使用 spring da
所以...已经说过了: 如何在 C# 中将 FlushMode 更改为 Commit? 我的意思是,在 Fluent NHibernate 中,FlushMode 默认设置为 Auto。 所以...要
我的应用程序使用 FlushMode.AUTO 。对于特定的服务方法调用,我想将 Hibernate Session.FlushMode 更改为 FlushMode.COMMIT 并在方法完成时恢复为
我们目前正在将一个用 Spring/Hibernate 编写的遗留应用程序迁移到 Spring Boot(为了减少冗长的配置和其他好处)。 因为 Spring Boot 遵守 JPA,我们必须“迁移”
我想在没有 FlushMode.ALWAYS 的情况下运行一个单一的方法。 所以我需要 setFlushMode(FlushMode.COMMIT) 但我不知道该怎么做,我开始认为使用 spring
我读到是否调用 session.flush()提交与否取决于 FlushMode已设定。不过,我不知道是哪个FlushMode做这个。我希望 session 被刷新并提交。我应该使用哪种 FlushM
我有下一个代码: Color color = new Color(null,"B12",null,1); Session session=sessionFactory.openSess
我是 spring 的初学者,在我基于控制台的项目中,我将 spring 与 hibernate 结合使用。我被以下错误困扰了大约一天。 Exception in thread "main" org.
我是一名优秀的程序员,十分优秀!