我有一个Keyword
和一个KeywordType
作为实体。有很多类型的关键字。
当尝试保留类型的第二个关键字时,违反了唯一约束并回滚了事务。
搜索SO我发现了几个可能性(其中一些来自不同的上下文,所以我不确定它们的有效性) - this post和this post建议捕获异常对我来说没有用,因为我最终在我开始的地方,仍然需要以某种方式持久保存关键字。
同样适用于针对不同情况提出的锁定here
如this和this帖子中提议的自定义插入语句我认为不合适,因为我我正在使用Oracle而不是MySQL,并希望将实现与Hibernate联系起来。
另一种解决方法是尝试在生成关键字的代码中首先检索类型,并在找到关键字时将其设置为关键字,否则创建一个新关键字。
那么,什么是最好的 - 最强大,可移植(适用于不同的数据库和持久性提供商)和理智的方法?
谢谢。
涉及的实体:
public class Keyword {
@Id
@GeneratedValue
private long id;
@Column(name = "VALUE")
private String value;
@ManyToOne
@JoinColumn(name = "TYPE_ID")
private KeywordType type;
...
}
和
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = { "TYPE" }) })
public class KeywordType {
@Id
@GeneratedValue
private long id;
@Column(name = "TYPE")
private String type;
...
}
答案 0 :(得分:4)
你的最后一个解决方案是正确的,IMO。搜索关键字类型,如果未找到,则创建它。
捕获异常不是一个好选择,因为
但是请注意,使用此技术,您可能仍然有两个并行搜索相同类型的事务,然后尝试并行插入它。其中一个事务将回滚,但它的频率会低得多。
答案 1 :(得分:2)
如果你正在使用EJB 3.1并且不介意序列化这个操作,那么使用容器管理并发的单例bean可以解决这个问题。
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class KeywordTypeManager
{
@Lock(LockType.WRITE)
public void upsert(KeywordType keywordType)
{
// Only one thread can execute this at a time.
// Your implementation here:
// ...
}
@Inject
private KeywordTypeDao keywordTypeDao;
}
答案 2 :(得分:0)
我会选择这个选项:
尝试不同的解决方法 在代码中首先检索类型 生成关键字并将其设置为开启 找到关键字或创建新关键字 一个,如果没有。