我正在使用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被更改?
答案 0 :(得分:10)
根据documentation,updatable
属性决定该列是否属于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,该书详细解释了此内容,并且是所附图片的来源。