Java 为什么hibernate对可存储对象运行删除和插入命令

Java 为什么hibernate对可存储对象运行删除和插入命令,java,hibernate,Java,Hibernate,我试图创建一个简单的示例来理解基本类型和可存储类型的集合在Hibernate中是如何工作的 我创建了一个用户实体,其中有一组昵称,还有一组地址。以下是我的Java类: User.java @Entity @Table(name = "TB_User") public class User { @Id @GeneratedValue private int id; private String name; @ElementCollection @Co

我试图创建一个简单的示例来理解基本类型和可存储类型的集合在Hibernate中是如何工作的

我创建了一个
用户
实体,其中有一组
昵称
,还有一组
地址
。以下是我的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
}
@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();
}
如果我尝试使用
会话中的
用户.getAddresses()
获取地址列表,则Hibernate会删除并重新插入
地址表中的记录


为什么hibernate尝试删除并重新创建
地址表中的记录,因为这会导致性能问题。另外,为什么它不适用于基本类型,如我的示例中的
昵称
,以及不为属性
昵称
运行更新命令?

此行为与存在双向映射这一事实有关。要深入了解这一点,请阅读本文:

下面是如何使用注释实现这一点的方法:

让我从答案中引述:

我找到了答案。
@OneToMany
注释的
mappedBy
属性在xml文件中的行为与inverse=true相同

一些总结:

Hibernate可以发出我们期望的SQL语句。但只有在双向映射到位的情况下

然后,另一端(地址)将驱动持久性。它将/必须了解它的父级-这就是为什么可以发布一些直接更新语句的原因


因此,如果我们想避免删除和插入,我们必须使用逆映射。Hibernate将发布更多“可预期”的SQL

这一个很老,但可能与躯体有关。另一个帮助我的例子:如果你可以把读和写分开,考虑使用< /P>
@Transactional(readOnly = true)

这使得底层JPA框架知道当前事务中不需要修改。实际上,当您只想获取一些数据时,Hibernate不再运行
delete
+
insert

因为我使用
地址
作为
@embeddeble
我想我不能使用
@OneToMany/@manytone
。因此,这意味着hibernate无法使用
update
命令,因为
Address
没有任何标识符,因此它正在删除和重新插入记录。我的理解正确吗?这意味着如果我们想使用可嵌入的集合,就无法控制生成的SQL。你完全明白了。优化此处生成的SQL的唯一方法是双向映射。如果这是@embeddeble。。。没有办法确定。(如果我们仔细想想,这是合乎逻辑的)。。。对不起,我没有“答案”。。。但希望能有所帮助;)
@Transactional(readOnly = true)