我有一个Oracle数据库表,其中的列位于我的FoobarId类中.FooarId中的所有3个字段都是我的Foobar表中的复合pk。
我正在第一次运行时插入数据。但是,当我再次运行它时,我得到了ORA-00001:唯一的约束,表明我的PK被违反。我在其他运行良好的项目中也有类似的代码。这个似乎不更新记录,而是尝试再次插入。我的EmbeddedId有问题吗?
我的实体类:
@Entity
@Table(name = "FOOBAR_TABLE")
public class Foobar implements Serializable {
private static final long serialVersionUID = 4290109857781985996L;
private FoobarId foobarId;
private int containerId;
private String containerType;
private String action;
public Foobar() { }
public Foobar(String itemName, int itemId, Date itemDate) {
foobarId = new FoobarId(itemName, itemId, itemDate);
}
@EmbeddedId
public FoobarId getFoobarId() {
return foobarId;
}
public void setFoobarId(FoobarId foobarId) {
this.foobarId = foobarId;
}
// getters and settters
}
我的身份证班:
@Embeddable
public class FoobarId implements Serializable{
private static final long serialVersionUID = 7393136028821250311L;
private int itemId;
private String itemName;
private Date itemDate;
public FoobarId(){}
public FoobarId(String itemName, int itemId, Date itemDate) {
super();
this.itemId = itemId;
this.itemName = itemName;
this.itemDate = itemDate;
}
// getters/setters
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((itemDate == null) ? 0 : itemDate.hashCode());
result = prime * result + ((itemName == null) ? 0 : itemName.hashCode());
result = prime * result + itemId;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FoobarId other = (FoobarId) obj;
if (itemDate == null) {
if (other.itemDate != null) {
return false;
}
} else if (!itemDate.equals(other.itemDate)) {
return false;
}
if (itemName == null) {
if (other.itemName != null) {
return false;
}
} else if (!itemName.equals(other.itemName)) {
return false;
}
if (itemId != other.itemId) {
return false;
}
return true;
}
}
我具有扩展CrudRepository的必要Repository接口。
在服务类中,我保存了Foobar物品列表:
@Transactional
public void addList(List<Activity> itemList) {
logger.info("Saving Activity List size of: " + itemList.size());
activityRepository.save(itemList);
}
创建表sql:
CREATE TABLE "FOOBAR"
(
"ITEM_NAME" VARCHAR2(50 CHAR) NOT NULL ENABLE,
"ITEM_ID" NUMBER NOT NULL ENABLE,
"ITEM_DATE" DATE NOT NULL ENABLE,
"CONTAINER_ID" NUMBER,
"CONTAINER_TYPE" VARCHAR2(50 CHAR),
"ACTION" VARCHAR2(50 CHAR),
CONSTRAINT "FOOBAR_PK" PRIMARY KEY ("ITEM_NAME", "ITEM_ID", "ITEM_DATE")
)
答案 0 :(得分:1)
equals
对象上的 Date
不可靠(例如,参见this question)。
更改您的equals
方法以比较每个日期的getTimeInMillis
结果,或者最好不要将日期用作主键的一部分。
Spring-Data-Jpa还支持诸如LocalDate
或LocalDateTime
之类的java.time类,它们也比Date
更好。
答案 1 :(得分:1)
“日期”很棘手,因为语义取决于上下文。例如,java.util.Date
包含以毫秒为单位的时间,但是Oracle的SQL DATE
数据类型表示日期和时间(最高为一秒)。如果您的Java代码在具有SQL java.util.Date
数据类型的PRIMARY KEY列上使用DATE
的相等语义,则您会看到(从JPA的角度来看)持久存在的唯一值(从JPA的角度来看)如果只有不到一秒的时间不同,则任何时候数据库都会违反UNIQUE CONSTRAINT。
如您所见,将数据库中的列数据类型更改为TIMESTAMP
会提高列的时间分辨率以及键空间,从而解决了问题。