Spring Data JPA: Fetching data from entity just after save() method

15,783

Solution 1

This might be a bit outdated, but I ran into the same issue and found that hibernate 2nd level cache was the issue.

Solution 2

The save() method may or may not write your changes to database immediately. If you want to commit the changes immediately, you will need to use T saveAndFlush(T entity) method.

Share:
15,783
Admin
Author by

Admin

Updated on June 05, 2022

Comments

  • Admin
    Admin almost 2 years

    I'm using Spring Data JPA with Hibernate JPA provider in my project. Inside my service I have a method, which saves an entity in database and than using returned object I try to fetch more details about this entity. As a result, details are not fetched. In logs I see only insert statement, without select for details.

    Here is my code:

    Configuration:

    @Configuration
    @Profile("test")
    @EnableJpaRepositories(basePackages = {"pl.lodz.uml.sonda.common.repositories"})
    @EnableTransactionManagement
    @PropertySource(value = "classpath:db.test.properties")
    public class PersistenceConfigTest {
      @Autowired
      private Environment env;
      @Value("classpath:sql/test-initialization.sql")
      private Resource sqlInitializationScript;
    
      @Bean
      public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
    
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));
    
        return dataSource;
      }
    
      @Bean
      public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    
        adapter.setShowSql(env.getProperty("hibernate.showSQL", Boolean.class));
        adapter.setGenerateDdl(env.getProperty("hibernate.hbm2ddl", Boolean.class));
    
        entityManagerFactory.setDataSource(dataSource());
        entityManagerFactory.setPackagesToScan("pl.lodz.uml.sonda.common.domains");
        entityManagerFactory.setJpaVendorAdapter(adapter);
    
        Properties properties = new Properties();
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
    
        entityManagerFactory.setJpaProperties(properties);
    
        return entityManagerFactory;
      }
    
      @Bean(name = "transactionManager")
      public PlatformTransactionManager platformTransactionManager() {
        EntityManagerFactory entityManagerFactory = entityManagerFactory().getObject();
        return new JpaTransactionManager(entityManagerFactory);
      }
    
      @Bean
      public DataSourceInitializer dataSourceInitializer() {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScript(sqlInitializationScript);
    
        DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDataSource(dataSource());
        initializer.setDatabasePopulator(populator);
        initializer.setEnabled(env.getProperty("db.initialization", Boolean.class));
    
        return initializer;
      }
    
      @Bean
      public ProbeService probeService() {
        return new ProbeServiceImpl();
      }
    }
    

    Service:

    @Service
    @Transactional
    public class ProbeServiceImpl implements ProbeService {
      @Autowired
      private ProbeRepository probeRepository;
    
      @Override
      public Probe saveProbe(Probe probe) {
        Probe saved = probeRepository.save(probe);
        saved.getGroup().getName();
    
        return saved;
      }
    }
    

    Simple test:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ActiveProfiles("test")
    @ContextConfiguration(classes = {PersistenceConfigTest.class})
    @Transactional
    @TransactionConfiguration(defaultRollback = true)
    @TestExecutionListeners({
      DependencyInjectionTestExecutionListener.class,
      DirtiesContextTestExecutionListener.class,
      TransactionalTestExecutionListener.class
    })
    public class ProbeServiceImplTest {
      @Autowired
      private ProbeService probeService;
    
      @Test
      public void test() {
        Probe probe = ProbeFixtures.generateProbeSample("Test one");
        probe.setGroup(ProbeFixtures.generateProbeGroupSample(1));
    
        Probe saved = probeService.saveProbe(probe);
        System.out.println("Group name: " + saved.getGroup().getName());
      }
    }
    

    Entities:

    @Entity
    @Table(name = "probes")
    public class Probe {
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      @Column(name = "probe_id")
      private long probeId;
    
      @Column(name = "probe_title", nullable = false)
      private String title;
    
      @Column(name = "probe_description", nullable = true)
      private String description;
    
      @ManyToOne(fetch = FetchType.EAGER)
      @JoinColumn(name = "probe_group_id", nullable = true)
      private ProbeGroup group;
    
      @OneToOne(fetch = FetchType.EAGER)
      @JoinColumn(name = "probe_image_id", nullable = true)
      private ProbeFile image;
    
      @Column(name = "probe_published_date", nullable = false)
      private Date published;
    
      @Column(name = "probe_last_updated_date", nullable = false)
      private Date updated;
    
      @Column(name = "probe_expire_date", nullable = false)
      private Date expires;
    
      @Column(name = "probe_is_active", nullable = false)
      private boolean isActive;
    
      @OneToMany(mappedBy = "probe", fetch = FetchType.LAZY)
      private List<Question> questions;
    
      @OneToMany(mappedBy = "probe", fetch = FetchType.LAZY)
      private List<Vote> votes;
    
      public Probe() {
        questions = new LinkedList<>();
        votes = new LinkedList<>();
      }
      // getters & setters ...
    
    
    @Entity
    @Table(name = "probe_groups")
    public class ProbeGroup {
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      @Column(name = "probe_group_id")
      private long probeGroupId;
    
      @Column(name = "probe_group_name", nullable = false, unique = true)
      private String name;
    
      @Column(name = "probe_group_description", nullable = true)
      private String description;
    
      @OneToMany(mappedBy = "group", fetch = FetchType.LAZY)
      private List<Probe> probes;
    
      public ProbeGroup() {
        probes = new LinkedList<>();
      }
      // getters & setters ...
    

    And few last logs lines:

    Hibernate: insert into probes (probe_description, probe_expire_date, probe_group_id, probe_image_id, probe_is_active, probe_published_date, probe_title, probe_last_updated_date) values (?, ?, ?, ?, ?, ?, ?, ?)
    Group name: null
    

    I also tried to run spring data jpa method - getOne(id) after save(), but also it does not work (insert statement invoked, select not);

    UPDATE: I removed @Transactional annotaion from my service and from test. Now when I'm saving an entity and then fetching the same entity, I have two sql statements in logs: insert and then select. Maybe my problem is because of wrong persistence/transaction configuration. What You think?