Java 为什么Hibernate每次运行我的应用时都要插入重复记录?
使用Hibernate 4.2.3最终版。我拥有以下实体:Java 为什么Hibernate每次运行我的应用时都要插入重复记录?,java,hibernate,orm,configuration,duplicates,Java,Hibernate,Orm,Configuration,Duplicates,使用Hibernate 4.2.3最终版。我拥有以下实体: @Entity @AttributeOverrides({ @AttributeOverride(name="id", column=@Column(name="word_id")) }) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @Table(name="words") public class Word { @Id @GeneratedValue(stra
@Entity
@AttributeOverrides({
@AttributeOverride(name="id", column=@Column(name="word_id"))
})
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name="words")
public class Word {
@Id @GeneratedValue(strategy=GenerationType.AUTO)
protected Long id;
@Column(name="word_text")
private String text;
@Column(name="word_length")
private Integer length;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="word_type_id", referencedColumnName="word_type_id")
private WordType type;
@Column(name="word_definition")
private String definition;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "synonyms", joinColumns = @JoinColumn(name = "word_id"), inverseJoinColumns = @JoinColumn(name = "synonym_id"))
private List<Word> synonyms;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "antonyms", joinColumns = @JoinColumn(name = "word_id"), inverseJoinColumns = @JoinColumn(name = "antonym_id"))
private List<Word> antonyms;
// ctor, getters/setters, etc.
}
以及以下测试驱动程序:
public class HibernateTester {
public static void main(String[] args) {
Word fast = new Word("fast", 4, WordType.Adverb, "A fast thing.", new ArrayList<Word>(), new ArrayList<Word>());
Word slow = new Word("slow", 4, WordType.Adverb, "A slow thing.", new ArrayList<Word>(), new ArrayList<Word>());
Word quick = new Word("quick", 5, WordType.Adverb, "A quick thing.", new ArrayList<Word>(), new ArrayList<Word>());
quick.addSynonym(fast);
quick.addAntonym(slow);
WordDAO wordDAO = new WordDAO();
wordDAO.saveWord(quick);
}
}
公共类HibernateTester{
公共静态void main(字符串[]args){
单词fast=新词(“fast”,4,WordType.副词,“一个快速的东西”,new ArrayList(),new ArrayList());
单词slow=新词(“slow”,4,WordType.副词,“一个慢的东西”,new ArrayList(),new ArrayList());
单词quick=新词(“quick”,5,WordType.副词,“一件快的事情”,new ArrayList(),new ArrayList());
addSynonym(fast);
快。加反义词(慢);
WordDAO WordDAO=新的WordDAO();
saveWord(快速);
}
}
如果我多次运行HibernateTester
,每次都会将这3个字插入数据库表中。因此,如果我从words
表中删除每条记录,然后运行测试驱动程序4次,那么表中就有12个字(4次运行x 3次记录/运行)。因为我使用的是会话#saveOrUpdate
,所以我希望Hibernate足够聪明,能够找出数据库中已经存在的实体,并防止它们被插入
因此:
saveOrUpdate()
如果实体没有ID,则保存该实体;如果实体已经有ID,则更新该实体。您总是传递没有ID的实体,因此Hibernate会创建该实体。每一次
唯一标识实体的是它的ID,而不是它的名称、文本或任何其他属性。saveOrUpdate()
如果实体没有ID,则保存它,如果它已经有ID,则更新它。您总是传递没有ID的实体,因此Hibernate创建实体。每一次
唯一标识实体的是它的ID,而不是它的名称、文本或任何其他属性。谢谢@JBNizet(+1)-那么这里的解决方案是什么?添加一个DAO方法,如
WordDAO#getWordByText(String
),然后首先查找每个单词?这样每个单词都会有一个ID,所以当我去保存它时,它会被视为一个更新。。。这是一个可行的解决方案吗?这里的标准做法是什么?再次感谢!你应该做什么取决于你想要实现什么。你想实现什么?我想确保被骗者不会进入我的数据库。words
表应该对word\u text
和word\u type\u id
具有唯一性约束。因此,如果我想从数据库中提取一个单词,那么我想我必须有这样一个方法:WordDAO#getWord(String-wordText,WordType-WordType):word
,它可以这样调用:word-fox=WordDAO.getWord(“fox”,WordType.noon)代码>。此时,fox
应该有一个填充的ID,如果我对它进行任何更改(或不更改),然后调用wordDAO.saveWord(fox)
,那么它应该被更新,而不是插入……这是我能想到的最好的解决方案,但这是我的第一个Hibernate项目。所以我不确定是否有更好的方法来防止重复…这就是解决方法。但是,在数据库中还应该有一个惟一的约束,以在数据库级别强制执行该约束(这是唯一能够保证惟一性的约束)。注意,您不需要调用WordDAO.saveWord(fox)。对附加实体所做的任何更改都将自动保持不变,而无需调用任何保存方法。您只需在数据库中找到实体,并对其进行更新即可。谢谢@JBNizet(+1)-那么这里的解决方案是什么?添加一个DAO方法,如WordDAO#getWordByText(String
),然后首先查找每个单词?这样每个单词都会有一个ID,所以当我去保存它时,它会被视为一个更新。。。这是一个可行的解决方案吗?这里的标准做法是什么?再次感谢!你应该做什么取决于你想要实现什么。你想实现什么?我想确保被骗者不会进入我的数据库。words
表应该对word\u text
和word\u type\u id
具有唯一性约束。因此,如果我想从数据库中提取一个单词,那么我想我必须有这样一个方法:WordDAO#getWord(String-wordText,WordType-WordType):word
,它可以这样调用:word-fox=WordDAO.getWord(“fox”,WordType.noon)代码>。此时,fox
应该有一个填充的ID,如果我对它进行任何更改(或不更改),然后调用wordDAO.saveWord(fox)
,那么它应该被更新,而不是插入……这是我能想到的最好的解决方案,但这是我的第一个Hibernate项目。所以我不确定是否有更好的方法来防止重复…这就是解决方法。但是,在数据库中还应该有一个惟一的约束,以在数据库级别强制执行该约束(这是唯一能够保证惟一性的约束)。注意,您不需要调用WordDAO.saveWord(fox)。对附加实体所做的任何更改都将自动保持不变,而无需调用任何保存方法。您只需在数据库中找到实体,并对其进行更新,仅此而已。对于JB Nizet的进一步解释,您可以通过放弃自动生成的ID并声明由文本和类型字段组成的复合ID来防止这种情况。请参见:哎哟,不要这样做。太可怕了。总是喜欢纯技术的、自动生成的主键。它们使一切变得更容易、更清洁、更快。但这是一个可行的解决方案吗?这完全取决于你所说的可行。逐个重命名1000个文件是一个可行的解决方案,但在脚本中自动化任务是一种更好的方法。功能性PK不好。复合的、功能性的PK甚至更糟糕。它们不是我倾向于使用的东西。如果明天是办公室里又一个安静的日子,那就为明天读点书吧!“宗教战争已经结束
public class HibernateTester {
public static void main(String[] args) {
Word fast = new Word("fast", 4, WordType.Adverb, "A fast thing.", new ArrayList<Word>(), new ArrayList<Word>());
Word slow = new Word("slow", 4, WordType.Adverb, "A slow thing.", new ArrayList<Word>(), new ArrayList<Word>());
Word quick = new Word("quick", 5, WordType.Adverb, "A quick thing.", new ArrayList<Word>(), new ArrayList<Word>());
quick.addSynonym(fast);
quick.addAntonym(slow);
WordDAO wordDAO = new WordDAO();
wordDAO.saveWord(quick);
}
}