我的父实体和子实体的 ID 是使用策略 GenerationType.TABLE
生成的因为我正在使用 MySQL 数据库。
如果我在不指定 ID 的情况下创建父级(即,第一次创建父级),向其中添加新的子级,并保存父级,则 hibernate 将按预期工作并使用 MySQL AUTO_INCREMENT 列功能。
但是,如果我创建一个父级并指定一个 ID(即实例化已持久化的父级),向其中添加一个子级并保存该子级,则 hibernate 会发出 select sequence_next_hi_value from hibernate_sequences ...
并将其用作 child 的 PK。
同样,如果我通过 session.get(Parent, 1)
从数据库获取父级来实例化它,向其中添加一个新的子进程,并保存父进程或子进程,然后 hibernate 使用序列来获取子进程的 PK。
如果我创建足够多的新父项(确切地说是 32767 个)来运行 mysql AUTO_INCRMENT 计数器,则会由于主键不够唯一而导致失败。
这是我的父实体和子实体(分别命名为“位置”和“类别”):
@Entity(name="location")
public class Location {
@Id @GeneratedValue(strategy=GenerationType.TABLE) @Column(name="location_id")
private int id;
@OneToMany(mappedBy="location")
@Cascade(CascadeType.SAVE_UPDATE)
private List<Category> categories;
...
}
@Entity(name="category")
public class Category {
@ID @GeneratedValue(strategy=GenerationType.TABLE) @Column(name="category_id")
private int id;
@ManyToOne @JoinColumn(name="location_id")
private Location location;
}
这是 hibernate 代码:
Hibernate: select sequence_next_hi_value from hibernate_sequences where sequence_name = 'category' for update
Hibernate: update hibernate_sequences set sequence_next_hi_value = ? where sequence_next_hi_value = ? and sequence_name = 'category'
Hibernate: insert into category (location_id, category_id) values (?, ?)
最佳答案
事先:我不知道为什么 hibernate 在保存你的子记录时使用另一种策略。但我可能会给你一些关于你描述的其他问题的答案或提示:
关于策略GenerationType.TABLE
,您的应用程序依赖于生成ID的数据库功能。这可能会导致插入的每个新数据库记录都需要数据库往返。当使用像 hi-lo 这样的替代策略时,生成器将通过仅联系数据库一次来保留一堆 id(例如 100 或 1000)。这可能会大大提高性能。另一方面,当应用程序重新启动时,您可能会丢失一些ID。如果您可能面临这个问题,则应该考虑一下。
使用不依赖数据库产品的策略的另一个好处是,如果您切换数据库,您可以保留映射。
关于java - 为什么 Hibernate 使用序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22779313/