我在阻止将重复的值插入MySQL数据库(使用Hibernate)时遇到问题。问题是:我有类别,它有父类别。可以有两个名称相同但父级不同的类别(这就是类别名称不能用作 businessId 的原因)。当类别没有父类别(即顶级类别)时,parentId 的值为 NULL。我无法理解我在以下代码中做错了什么,无法将重复的内容插入数据库。
这是我的实体类。
@Entity
@Table(name = "category", uniqueConstraints = {@UniqueConstraint(columnNames = {"name","parentId"})})
public class Category implements Serializable {
@Id
@Column(name="id")
@GeneratedValue
private long id;
@Column(name="name")
private String name;
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="parentId", nullable=true)
private Category parent;
...
}
这是用于解析新类别的代码(我相信这里有点问题:-|)
for (...) {
Category parent = null;
String [] categories = somePath.split("\\");
for (String cat: categories) {
Category category = new Category();
category.setName(cat);
category.setParent(parent);
parent = categoryDB.insertCategory(category);
}
}
这是插入类别函数
public Category insertCategory (Category category) {
Session session = sessionFactory.openSession();
Transaction transaction = null;
try{
transaction = session.beginTransaction();
category.setId((Long) session.save(category));
transaction.commit();
} catch (HibernateException e) {
if (transaction!=null)
transaction.rollback();
...
} finally {
session.close();
}
return category;
}
执行代码后,我在数据库中得到了以下条目:
select * from category;
+----+--------------+----------+
| id | name | parentId |
+----+--------------+----------+
| 1 | A | NULL |
| 4 | A | NULL |
| 2 | B | 1 |
| 3 | C | 2 |
| 5 | B | 4 |
| 6 | C | 5 |
+----+--------------+----------+
当我尝试仅通过"名称"进行限制时,只有 3 个条目插入到数据库中,但由于上述情况,我不能仅按名称施加限制。
编辑:我看到解决这个问题的可能性之一是约束定义中的函数使用(在MySQL的情况下可能是IFNULL(parentId,0)。例如,在Oracle中(根据这篇文章),似乎这种可能性是可能的,但在MySQL中则不然。
编辑2:实际上,我在MySQL错误跟踪器中发现了有类似问题的人。由于我使用的是 MySQL,因此我检查了在创建表时生成的代码,它几乎与 Bug 报告中的代码相同(实际上认为 NOT 错误与错误跟踪器中提到的某些标准一致。无论如何,我的同事试图在MS SQL Server上执行等效的代码,这实际上阻止了他在名称字段和null parentId上插入具有相同值的行。似乎没有数据库级别的可能性(至少使用 MySQL)来制作所需的约束,这非常令人失望。接受答案,因为这是该问题的可能解决方法之一(使用 magic numbers
,我不会坚持,更喜欢在我的代码中保留一个额外的find
查询)
任何帮助将不胜感激,谢谢!
一个简单的解决方案是parentId
成为"自我"。
+----+--------------+----------+
| id | name | parentId |
+----+--------------+----------+
| 1 | A | 1 |
| 2 | B | 1 |
| 3 | C | 2 |
| 4 | C | 3 |
+----+--------------+----------+
因此,您不可能永远拥有两个"顶级"类别。使parentId
不可为空。
我确定您的问题与未在约束中检查空值有关。不过,您可以尝试使用休眠检查,但它肯定会效率更低。
@org.hibernate.annotations.Check