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();
}
...
}
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.
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.
Saving an entity can be performed via the CrudRepository. save(…) -Method. It will persist or merge the given entity using the underlying JPA EntityManager .
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.
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.
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:
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.
For starter, you're actually working on 2 different EntityManager
in your non-working test case:
EntityManager
autowired into your test by Spring (this one is singleton and should be avoided anyway) ,other isEntityManager
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With