Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving entity in repository does not work SPRING

I'm trying to save entity in repository but it does not work at all. Repository is Autowired and in runtime I use saveAndFlush to save entity. I'm using PostgreSQL. Above test methods I added comments with explanation what is going on. I expected that method saveAndFlush should work but it did not. I can not find why.

@Transactional
public class TestClass{

    @Autowired private MyRepository repository;
    @Autowired private EntityManager entityManager;

    // Working version
    public void writingToRepositoryWorking() {
        entityManager.getTransaction().begin();
        entityManager.persist(new MyData(99));
        entityManager.getTransaction().commit();

    }

    // not working and throws exception : 
    // TransactionRequiredException: no transaction is in progress
    public void writingToRepositoryNotWorking() {
        repository.saveAndFlush(new MyData(99));
    }

    // not working, no exception, no data in repository, 
    // but auto generated ID is incremented
    public void writingToRepositoryNotWorkingToo() {
        repository.save(new MyData(99));
    }
}

repository interface file

@Repository
@Transactional
public interface MyRepository extends JpaRepository<MyData, Long> {}

MyData file

@Entity(name = "myData")
public class MyData {
    @Id @GeneratedValue(strategy = GenerationType.AUTO) long id;

    private int testValue;

    public MyData() { }

    public BugData(int testValue) {
        this.testValue = testValue;
    }

    public long getId() {
        return id;
    }

    public int getTestValue() {
        return testValue;
    }
}

ApplicationConfiguration file

@Configuration
@EnableJpaRepositories("com.mypackage.app")
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
@EnableWebMvc
class ApplicationConfiguration extends WebMvcConfigurationSupport {

    @Value("${jdbc.url}") private String KEY_JDBC_URL;

    @Value("${jdbc.username}") private String KEY_JDBC_USERNAME;

    @Value("${jdbc.password}") private String KEY_JDBC_PASSWORD;

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    @Autowired
    public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
        LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setPackagesToScan("com.mypackage.app");
        factory.setHibernateProperties(hibernateProperties());
        return factory;
    }

    public Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        return properties;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        return new HibernateTransactionManager(sessionFactory);
    }

    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl(KEY_JDBC_URL);
        dataSource.setUsername(KEY_JDBC_USERNAME);
        dataSource.setPassword(KEY_JDBC_PASSWORD);
        return dataSource;
    }

    @Bean
    public EntityManagerFactory  entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();

        em.setDataSource(dataSource());
        em.setPackagesToScan("com.mypackage.app");
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        em.setJpaProperties(hibernateProperties());
        em.afterPropertiesSet();

        return em.getObject();
    }

    @Bean
    public EntityManager entityManager(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }

    ...
}
like image 212
Marcin Lagowski Avatar asked May 08 '15 11:05

Marcin Lagowski


People also ask

How do I save a JPA Repository?

Spring Data JPA CrudRepository - save() Method In this tutorial, we will learn how to use the Spring Data CrudRepository interface provided save() method with an example. As the name depicts, the save() method allows us to save an entity to the DB. It belongs to the CrudRepository interface defined by Spring Data.

How can we save entity in JPA without primary key?

Sometimes your object or table has no primary key. The best solution in this case is normally to add a generated id to the object and table. If you do not have this option, sometimes there is a column or set of columns in the table that make up a unique value. You can use this unique set of columns as your id in JPA.

What type of request is used to call the Save method from the JPA CRUD Repository?

Saving an entity can be performed via the CrudRepository. save(…) -Method. It will persist or merge the given entity using the underlying JPA EntityManager .

Why doesn't repository save have createdby and createddate in it?

Unfortunately, when I call repository.save () to update an existing entity the object returned does not have the createdBy and createdDate set. All the fields are set correctly in the database though This behavior is not caused by the auditing feature setting values or not. You are essentially resetting the fields to null.

What is the use of save method in spring?

The save () Method As the name depicts, the save () method allows us to save an entity to the DB. It belongs to the CrudRepository interface defined by Spring Data. Let's see how we can use it: Normally, Hibernate holds the persistable state in memory.

How to save an entity to the DB using JPA?

As a first step, let's create an entity class: Next, let's create a JPA repository for the CRUD operations on the Employee entity class: 3. The save () Method As the name depicts, the save () method allows us to save an entity to the DB. It belongs to the CrudRepository interface defined by Spring Data. Let's see how we can use it:

Can I use the instance returned by the save operation?

Use the returned instance for further operations as the save operation might have changed the entity instance completely. Sorry, something went wrong. If I used the instance returned by the save operation then I would be using an instance that does not have the created fields that exist on the resource in the repository.


1 Answers

For starter, you're actually working on 2 different EntityManager in your non-working test case:

  1. EntityManager autowired into your test by Spring (this one is singleton and should be avoided anyway) ,other is
  2. EntityManager created by the EntityManagerFactory configured in your ApplicationConfiguration.

At the same time, you also have another Session running along side the aforementioned 2 EntityManagers due to your configuration of Hibernate SessionFactory. Additionally, because of the configured HibernateTransactionManager, all transactions created by @Transactional are bound to the Hibernate's Session created by SessionFactory and the EntityManager used by your Repository certainly has no way to know about it. This is why TransactionRequiredException was thrown when your Repository tried to persist data.

To fix it, you may consider removing the Hibernate's SessionFactory and switch the transaction manager to a JpaTransactionManager. Then, @Transactional on your Repository will have the effect of creating a new transaction and binding it to the existing EntityManager that is known to Spring.

One side note is that the @Transactional on your TestClass doesn't help at all as the instance of this class is not instantiated and managed by Spring. To make this work, a proper configuration of transactional test class needs to be provided as described here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html.

Hope this helps.

like image 118
Phoenix VN Avatar answered Oct 09 '22 17:10

Phoenix VN