【发布时间】:2011-07-04 04:26:36
【问题描述】:
使用 JPA 使实体只读的正确方法是什么?我希望我的数据库表永远不会以编程方式被修改。
我想我明白我应该用LockModeType.READ 锁定我的对象。从数据库中检索后,是否可以使用注释使我的实体直接锁定?还是我必须为那个特定实体搞乱并覆盖我的通用 DAO?
【问题讨论】:
使用 JPA 使实体只读的正确方法是什么?我希望我的数据库表永远不会以编程方式被修改。
我想我明白我应该用LockModeType.READ 锁定我的对象。从数据库中检索后,是否可以使用注释使我的实体直接锁定?还是我必须为那个特定实体搞乱并覆盖我的通用 DAO?
【问题讨论】:
在您的实体中添加EntityListener,如下所示:
@Entity
@EntityListeners(PreventAnyUpdate.class)
public class YourEntity {
// ...
}
实现您的EntityListener,以在发生任何更新时抛出异常:
public class PreventAnyUpdate {
@PrePersist
void onPrePersist(Object o) {
throw new IllegalStateException("JPA is trying to persist an entity of type " + (o == null ? "null" : o.getClass()));
}
@PreUpdate
void onPreUpdate(Object o) {
throw new IllegalStateException("JPA is trying to update an entity of type " + (o == null ? "null" : o.getClass()));
}
@PreRemove
void onPreRemove(Object o) {
throw new IllegalStateException("JPA is trying to remove an entity of type " + (o == null ? "null" : o.getClass()));
}
}
这将为您的具有 JPA 生命周期侦听器的实体创建一个防弹安全网。
【讨论】:
一种解决方案是使用基于字段的注释,将您的字段声明为 protected 并仅建议公共 getter。这样做,您的对象将无法更改。
(此解决方案不是实体特定的,它只是构建不可变对象的一种方式)
【讨论】:
Hibernate 还有一个org.hibernate.annotations.Immutable 注释,您可以将它放在类型、方法或字段上。
【讨论】:
@Immutable。这不是很有帮助。如果您尝试更新,它不会出错:它只会默默地失败。来自 Hibernate 的文档:“对不可变实体的更新将被忽略,但不会引发异常”。
如果您的 JPA 实现是休眠的 - 您可以使用休眠实体注释
@org.hibernate.annotations.Entity(mutable = false)
显然,这会将您的模型绑定到休眠状态。
【讨论】:
IIRC 您可以在@Column 注释中将每个字段设置为insertable = false 和updatable = false,但我相信一定有更好的方法... :)
我不认为 this 有帮助吗?
【讨论】:
我认为你正在寻找的是你的实体是不可变的。 Hibernate 支持这一点; JPA(至少 JPA 1.0)没有。我想你只能通过只提供 getter 来控制这一点,并确保 getter 只返回不可变的值。
【讨论】:
Eclipselink 实现还为您提供了实体级别的 @ReadOnly 注释
【讨论】:
【讨论】:
declare error 方法,是的。这仅在调用代码可用于 AspectJ 编译器时才有效。但是第一种方法仍然有效,因为它修改了实际的实体类文件。
如果您正在使用 spring-data 或以其他方式使用存储库模式,请不要在该特定实体的存储库中包含任何保存/更新/创建/插入/等方法。这可以通过为只读实体提供一个基类/接口和一个为可更新实体扩展只读的可更新实体来概括。正如其他发帖者所指出的,setter 也可能是非公开的,以避免开发人员意外设置他们无法保存的值。
【讨论】: