Hibernate updatable = false UUID字段已更新

时间:2014-12-15 16:38:15

标签: java spring hibernate jpa spring-data-jpa

我正在使用Spring Data JPA和Hibernate,并且@Column注释上的updatable = false属性出现问题。

我的所有@Entity对象都有一个基类,其UUID定义如下:

@MappedSuperclass
@Getter @Setter @EqualsAndHashCode(of= {"uuid"})
public abstract class AbstractEntity implements Persistable<Long> {

    @Id
    @GeneratedValue(strategy = AUTO)
    @Column(unique = true, updatable = false)
    private Long id;

    @Column(unique = true, updatable = false)
    private UUID uuid = UUID.randomUUID();

}

请注意updatable = false注释。

为了验证UUID字段实际上是不可更新的,我写了这个测试:

@Test
public void testChangeUUID() {

    User user = userRepo.findOne(1L);

    assertNotNull(user);
    assertEquals(USER_UUID, user.getUuid().toString());

    final UUID newUuid = UUID.randomUUID();

    user.setUuid(newUuid);

    user = userRepo.save(user);

    assertEquals(newUuid, user.getUuid());

    User user2 = userRepo.findOne(1L);
    assertNotNull(user2);
    assertEquals("UUID should not have changed", USER_UUID, user2.getUuid().toString());
}

我实际上期待在调用userRepo.save(user)时抛出异常,但这不会发生。相反,最终assertEquals()失败,这意味着UUID实际上正在更新。

这是预期的行为吗?有没有办法阻止UUID被更改?

2 个答案:

答案 0 :(得分:10)

根据documentationupdatable属性决定该列是否属于update语句的一部分。这意味着Hibernate在向数据库发送更新时会忽略它。因此,内存状态和数据库状态将不同。

要验证这一点,请在致电User user2 = userRepo.findOne(1L)

之前尝试清除会话(逐出)

答案 1 :(得分:0)

虽然最初的问题已经回答,但我想强调一个重要的观点,对于刚接触Hibernate的人,因为这可能有助于避免某些困惑。

@Column批注的javadoc of Hibernate 5.4表示其可选元素“可更新”:

  

(可选)该列是否包含在由持久性提供程序生成的 SQL UPDATE语句中。

如果您使用HQL或使用 CriteriaUpdate 发布更新声明,则对您用@Column(updatable = false)注释的字段进行更新,将被执行

当您使用Hibernate的@Column(updatable = false)或JPA的update方法时,merge可以工作。

不会抛出异常(例如,它会创建约束...,例如:@Column(nullable= false)除外),但是生成的更新语句将不包含标记的字段。

有关更多信息,确实有必要熟悉JPA的实体生命周期状态以及管理状态的方法,如下图所示。

我强烈建议您阅读此article,该书详细解释了此内容,并且是所附图片的来源。

JPA’s entity lifecycle states