我有一个Spring Boot服务,它应该将事务中两种类型的多个实体持久化到Oracle DB。第一种实体类型的表是巨大的(每天300万个条目,分区…),我有一个问题,我需要对重复项做出反应。我使用一些字段来创建哈希,并且在数据库中对该字段有一个唯一的约束。我认为一个聪明的想法是一个实体一个实体地保存和刷新,并对ConstraintViolationException做出反应。根据保存第一个实体列表的结果,我需要创建第二个实体并保存它,但它会回滚所有内容。我现在的问题是,如果这种方法通常是错误的,或者可以,并且存在一些小问题?如果这通常是错误的,那么我应该如何进行重复检查(预先选择不是选项)?
下面是一些伪代码,可以让你有更好的想法
@Entity
public class Foo{
public String uniqueHash;
// couple of other properties that will be used to calculate the hash
}
@Entity
public class Bar{
private List goodIds;
private List badIds;
public Bar(List goodIds, List badIds){
this.goodIds = goodIds;
this.badIds = badIds;
}
}
@Repository
@Transactional(noRollbackFor = PersistenceException.class)
public interface FooRepository extends JpaRepository<Foo, String> {
Foo saveAndFlush(Foo f) throws PersistenceException;
}
@Repository
@Transactional(noRollbackFor = PersistenceException.class)
public interface BarRepository extends JpaRepository<Bar, String> {
Bar saveAndFlush(Bar b) throws PersistenceException;
}
SomeService
@Transactional(noRollbackFor = PersistenceException.class)
public void doSomething(List<Foo> foos){
List<String> goodIds = new ArrayList();
List<String> badIds = new ArrayList();
for (Foo foo : foos) {
try {
fooRepository.saveAndFlush(foo);
goodIds.add(foo.getId());
} catch (PersistenceException e) {
if (e.getCause() instanceof ConstraintViolationException) {
badIds.add(foo.getId);
} else {
throw e;
}
}
}
barRepository.saveAndFlush(new Bar(goodIds, badIds));
}
为此,您可以使用自定义的< code>@SQLInsert来利用Oracles MERGE语句。另请参见https://stackoverflow.com/a/64764412/412446
最后,我找到了一种方法来实现预期的行为,甚至更好的是,我能够摆脱这些“noRollBackFor”属性。我只是重组了流程,并尝试保存事务中的所有内容,如果失败,Exception被捕获在调用方法上,输入被“清理”,事务方法被再次调用(递归)。这些重复是罕见的情况(每10kFoo实例都会发生),所以从性能的角度来看,有这些后续事务是可以的。这里又是更改后的伪代码
@Entity
public class Foo{
public String uniqueHash;
// couple of other properties that will be used to calculate the hash
}
@Entity
public class Bar{
private List goodIds;
private List badIds;
public Bar(List goodIds, List badIds){
this.goodIds = goodIds;
this.badIds = badIds;
}
public List getGoodIds(){
return goodIds;
}
public List getBadIds(){
return badIds;
}
}
@Repository
public interface FooRepository extends JpaRepository<Foo, String> {
}
@Repository
public interface BarRepository extends JpaRepository<Bar, String> {
}
public class FooException extends RuntimeException {
private final Foo foo;
public FooException(String message, Foo foo) {
super(message);
this.foo = foo;
}
public getFoo(){
return foo;
}
}
SomeService
public void doSomething(List<Foo> foos, Bar bar){
try{
doSomethingTransactional(foos,bar);
}
catch (FooException e) {
bar.getBadIds().add(e.getFoo().getId());
foos.remove(foo);
doSomething(foos, bar);
}
}
@Transactional
public void doSomethingTransactional(List<Foo> foos, Bar bar){
for (Foo foo : foos) {
try {
fooRepository.saveAndFlush(foo);
bar.getGoodIds.add(foo.getId());
} catch(DataAccessException e) {
if (e.getCause() instanceof ConstraintViolationException
&& ((ConstraintViolationException) e.getCause()).getConstraintName().contains("Some DB Message")) {
throw new FooException("Foo already exists", foo);
} else {
throw e;
}
}
}
barRepository.saveAndFlush(bar);
}
问题内容: 我正在JPA中对userid列强制执行唯一性约束检查,这是对user表中的所有记录强制执行的。 我的要求是,特定组织内的用户ID必须唯一,而不是在所有组织中都唯一。 如何执行此类检查? 问题答案: 您可以为唯一约束指定多个字段,请尝试: 通过这样做,您的约束条件将检查userid和Organizationid的组合是否唯一。 最好的祝福,费边
我遇到一个情况,需要根据另一个列值对一个列[属性]强制执行唯一约束。 例如,我有一个像table(ID,EID,Name,ISDeleted)这样的表 ISDeleted只能有一个值null或'y'(active或deleted),并且我想在EID上创建一个唯一的约束,仅当ISDeleted=null时才创建ISDeleted,因为我不关心是否有多个具有相同ID的已删除记录。请注意,EID可以为空
我有一个spring项目,想在数据库中强制一个字段的唯一性,并将错误消息返回给UI。 我已经阅读了这个SO答案,它是有意义的,所以@Col的(唯一=真)使表上的约束,但不强制它。 因此,问题变成了如何创建一个@Unique注释,该注释与数据库进行检查,并在POST处理程序上向BindingResult返回错误消息。 一个例子会很棒。 更新 我尝试了以下方法来制作自定义验证器: 对象(请注意,我添加
问题内容: 我想在我的MySQL表上添加一个唯一性约束。该表包含四列: 此约束必须检查对于new行,new和都未包含在或中。 例子 : 有没有办法定义这样的约束? 问题答案: 您可以通过触发器来做到这一点 注意: 由于您使用的MySQL版本缺少技巧,因此当找到具有相同地址的行时,违反对其中一列的约束。 这是 SQLFiddle 演示。取消注释最后一个插入语句之一,然后单击确定。这些插入不会成功。
我有以下JPA实体 这是我检查唯一约束的测试,插入具有相同电子邮件的另一个用户。
我有一个用户创建屏幕,它记录了各种用户详细信息以及名字和手机号码。我有一个对应的用户表,其中名字和手机号码构成一个复合唯一键。此表中还定义了其他完整性约束。 当在创建用户屏幕上输入违反此约束的用户数据时,需要向用户显示“用户友好”错误消息。 当这种违反发生时,我从MySQL数据库中得到的异常是: 有两个选项可以显示有意义的消息(例如:“错误:给定手机号码的用户名已存在,请更改其中一个”)。 选项1