I have a Spring 4.3 Application with simple configuration and I expect my methods from service classes to be transactional so I enable transaction management in my configuration and then annotate my service methods with #Transactional. I call service methods from my controlles but they don't behave as expected. When some part of a method throws exception rollback is never called
AppInitializer.class:
#EnableTransactionManagement
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebConfig.class};
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class, SecurityConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
RootConfig.class:
#Configuration
#EnableJpaRepositories(basePackages"package.repository"})
public class RootConfig {
#Bean
public DataSource dataSource() {
...
return dataSource;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
...
return hibernateJpaVendorAdapter;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
...
return factory.getObject();
}
#Bean
public JpaTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
Does anybody have idea what is wrong here
GitHub link https://github.com/VadOs1/TRANSACTIONAL-ISSUE/
Thanks
can you remove the #EnableTransactionManagement annotation from the AppInitializer class and enable it in RootConfig class and let me know if this worked for you
ie
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages"package.repository"})
public class RootConfig {
#Bean
public DataSource dataSource() {
...
return dataSource;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
...
return hibernateJpaVendorAdapter;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
...
return factory.getObject();
}
#Bean
public JpaTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
Related
I'm trying to send requests to my RestController, but it's not working, i have
#RestController
#RequestMapping(
value = "/cursos",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE,
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public class CursoRestController {
#Autowired
private CursoService cursoService;
#GetMapping
#ResponseStatus(HttpStatus.OK)
public List<Curso> listAll() {
System.out.println("Test");
return cursoService.findAll();
}
#PostMapping
public ResponseEntity<Void> save(#RequestBody Curso curso) {
cursoService.save(curso);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(curso.getId()).toUri();
return ResponseEntity.created(location).build();
}
I'm using Postman to send request, and when i send some request i get 400 error code, with no message or something to tell to me, what's happing, BUT when i try to open the same URL on the browser, I GET THE RESPONSE, i don't if i configured something wrong, i'm using theses classes to config my project
SpringRootConfig
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("br.com.gabriel.restful")
public class SpringRootConfig {
}
SpringInitConfig
public class SpringInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringRootConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[0];
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
SpringJpaConfig
#Configuration
public class SpringJpaConfig {
#Bean
public DataSource dataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUrl("jdbc:postgresql://localhost:5432/wildbuild");
ds.setUsername("postgres");
ds.setPassword("admin");
return ds;
}
#Bean
public EntityManagerFactory entityManagerFactory(){
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setPackagesToScan("br.com.gabriel.restful.domain");
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.setJpaProperties(jpaProperties());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public JpaTransactionManager jpaTransactionManager(){
JpaTransactionManager manager = new JpaTransactionManager();
manager.setEntityManagerFactory(entityManagerFactory());
manager.setJpaDialect(new HibernateJpaDialect());
return manager;
}
private Properties jpaProperties(){
Properties props = new Properties();
props.setProperty("hibernate.show_sql", "true");
props.setProperty("hibernate.hbm2ddl.auto", "update");
return props;
}
}
My project have this structure:
project structure
I having a configuration problem that cause the error below. I know there are a tons of similar problem but I read a lot of answer that stackoverflow suggest with my title but I don't find the right answer yet.
Description:
Field collaborateurJpaRepository in com...infrastructure.persistence.user.UserRepositoryImpl required a bean of type 'com...infrastructure.persistence.jurisdiction.CollaborateurJpaRepository' that could not be found.
Action:
Consider defining a bean of type 'com...infrastructure.persistence.jurisdiction.CollaborateurJpaRepository' in your configuration.
Before to give some details of the code, I think it could be nice that I describe you brievly the context.
I work on a client project which has 8 maven modules (DDD methods) because at the end of the year 4 modules will be separate in an other server.
Recently we create a second oracle database so I had to create multiple configuration to refer to the good dataSource.
I think the problem is due to bad datasource configuration that block the bean spring instanciation.
We are using spring boot version 1.5.7.release.
First Infrastructure configuration
#Configuration
#ComponentScan(basePackages = "com...jade")
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "jadeEntityManager", transactionManagerRef = "jadeTransactionManager")
#EntityScan(basePackages = { "com...jade", "org.springframework.data.jpa.convert.threeten" })
#Profile({"ARA_JADE_CONF", "LOCAL_JADE_CONF"})
public class InfrastructureConfig {
private final static int JDBC_FETCH_SIZE = 1000;
#Autowired
private Environment environment;
#Bean
public LocalContainerEntityManagerFactoryBean jadeEntityManager() throws SQLException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSourceJade());
em.setPackagesToScan(new String[] {"com...jade"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
#Primary
public OracleDataSource dataSourceJade() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setUser(environment.getProperty("db.datasource.jade.username"));
dataSource.setPassword(environment.getProperty("db.datasource.jade.password"));
dataSource.setURL(environment.getProperty("db.datasource.jade.url"));
dataSource.setImplicitCachingEnabled(true);
dataSource.setFastConnectionFailoverEnabled(true);
return dataSource;
}
#Bean(name="jdbcTemplateJade")
public JdbcTemplate jdbcTemplateJade() throws SQLException {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceJade());
jdbcTemplate.setResultsMapCaseInsensitive(true);
jdbcTemplate.setFetchSize(JDBC_FETCH_SIZE);
return jdbcTemplate;
}
#Bean
public PlatformTransactionManager transactionManager() throws SQLException{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(jadeEntityManager().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
} ...
Seconde Infrastructure configuration
#Configuration
#ComponentScan(basePackages = "com.bnpparibas.sit.risk.art")
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "artEntityManager", transactionManagerRef = "artTransactionManager")
#EntityScan(basePackages = { "com...art", "org.springframework.data.jpa.convert.threeten" })
#Profile({"LOCAL_ART_CONF,'ARA_ART_CONF"})
public class ArtInfrastructureConfig {
private final static int JDBC_FETCH_SIZE = 1000;
#Autowired
private Environment environment;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean artEntityManager() throws SQLException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSourceArt());
em.setPackagesToScan(new String[] {"com...art.infrastructure.persistence"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
#Primary
public OracleDataSource dataSourceArt() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setUser(environment.getProperty("db.datasource.art.username"));
dataSource.setPassword(environment.getProperty("db.datasource.art.password"));
dataSource.setURL(environment.getProperty("db.datasource.art.url"));
dataSource.setImplicitCachingEnabled(true);
dataSource.setFastConnectionFailoverEnabled(true);
return dataSource;
}
#Bean
#Primary
public PlatformTransactionManager artTransactionManager()throws SQLException{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(artEntityManager().getObject());
return transactionManager;
}
#Bean
#Primary
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}...
Interface link to Entity.
#DDD.Repository
#Repository
public interface CollaborateurJpaRepository extends CrudRepository<Collaborateur,String>{
#Query("FROM ART_PARAM.ART_USER u WHERE u.refogUID = :uid")
Collaborateur findCollaborateurById(#Param("uid") String uid);
}
Class that contain the autowired interface to retrieve some data of the second database.
#DDD.RepositoryImpl
#Repository
#Primary
public class UserRepositoryImpl implements UserRepository {
#Autowired
private CollaborateurJpaRepository collaborateurJpaRepository;
#Override
//#Cacheable(cacheNames = CacheConfig.CACHE_JURIDICTION, key = CacheConfig.CACHE_KEY_UTILISATEUR_ID)
#Transactional("entityManagerFactoryArt")
public User retrieveUser(UserId userId) {
if(userId.getValue() == null) {
return null;
} else {
Collaborateur collaborateur = collaborateurJpaRepository.findOne(userId.getValue());
return new User(collaborateur.getRefogUID(),collaborateur.getRefogFirstName(),collaborateur.getRefogLastName(),collaborateur.getProfile(),collaborateur.isActiveUser(),collaborateur.isBankingSecrecy());
}
}
I want to use Playframework 2.5 together with Spring and JPA. I found the following template https://github.com/jamesward/play-java-spring where it works perfectly, unfortunately it’s not for Playframework 2.5. So I decided to adapt this template and create my own one for Playframework 2.5. However, my entitymanager in my controller Application is still null. What am I doing wrong? My code looks like the following:
AppConfig.java
package config;
#Configuration
#ComponentScan({"daos","services","controllers","models"})
public class AppConfig {
}
DataConfig.java
package config;
#Configuration
#EnableTransactionManagement
public class DataConfig
{
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPackagesToScan("models");
entityManagerFactory.setJpaVendorAdapter(vendorAdapter);
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setJpaPropertyMap(new HashMap<String, String>(){{
put("hibernate.hbm2ddl.auto", "create-drop");
put("hibernate.dialect","org.hibernate.dialect.PostgreSQLDialect");
}});
entityManagerFactory.afterPropertiesSet();
return entityManagerFactory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory());
return transactionManager;
}
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
return dataSource;
}
}
Global.java
package config;
#Singleton
#Configuration
public class Global
{
private ConfigurableApplicationContext context;
#Inject
public Global(ApplicationLifecycle lifecyle)
{
this.context = new AnnotationConfigApplicationContext(AppConfig.class, DataConfig.class);
lifecyle.addStopHook(()-> {
context.close();
return CompletableFuture.completedFuture(null);
});
}
}
Application.java
package controllers;
#Controller
#Transactional
#Component
public class Application extends play.mvc.Controller
{
#PersistenceContext
private EntityManager em;
#Transactional
public Result index()
{
System.out.println("******************* EM " + this.em +" *************************");
return ok(index.render());
}
}
Thank you for your help!
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
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;
}
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.
I have a standalone application in which I am trying to populate a database.
My application config looks like:
#Configuration
#EnableTransactionManagement
#PropertySource(value = { "classpath:classpath property file" })
#ComponentScan(basePackages = { my packages to scan })
public class PersistenceJPAConfig {
#Bean
public EntityManagerFactory entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { packages to scan});
JpaVendorAdapter vendorAdapter = jpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
em.afterPropertiesSet();
return em.getObject();
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.ORACLE);
return jpaVendorAdapter;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl(url);
dataSource.setUsername(dbUser);
dataSource.setPassword(dbPassword);
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
return new Properties() {
{ // Hibernate Specific:
setProperty("hibernate.hbm2ddl.auto", "validate");
setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
}
};
}
}
However when I am trying to persist something in database, the annotation is failing with error:
Exception in thread "main" javax.persistence.TransactionRequiredException: No transactional EntityManager available
In the resulting error stack, I don't see the transactional advice being applied.
The file that contains transactional annotation is something like this:
import org.springframework.transaction.annotation.Transactional;
#Service
public class MyService {
#Autowired
private MyDao myDao;
#Transactional
public void save(MyEntity e) {
myDao.save(e);
}
}
The MyDao class is something like this:
#Repository
public class MyDao {
#PersistenceContext
private EntityManager entityManager;
public void save(MyEntity e) {
entityManager.persist(e);
}
}
I am calling the function from my Main method as follows:
public static void main(String[] args) {
try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
ctx.scan(CONFIG_PACKAGE);
ctx.refresh();
myService = ctx.getBean(MyService.class);
Thread.sleep(10 * 1000);
myService.save(entity);
...
}
Stack trace looks something like this(edited to remove too specific traces pertaining to my code):
Exception in thread "main" javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:275)
at com.sun.proxy.$Proxy27.persist(Unknown Source)
at mypackage.MyDao.save(MyDao.java:42)
at mypackage.MyDao$$FastClassBySpringCGLIB$$758201c8.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at mypackage.MyDao$$EnhancerBySpringCGLIB$$9bd3b4fc.save(<generated>)
at mypackage.MyService.save(MyService.java:176)
at mypackage.MyService$$FastClassBySpringCGLIB$$5c0a03f6.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:649)
at mypackage.Run.main(Run.java:109)
Can anyone please help me with this, i.e. what I might be doing wrong?
Thanks for your help
You need to add #EnableJpaRepositories(basePackages = "base package") annotation in the configuration class.