当前位置: 首页 > 面试题库 >

使用FlushMode.AUTO调用session.close()时,Hibernate是否会刷新我更新的持久对象?

万俟穆冉
2023-03-14
问题内容

如果设置了FlushMode.AUTO,当我调用session.close()时,Hibernate会刷新我更新的持久对象吗?

我知道session.close()通常不会刷新会话,但是我不确定FlushMode.AUTO如何影响它。

从文档中:

FlushMode.AUTO
有时会在执行查询之前刷新会话,以确保查询永远不会返回陈旧状态。这是默认的刷新模式。

这是否意味着我有时可以在会话关闭之前依靠Hibernate验证更改是否被刷新?

小代码示例:

Session session = HibernateSessionFactory.getSession();  
PersistedObject p = session.get(PersistedObject.class,id);  
p.setSomeProperty(newValue);  
session.close();

更新
根据文档,这些是会话将刷新的位置(使用AUTO时)

  • 在执行某些查询之前
  • 来自org.hibernate.Transaction.commit()
  • 来自Session.flush()

这没有说任何有关Session.close()的信息


问题答案:

当调用session.close()(使用FlushMode.AUTO)时,Hibernate是否会刷新更新的持久对象

不,它不会,您应该 使用边界明确的事务
。引用非事务数据访问和自动提交模式:

与Hibernate进行非事务处理

查看以下代码,该代码无事务边界地访问数据库:

Session session = sessionFactory.openSession();
session.get(Item.class, 123l);
session.close();

默认情况下,在具有JDBC配置的Java SE环境中,如果执行以下代码片段,将发生以下情况:

  1. 打开一个新的会话。此时,它尚未获得数据库连接。
  2. 调用get()会触发SQL
    SELECT。现在,会话从连接池获取JDBC连接。默认情况下,Hibernate使用setAutoCommit(false)立即关闭此连接上的自动提交模式。这有效地启动了JDBC事务!
  3. SELECT在此JDBC事务内执行。Session关闭,并且连接返回到池中并由Hibernate释放-Hibernate在JDBC
    Connection上调用close()。未提交的交易会怎样?

该问题的答案是:“取决于情况!”
当在连接上调用close()时,JDBC规范没有说明未决事务。发生什么情况取决于供应商如何实施规范。例如,使用Oracle
JDBC驱动程序,对close()的调用将提交事务!当JDBC
Connection对象关闭并且资源返回到池中时,大多数其他的JDBC供应商都会采用合理的路由并回滚任何未决的事务。

显然,这对于您执行的SELECT来说不是问题,但请看以下变化:

Session session = getSessionFactory().openSession();
Long generatedId = session.save(item);
session.close();

此代码将导致INSERT语句,该语句在从未提交或回滚的事务内执行。在Oracle上,这段代码永久地插入数据。在其他数据库中,可能没有。(这种情况稍微复杂一些:仅在标识符生成器需要时才执行INSERT。例如,可以从没有INSERT的序列中获取标识符值。
然后将持久性实体排队,直到刷新时间插入为止-永远不会发生在这个代码 。一个身份策略需要对将要产生的值立即INSERT。)

底线:使用显式事务划分。



 类似资料:
  • 问题内容: 每天都会通过Web服务导入数据。 我创建了一个pojo 的 新(临时)实例 ,该 实例 已通过JPA注释在hibernate中进行了映射。 我将来自Web服务的数据填充到临时实例中 我从数据库中加载要使用瞬时实例中的数据更新的持久对象。 我以某种方式将此瞬态实例与持久实例合并。如果持久对象在其字段之一上具有非null值,则不会被瞬态对象上的潜在null值覆盖。基本上,我不想丢失任何数据

  • 我需要一些帮助来解决为什么我的持久性单元没有使用Hibernate加载到Karaf中的问题。日志文件报告 我认为问题是EntityManagerFactory服务未运行。根据SO消息Jpa-hibernate错误,启动服务时所有必需的服务都在运行。见下文。 我尝试在hibernate bundles之前启动我的持久性bundle,但是得到了相同的行为。 下面列出了数据源、持久性和persisten

  • 我用IdentityServer4创建了一个令牌我复制了这个例子我只是修改了这个 在身份服务器中- 我的令牌应该在10秒后到期,并且每10秒我有一个刷新令牌,但我不知道如何测试它。我做类似的事情: 它退回已过期的商品,我认为它应该退回我未过期的商品,因为它会被刷新。

  • 是否有必要向租户更新房屋的新引用? 编辑:为了澄清,您可以假设实体是在上面的代码之前加载的(因此,处于托管状态)。因为这个“事务”是Spring函数的一部分,所以事务将在它的末尾隐式提交。 编辑二:问题不在于我是否应该在一开始就把房子存起来,以避免这种情况。它是关于更好地理解对象是如何管理的。

  • 问题内容: 我有一个表和两个具有相同表的数据库,但是一个是另一个的符号链接,并且只允许对该表进行读取。 我已经使用Hibernate将表映射到Java,并使用spring根据某些输入条件将实体管理器的数据源设置为两个数据库之一。 当我连接到第二个数据库时,我仅调用只读操作(选择),但是Hibernate似乎试图将某些内容刷新回数据库,并且它无法告诉该视图不允许更新。 如何仅对第二个数据源禁用此更新

  • 问题内容: 我将一些对象存储在切片中。在将其附加到切片之前,我先打印对象的名称。 将其存储在切片中之后,我将其检索为指针,并希望将名称更改为,但是更改仍然有效,因为它仍然可以打印。为什么? 问题答案: 每当方法想要修改接收者时, 它都必须是指向该值的指针 ;该方法必须具有指针接收器。 如果方法具有非指针接收者,则在调用该方法时将创建并传递一个副本。从那时起,无论您对接收器做什么,都只能修改副本,而