jpa dirty checking not working in @SpringBootApplication
I use initDb in @SpringBootApplication like this
@SpringBootApplication
@EnableJpaAuditing
@EnableScheduling
@RequiredArgsConstructor
public class main {
private final PoiRepository poiRepository;
private final PoiCategoryRepository poiCategoryRepository;
public static void main(String[] args) {
SpringApplication.run(main.class, args);
}
//Dummy data poiCategory
@Bean
@Profile("local")
@Transactional
public CommandLineRunner createPoiCategory(PoiCategoryRepository repository) {
return args -> {
if (repository.findAll().size() == 0) {
PoiCategory parent = repository.save(PoiCategory.builder()
.name("parent")
.imageFileName("test")
.build());
PoiCategory child = repository.save(PoiCategory.builder()
.name("child")
.imageFileName("test2")
.build());
parent.addChildCategory(child);
System.out.println("parent = " parent);
parent.setImageFileName("1234");
System.out.println("parent.getImageFileName() = " parent.getImageFileName());
}
};
}
}
parent.addChildCategory(parent) and parent.setImageFileName("1234") is not changed
but if I use
repository.save(parent);
repository.save(child);
then parent and child will update
why jpa's dirty checking and update is not work?
CodePudding user response:
It is because @Tranasctional
does not work if you declare it on the @Bean
method. It should be annotated on the actual method you want to be executed. So your codes now actually will not have any transaction wrapped around CommandLineRunner#run()
and dirty checking only works if the entities are modified within a transaction.
Changing to the following should solve your problem :
public class MyCommandLineRunner implements CommandLineRunner {
private PoiCategoryRepository poiCategoryRepository;
public MyCommandLineRunner(PoiCategoryRepository poiCategoryRepository) {
this.poiCategoryRepository = poiCategoryRepository;
}
@Transactional
@Override
public void run(String... args) throws Exception {
// put your codes that you want to execute within a transaction here....
}
}
And define the MyCommandLineRunner
bean :
@Bean
public MyCommandLineRunner myCommandLineRunner(PoiCategoryRepository poiCategoryRepository) {
return new MyCommandLineRunner(poiCategoryRepository);
}
It will update the parent and the child now if you call save()
on the JpaRepository
simply because the implementation already had @Tranasctional
annotated on this method.