hguser
hguser

Reputation: 36068

Can not save/update entity using JPA in spring

I am using JPA in my application, and it works once I query for objects, however it throw error javax.persistence.TransactionRequiredException: No transactional EntityManager available once I tried to save or update an object.

This is the java configuration:

@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@PropertySource("classpath:dao.properties")
public class JpaConfig {
    @Autowired
    private Environment env;
    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        .....................
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        Properties jpaProperties = new Properties();
        jpaProperties.put("hibernate.dialect", ...........)

        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        entityManagerFactoryBean.setJpaProperties(jpaProperties);
        entityManagerFactoryBean.setPackagesToScan("com....");
        return entityManagerFactoryBean;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }
}

Note I use proxyTargetClass = true in the @EnableTransactionManagement, since I do not want to create the useless interfaces in my application.

And this is the concrete implemention of the dao:

@Transactional
@Repository
public abstract class AbstractJPADao<I, E> {
    @Autowired
    @PersistenceContext
    protected EntityManager entityManager;

    private Class<E> type;
    public AbstractJPADao() {
        type=....
    }

    @Override
    public Result<E> find(I id) {
        E e = entityManager.find(type, id);
        return Result.newInstance().setContent(e);
    }

    @Override
    public Result<E> find(Map<String, Object> condition) {
        Query q = entityManager.createQuery(".......));
        return Result.newInstance().setContent(q.getResultList());
    }

    @Override
    public E save(E element) {
        entityManager.persist(element);
        return element;
    }
    @Override
    public E update(E element) {
        entityManager.merge(element);
        return element;
    }

    @Override
    public void delete(E element) {
        entityManager.remove(element);
    }
}

@Repository
@Transactional
public class DepartmentDao extends AbstractJPADao<String, Department> {
    @Override
    protected String selectCause(Map<String, Object> condition) {
        return "";
    }
}

And the controller as the client of the dao:

@Controller
@RequestMapping("/api/deps")
public class DepartmentCtrl {
    @Autowired
    private DepartmentDao departmentDao;
    @RequestMapping(value = "", method = RequestMethod.POST)
    public Result create(@Valid Department department, BindingResult bindingResult) {
        if (!bindingResult.hasErrors()) {
            departmentDao.save(department);
            return Result.newInstance().setContent(department);
        }
        throw new RuntimeException("...");
    }
}

Is there anything wrong?


dao.properties:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/proj
jdbc.username=root
jdbc.password=

hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.hbm2ddl.auto=update
#hibernate.ejb.naming_strategy=true
hibernate.show_sql=true
hibernate.format_sql=true

Upvotes: 10

Views: 1895

Answers (2)

gipsy
gipsy

Reputation: 3859

Try renaming method transactionManager to txManager in the class JpaConfig

Autowiring goes by the name txManager

Edit

Also the framework could be expecting a no argument method for txManager. Can you try changing to

 @Bean
 public PlatformTransactionManager transactionManager() {
     JpaTransactionManager transactionManager = new JpaTransactionManager();
     transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
     return transactionManager;
 }

Upvotes: 4

Adrien Colson
Adrien Colson

Reputation: 648

As noticed Tiny, you have two annotations @Autowired and @PersistenceContext over the protected field of type EntityManager in AbstractJPADao. Try removing @Autowired. @PersistenceContext is enough to inject the EntityManager.

Upvotes: 1

Related Questions