Issue
@file:Suppress("DuplicatedCode")
package test
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.data.repository.CrudRepository
import javax.annotation.PostConstruct
import javax.persistence.*
fun main(args: Array<String>)
{
runApplication<TestApplication>(*args)
}
@SpringBootApplication
class TestApplication(
val personRepository: PersonRepository,
val vehicleRepository: VehicleRepository
)
{
@PostConstruct
fun init()
{
var p1 = personRepository.save(Person(name = "Fred", age = 30))
println(" ")
p1.vehicles += vehicleRepository.save(Vehicle(type = "Car", brand = "BMW"))
personRepository.save(p1)
println(" ")
p1.vehicles += vehicleRepository.save(Vehicle(type = "Car", brand = "BMW"))
personRepository.save(p1)
println(" ")
p1.vehicles += vehicleRepository.save(Vehicle(type = "Car", brand = "BMW"))
personRepository.save(p1)
}
}
interface PersonRepository : CrudRepository<Person, Long>
interface VehicleRepository : CrudRepository<Vehicle, Long>
@Entity
data class Person(
@Id
@GeneratedValue
val id: Long = 0,
val name: String,
val age: Int,
@OneToMany
@OrderColumn
@JoinColumn(name = "personId")
val vehicles: MutableList<Vehicle> = ArrayList()
)
@Entity
data class Vehicle(
@Id
@GeneratedValue
val id: Long = 0,
var type: String,
var brand: String
)
Log
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into person (age, name, id) values (?, ?, ?)
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into vehicle (brand, type, id) values (?, ?, ?)
Hibernate: select [...]
Hibernate: select [...]
Hibernate: update vehicle set person_id=?, vehicles_order=? where id=?
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into vehicle (brand, type, id) values (?, ?, ?)
Hibernate: select [...]
Hibernate: select [...]
Hibernate: update vehicle set person_id=?, vehicles_order=? where id=?
Hibernate: update vehicle set person_id=?, vehicles_order=? where id=?
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into vehicle (brand, type, id) values (?, ?, ?)
Hibernate: select [...]
Hibernate: select [...]
Hibernate: update vehicle set person_id=?, vehicles_order=? where id=?
Hibernate: update vehicle set person_id=?, vehicles_order=? where id=?
Hibernate: update vehicle set person_id=?, vehicles_order=? where id=?
Question
Each car that is added, hibernate is updating all the other cars again. I noticed that if I change personRepository.save(p1)
to p1 = personRepository.save(p1)
, it works as expected and only updates the new car. Why is that? Does hibernate has some internal "commit id"?
Also, how could I transform this code into a transaction?
Thanks.
Solution
Each call to save
is calling EntityManager#merge
which flushes the current object state to the database, possibly returning you a new object which is then "managed" meaning that changes done to that object will be flushed at the end of the transaction automatically. You can run that code in a transaction by using the @Transactional
annotation, but not sure if that also works for @PostConstruct
. Within the transaction, every object that you save
is managed, so the changes are flushed at the end of the transaction automatically. You could use code like the following:
@PostConstruct
@Transactional
fun init()
{
var p1 = personRepository.save(Person(name = "Fred", age = 30))
p1.vehicles += vehicleRepository.save(Vehicle(type = "Car", brand = "BMW"))
p1.vehicles += vehicleRepository.save(Vehicle(type = "Car", brand = "BMW"))
p1.vehicles += vehicleRepository.save(Vehicle(type = "Car", brand = "BMW"))
}
Answered By - Christian Beikov
Answer Checked By - Katrina (JavaFixing Volunteer)