I'm trying to refactor existing spring boot application kotlin so there are following entities:
@Entity
data class MainEntity(
@Id
val uuid: UUID = UUID.randomUUID(),
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = [CascadeType.ALL], mappedBy = "mainEntity")
val nestedEntities: List<NestedEntity>,
@CreatedDate
val createdDate: Date = Date(),
@CreatedBy
val createdBy: String,
// other fields
) {// some methods}
@Entity
class NestedEntity(
@Id
val uuid: UUID = UUID.randomUUID(),
@ManyToOne
val mainEntity: MainEntity,
@OneToMany(mappedBy = "nestedEntity", fetch = FetchType.EAGER)
val auxiliaryEntities: List<AuxiliaryEntity> = listOf(),
// other fields
) {// some methods}
@Entity
class AuxiliaryEntity(
@Id
val uuid: UUID = UUID.randomUUID(),
@ManyToOne(fetch = FetchType.EAGER)
val nestedEntity: NestedEntity,
// other fields
) {// some methods}
And then i have two controllers which call same service method, but their calls have completely different results:
@RestController
class StuffController(
val nestedEnityRepo: NestedEnityRepo,
val auxiliaryService: AuxiliaryService
) {
@PostMapping("/api/v1/one/do-stuff")
fun proceed(@RequestBody auxiliaryDtos: List<AuxiliaryDto>) {
auxiliaryDtos.forEach {
val nestedEntity = nestedEnityRepo.findById(it.nestedEntityUuid)
// some checks performed over nestedEntity
auxiliaryService.doStuff(setOf(AuxiliaryEntity(nestedEnity = nestedEnity)))
}
}
}
@RestController
class AdminDoStuffController(
val nestedEnityRepo: NestedEnityRepo,
val auxiliaryService: AuxiliaryService
) {
@PostMapping("/api/v1/admin/do-stuff")
@Transactional
fun proceed(@RequestBody auxiliaryDtos: List<AuxiliaryDto>) {
auxiliaryDtos.forEach {
val nestedEntity = nestedEnityRepo.findById(it.nestedEntityUuid)
// some checks performed over nestedEntity
auxiliaryService.doStuff(setOf(AuxiliaryEntity(nestedEnity = nestedEnity)))
}
}
}
and service
@Service
class AuxiliaryService(
private val auxiliaryRepository: AuxiliaryRepository
) {
fun doStuff(auxiliaryEntities: Set<AuxiliaryEntity>) {
val byMainEntity = auxiliaryEntities.groupBy { it.nestedEntity.mainEntity }
byMainEntity.forEach {
// some business logic
auxiliaryRepository.saveAll(it.value)
}
}
}
The first thing confuses me is fact that call to AdminDoStuffController.doStuff (has @Transactional) makes hibernate persist all changes done to auxiliaryEntity, mainEntity, nestedEntity while call to StuffController.doStuff (hasn't @Transactional) persists only changes done to auxiliaryEntity and not to mainEntity, nestedEntity.
As an experiment i moved @Transactional to service AuxiliaryService.doStuff, so calls to both controllers stopped persisting changes done to mainEntity, nestedEntity. When i have @Transactional on both controllers methods, both calls make hibernate persist all changes for all entities.
The second thing - main class of spring boot application don't have @EnableTransactionManagement
Can someone, please, enlighten me about this behavior.