samshers
samshers

Reputation: 3690

Hibernate does a select prior to insert. Is this intended behaviour and if so what is the purpose?

I am recreating the database using - spring.jpa.hibernate.ddl-auto=create ( am using a spring boot jpa project). So hibernate is droping the earlier tables and recreating new one's as expected. In this post, to distinguish
hibernate output
and

java code

i am using above convention.

Hibernate is querying and tyring to alter existing schema as below -

 alter table state 
        drop 
        foreign key FKcdpxn6x9xj5h0r44m8poebva0

... and so on

drop table if exists state

and after droping the constrains and the tables - it's recreating the tables and constrains..

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)
)

... creating few more tables and then the constraints...

 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)

so far so good... next there is an insert operation in java code...

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

my problem is here. Prior to inserting, hibernate is doing a select statement...

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]

Next Hibernate is doing the actual insert...

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]

So, am wondering what is the purpose of querying the tables prior to inserting.

Update/Edit - as asked on comments, java model code is below.

@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

Upvotes: 1

Views: 1210

Answers (1)

Nosairat
Nosairat

Reputation: 502

Hibernate does that because you specified the value of the primary key (which is in your case the country name), So this behavior helps hibernate to determine what action to do, i.e insert a new record, or update an existing record

To avoid this behavior, you can use the optimistic locking by adding the @javax.persistence.Version to your entity, like this:

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

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

    @Version
    Integer version;

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

The first time you create the record and prior to inserting it into DB, the value of the version will be null.

If the version value is null, so hibernate marks the record as new and insert statement will be executed, otherwise and if it has a value, that means it's an existing record, and update statement will be executed

Upvotes: 1

Related Questions