我试图创建一个简单的例子来理解基本和可嵌入类型的集合在Hibernate中是如何工作的。
我创建了一个User
实体,其中包含一组nickNames
和一组addresses
。这是我的Java类:
User.java
@Entity
@Table(name = "TB_User")
public class User {
@Id
@GeneratedValue
private int id;
private String name;
@ElementCollection
@CollectionTable(name = "Nicknames", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "nickname")
private Set<String> nickNames = new HashSet<String>();
@ElementCollection
@CollectionTable(name = "Addresses", joinColumns = @JoinColumn(name = "user_id"))
@AttributeOverrides({ @AttributeOverride(name = "street1", column = @Column(name = "fld_street")) })
public Set<Address> addresses = new HashSet<Address>();
public User() {
}
public User(String name, Address... addresses) {
this.name = name;
this.addresses.addAll(Arrays.asList(addresses));
}
public void addNickName(String... nickNames) {
this.nickNames.addAll(Arrays.asList(nickNames));
}
// Setters & Getters
}
Address.java
@Embeddable
public class Address {
private String street1;
public Address() {}
public Address(String street1) {
this.street1 = street1;
}
@Override
public String toString() {
return street1;
}
// Setters & Getters
}
现在我创建了一个简单的程序来在数据库中创建用户,然后显示用户列表。这是我的代码:
private static void saveUsers() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.getTransaction().begin();
User user = new User("User", new Address("abc"),
new Address("xyz"));
user1.addNickName("alpha", "beta");
session.save(user);
session.getTransaction().commit();
}
private static void showUsers() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.getTransaction().begin();
List<User> users = session.createQuery("from User").list();
for (User user : users) {
System.out.println(user.getName() + " -- > " + user.getNickNames()
+ " --> " + user.getAddresses());
}
session.getTransaction().commit();
}
当我运行这个程序时,我发现hibernate问题出现在以下命令集中:
Hibernate: select user0_.id as id1_2_, user0_.name as name2_2_ from TB_User user0_
Hibernate: select nicknames0_.user_id as user_id1_2_0_, nicknames0_.nickname as nickname2_1_0_ from Nicknames nicknames0_ where nicknames0_.user_id=?
Hibernate: select addresses0_.user_id as user_id1_2_0_, addresses0_.fld_street as fld_street2_0_0_ from Addresses addresses0_ where addresses0_.user_id=?
User -- > [alpha, beta] --> [xyz, abc]
Hibernate: delete from Addresses where user_id=?
Hibernate: insert into Addresses (user_id, fld_street) values (?, ?)
Hibernate: delete from Addresses where user_id=?
Hibernate: insert into Addresses (user_id, fld_street) values (?, ?)
如果我尝试在user.getAddresses()
中使用session
获取地址列表,则Hibernate将删除&amp;在Addresses
表中重新插入记录。
为什么hibernate会尝试删除并重新创建Addresses
表中的记录,因为这会导致性能问题。另外,为什么它不适用于我的示例中的nickNames
等基本类型,而不是为属性nickNames
运行更新命令?
答案 0 :(得分:1)
此行为与不双向映射这一事实有关。要深入理解 - 请阅读这篇文章:
以下是使用注释的方法:
让我引用答案:
我找到了答案。
mappedBy
注释的@OneToMany
属性与xml文件中的inverse = true相同。
一些总结:
Hibernate可以发出我们期望的SQL语句。但是,只有我们确实有双向映射。
然后,另一端(地址)将驱动持久性。它/ 必须了解其父级 - 以及为什么可以发布一些直接的UPDATE语句。
因此,如果我们想要避免DELETE和INSERT,我们必须使用逆映射。 Hibernate会发布更多&#34;可预期的&#34; SQL。
答案 1 :(得分:0)
这个很老,但可能与sombody有关。在我的案例中帮助的另一个提示:如果您可以将读取与写入分开,请考虑使用
@Transactional(readOnly = true)
这使得基础JPA框架知道当前事务中不会进行任何修改。实际上,当你只想获取一些数据时,Hibernate不再运行delete
+ insert
。