【问题标题】:Hibernate does a select prior to insert. Is this intended behaviour and if so what is the purpose?Hibernate 在插入之前进行选择。这是预期的行为吗?如果是,目的是什么?
【发布时间】:2020-01-10 11:31:40
【问题描述】:

我正在使用 - spring.jpa.hibernate.ddl-auto=create(我正在使用 spring boot jpa 项目)。 因此,hibernate 正在删除早期的表并按预期重新创建新的表。在本帖中,区分
hibernate output

java code

我正在使用上述约定。

Hibernate 正在查询并尝试更改现有架构,如下所示 -

 alter table state 
        drop 
        foreign key FKcdpxn6x9xj5h0r44m8poebva0

...等等

drop table if exists state

在删除约束和表格之后 - 它正在重新创建表格和约束..

2019-09-08 13:14:05.794 DEBUG 5016 --- [  restartedMain] org.hibernate.SQL                        : 
create table state (
    name varchar(255) not null,
    population varchar(255),
    country_name varchar(255),
    primary key (name)
)

...创建更多的表,然后是约束...

 2019-09-08 13:14:08.355 DEBUG 5016 --- [  restartedMain] org.hibernate.SQL                        : 
    alter table state 
        add constraint FKcdpxn6x9xj5h0r44m8poebva0 
        foreign key (country_name) 
        references country (name)

到目前为止一切顺利...接下来是java代码中的插入操作...

Country usa = new Country ("USA", "330000000"); countryRepository.save(usa);

我的问题就在这里。在插入之前,hibernate正在做一个select语句...

2019-09-08 13:14:10.915 DEBUG 5016 --- [  restartedMain] org.hibernate.SQL                        : 
    select
        country0_.name as name1_1_1_,
        country0_.population as populati2_1_1_,
        states1_.country_name as country_3_2_3_,
        states1_.name as name1_2_3_,
        states1_.name as name1_2_0_,
        states1_.country_name as country_3_2_0_,
        states1_.population as populati2_2_0_ 
    from
        country country0_ 
    left outer join
        state states1_ 
            on country0_.name=states1_.country_name 
    where
        country0_.name=?
2019-09-08 13:14:10.915 TRACE 5016 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [USA]

下一个 Hibernate 正在执行实际的插入...

2019-09-08 13:14:11.552 DEBUG 5016 --- [  restartedMain] org.hibernate.SQL                        : 
    insert 
    into
        country
        (population, name) 
    values
        (?, ?)
2019-09-08 13:14:11.553 TRACE 5016 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [330000000]

所以,我想知道在插入之前查询表的目的是什么。

更新/编辑 - 按照 cmets 的要求,java 模型代码如下。

@Table(name="state")
@Entity
public class State {

    @Id
    @Column(name="name")
    String name;
    @Column(name="population") 
    String population;  

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="state_name")
    List<City> cities;

    @ManyToOne (cascade=CascadeType.ALL, fetch=FetchType.LAZY) 
    Country country; 
    getters / setters


@Table(name="country")
@Entity
public class Country {

    @Id
    @Column(name="name")
    String name;

    @Column(name="population")
    String population;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="country_name")
    List<State> states;

     getters/setters

【问题讨论】:

  • 猜测:检查值是否已经存在以避免违反主键的唯一性
  • 是的,但是插入无论如何都会失败...那何必呢。接下来,为什么要查询指向country 表的表。查询state 表有什么意义。
  • 您没有提供任何 JAVA 代码。我们无法看到您的对象是如何映射到表格的。
  • 如果是更新,那么查询state 是有意义的,因为它必须确保现有关系不会中断。
  • @LukaszSzozda,型号代码已更新

标签: java mysql hibernate orm spring-data-jpa


【解决方案1】:

Hibernate 这样做是因为您指定了主键的值(在您的情况下是国家名称),因此这种行为有助于 hibernate 确定要执行的操作,即插入新记录或更新现有记录

为避免这种行为,您可以通过将@javax.persistence.Version 添加到您的实体来使用乐观锁定,如下所示:

@Table(name="country")
@Entity
public class Country {

    @Id
    @Column(name="name")
    String name;

    @Version
    Integer version;

    @Column(name="population")
    String population;

第一次创建记录并在将其插入数据库之前,版本的值将为空。

如果version值为null,则hibernate将记录标记为new并执行insert语句,否则如果有值,则表示它是现有记录,执行update语句

【讨论】:

  • “因为你指定了主键的值”,你的意思是如果这是自动生成的,那么选择不会执行。
  • 是的,有自动生成的值,不会被执行
  • Nosairat,正在重新检查我之前的 Q,发现我忘记投票了,这方面的 Q 很少,但稍后会发布。发送。
猜你喜欢
  • 2017-09-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多