Home > OS >  jpa dirty checking not working in @SpringBootApplication
jpa dirty checking not working in @SpringBootApplication

Time:10-16

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.

  • Related