No transactional EntityManager available even though one is configured - spring

I'm attempting to transactionally interact with my MySQL database through JPA and Spring data.
config
#Configuration
#EnableJpaRepositories("com.some.models.repositories")
#EnableTransactionManagement
public class MegabotsConfiguration {
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setJpaProperties(additionalProperties());
factory.setPackagesToScan(new String[] { "com.datarank.megabots.models.entities", "com.datarank.megabots.models.repositories" });
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/local_ttaggdb");
dataSource.setUsername( "root" );
dataSource.setPassword( "" );
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
//...
}
And here's where I'm attempting to use a transaction:
#Repository
#Scope("prototype")
#Transactional
public class BotWorkQueueRepository {
#Autowired
private BotWorkQueueJPARepository botWorkQueueJPARepository; //this is the jparepository referenced in the #EnableJpaRepositories in config
#PersistenceContext
private EntityManager entityManager;
#Transactional
public synchronized void flagInFlight(final List<BotWorkQueueEntity> botWorkQueueEntities) {
try {
//...set a few properties on entities, then
entityManager.flush(); //Exception thrown here
entityManager.clear();
} catch (Exception e) {
LOGGER.warn("Error making in flight: " + e);
}
}
}
The error I'm getting:
javax.persistence.TransactionRequiredException: No transactional EntityManager available
I've tried most of the solutions for this error posted in SO, with no success.

One thing for starter,
In maven, if you are using the appassembler-maven-plugin, add the following line to your plugin.configuration tag in the POM file.
<extraJvmArguments>-javaagent:"$REPO"/org/aspectj/aspectjweaver/1.8.5/aspectjweaver-1.8.5.jar</extraJvmArguments>
If you are running in an IDE add the following line to your VM arguments.
-javaagent:<PATH TO MAVEN REPO>/org/aspectj/aspectjweaver/1.8.5/aspectjweaver-1.8.5.jar
Where path to maven repo may look something like /User/kenny/.m2/repository/.
$REPO will be auto-resolved in the POM file.

Related

Spring Boot and Database Initialization not working properly

The scripts in schema.sql gets executes but scripts from data.sql are not executing,
not sure what I am missing?
I am using Spring Boot with two data source my data base configuration is as follows
#PropertySource({ "classpath:application.properties" })
#Configuration
#EnableJpaRepositories(
basePackages = "com.projectx.mysql",
entityManagerFactoryRef = "userEntityManager",
transactionManagerRef = "userTransactionManager"
)
public class DataBaseConfig {
#Autowired
Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean userEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan(new String[] { "com.projectx.mysql" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto_mysql"));
properties.put("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect_mysql"));
properties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean
public PlatformTransactionManager userTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(userEntityManager().getObject());
return transactionManager;
}
}
and .properties file configuration as follows
spring.datasource.initialize=true
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.show-sql: true
spring.jpa.hibernate.ddl-auto_mysql=update
spring.jpa.properties.hibernate.dialect_mysql=org.hibernate.dialect.MySQL5Dialect
For those of you who stumble upon this question in a SpringBoot 2.1+ world.
First, what I think is the full class name of the important class (the object of the "publishEvent"... "org.springframework.boot.autoconfigure.jdbc.DataSourceInitializedEvent"
For future readers, this class seems to have disappeared between these two versions :
Below does exist:
https://docs.spring.io/spring-boot/docs/2.0.0.M3/api/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializedEvent.html
Below no longer exists:
https://docs.spring.io/spring-boot/docs/2.1.0.M1/api/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializedEvent.html
Here is how I "coded up" the seed data ("data.sql") .. when I had a Java-Config heavy class.
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
#Bean
public DataSource getDataSource() {
//not shown
}
#Bean
public DataSourceInitializer dataSourceInitializer(DataSource ds) {
ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
resourceDatabasePopulator.addScript(new ClassPathResource("/data.sql"));
DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(ds);
dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);
return dataSourceInitializer;
}
Debug tip. You may want to use a file name that is NOT a magic file name ("data.sql" is a magic name) to purposely avoid spring boot magic. Especially since spring boot 2.5.
The issue was with datasource initialization when we see content of org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer class that takes care of Database initialization through *.sql files.It has post construct method as follows
#PostConstruct
public void init() {
if (!this.properties.isInitialize()) {
logger.debug("Initialization disabled (not running DDL scripts)");
return;
}
if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
false).length > 0) {
this.dataSource = this.applicationContext.getBean(DataSource.class);
}
if (this.dataSource == null) {
logger.debug("No DataSource found so not initializing");
return;
}
runSchemaScripts();
}
The runSchemaScripts() method will initialize the data before hibernate schema creation and update operation is perfomed so if database schema is not generated then these method will create schema if you provide that in SQL script, but I want to perform operation after the schema is created/updated, for that class contains
#Override
public void onApplicationEvent(DataSourceInitializedEvent event) {
if (!this.properties.isInitialize()) {
logger.debug("Initialization disabled (not running data scripts)");
return;
}
// NOTE the event can happen more than once and
// the event datasource is not used here
if (!this.initialized) {
runDataScripts();
this.initialized = true;
}
}
this is called if after the hibernate schema creation/updation operation when we have spring boots default Datasource creation mechanism.
But as I was creating Datasource by myself,so it was not creating DataSourceInitializedEvent,so the data initilization scripts data.sql was not executed.
So I have changed my Data source creation logic to create DataSourceInitializedEvent as follows and that solved my issue.
#Autowired
private ConfigurableApplicationContext applicationContext;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean userEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan(new String[] { "com.projectx.mysql" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto_mysql"));
properties.put("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect_mysql"));
properties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
em.setJpaPropertyMap(properties);
this.applicationContext.publishEvent(new DataSourceInitializedEvent(primaryDataSource()));
return em;
}
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
Added this.applicationContext.publishEvent(new DataSourceInitializedEvent(primaryDataSource())); to create the DataSourceInitializedEvent event
I managed to get 2 data-sources instantiated and initiate schema and data in one of them with this test project. Hope that helps, maybe i missed some requirement of yours that makes my suggestions invalid :(
For ref (guess you already saw this): https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources

Spring JPA+Hibernate not able to fetch record using findAll() of JPARepository

I have created configuration using below code :
#Configuration
#EnableTransactionManagement
#ComponentScan("Name of package")
#EnableJpaRepositories("Name of package")
public class Config {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "Name of package";
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("Driver Name");
dataSource.setUrl("Url");
dataSource.setUsername("UserName");
dataSource.setPassword("Password");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN);
entityManagerFactoryBean.setJpaProperties(hibProperties());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return entityManagerFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.DB2Dialect");
properties.put("hibernate.default_schema","Schema Name");
return properties;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
There is an custom repository interface that implements JPARepository.
I have autowired the custom repository in controller and tried to call findAll().But the method returns 0 although there are 3 records in DB.
I am using spring web for rest service calls.
Entity class is created with #Entity and #Table annotations.It has an embedded key which is annotated using #EmbeddedId annotation.
#Repository
public interface EntityRepository extends JpaRepository<EntityTable, Long> {
#SuppressWarnings("unchecked") EntityTable save(EntityTable entityTable);
}
Entity table is the name of my table mapped with db table.

Automatic hibernate schema creation not working (junit+spring)

I am running a JUnit test case with the following spring config. THe automatic schema creation is not happening.
#Configuration
public class DatabaseConfiguration {
#Bean
DataSource dataSource() {
BasicDataSource ret = new BasicDataSource();
ret.setDriverClassName("com.mysql.jdbc.Driver");
ret.setUrl("jdbc:mysql://localhost:3306/mydb");
ret.setUsername("root");
ret.setPassword("root");
return ret;
}
#Bean
SessionFactory sessionFactoryBean(DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(
dataSource);
sessionBuilder.scanPackages("com.mypackage.domain");
sessionBuilder.addProperties(getHibernateProperties());
return sessionBuilder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", "true");
properties.put("hbm2ddl.auto", "create");
properties.put("hibernate.dialect",
"org.hibernate.dialect.MySQLDialect");
return properties;
}
#Bean
HibernateTransactionManager transactionManager(SessionFactory lsfb) {
HibernateTransactionManager mgr = new HibernateTransactionManager();
mgr.setSessionFactory(lsfb);
return mgr;
}
}
I have debugged to make sure that the schema creation is actually getting skipped.
Any idea why the schema creation might get skipped?
Try with hibernate.hbm2ddl.auto instead of hbm2ddl..auto

Multiple Transaction Managers in Spring Boot for different EntityManagers

I need to connect to two different databases from a single application. The trouble is that my appEntityManager does not have a transaction manager associated with it and I am not sure how to do it. The #Primary adminEntityManager is able to use the one provided by spring boot without any trouble as described here.
The configuration above almost works on its own. To complete the
picture you need to configure TransactionManagers for the two
EntityManagers as well. One of them could be picked up by the default
JpaTransactionManager in Spring Boot if you mark it as #Primary. The
other would have to be explicitly injected into a new instance. Or you
might be able to use a JTA transaction manager spanning both.
I have annoted the configuration with
#EnableTransactionManagement
And here is the relavant beans
#Bean
#ConfigurationProperties(prefix = "datasource.app")
public DataSource appDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource.admin")
public DataSource adminDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
public LocalContainerEntityManagerFactoryBean appEntityManagerFactory(
final EntityManagerFactoryBuilder builder) {
return builder
.dataSource(appDataSource())
.packages("au.com.mycompany.app.bomcommon.domain")
.persistenceUnit("appPersistentUnit")
.build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean adminEntityManagerFactory(
final EntityManagerFactoryBuilder builder) {
return builder
.dataSource(adminDataSource())
.packages("au.com.mycompany.app.bombatch")
.persistenceUnit("adminPersistentUnit")
.build();
}
//I thought this would do it but I am getting an exception
//No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: appTransactionManager,transactionManager
#Bean
public JpaTransactionManager appTransactionManager(#Qualifier("appEntityManagerFactory") final EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
Update
I ended up doing it a different way. see here.
See if this works:
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource.admin")
public DataSource adminDS() { ... }
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean adminEMF(...) { ... }
#Bean
#Primary
public JpaTransactionManager adminTM(...) { ... }
#Bean
public LocalContainerEntityManagerFactoryBean appEMF(...) { ... }
#Bean
public JpaTransactionManager appTM(...) { ... }
The only change I have made from your configuration is to declare a transaction manager for the admin side explicitly and marked that transaction manager as the default.
See the below changes. It works for me. Created 3 Data Sources, 3 Session Factories, and 3 Transaction Managers. Added these transaction managers in chainedTransaction as per below:
#Configuration
#EnableTransactionManagement
public class HibernateConfiguration implements TransactionManagementConfigurer {
#Bean("chainedTransactionManager")
public PlatformTransactionManager transactionManager(
#Qualifier("transactionManager1") final HibernateTransactionManager transactionManager1,
#Qualifier("transactionManager2") final HibernateTransactionManager transactionManager2,
#Qualifier("transactionManager3") final HibernateTransactionManager transactionManager3) {
return new ChainedTransactionManager(transactionManager1, transactionManager2, transactionManager3);
}
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
// TODO Auto-generated method stub
return transactionManager(oneTransactionManager(), twoTransactionManager(), threeTransactionManager());
}
#Bean(name = "oneDataSource", destroyMethod="")
public DataSource oneDataSource() throws IllegalArgumentException, NamingException, SQLException {
HikariConfig hkConfig = new HikariConfig();
System.out.println(env.getRequiredProperty("spring1-datasource.jdbcUrl"));
hkConfig.setJdbcUrl(env.getRequiredProperty("spring1-datasource.jdbcUrl"));
hkConfig.setUsername(env.getRequiredProperty("spring1-datasource.username"));
hkConfig.setPassword(env.getRequiredProperty("spring1-datasource.password"));
hkConfig.setDriverClassName(env.getRequiredProperty("spring1-datasource.driverClassName"));
return new HikariDataSource(hkConfig);
}
#Bean(name="oneSessionFactory")
#Qualifier("oneSessionFactory")
public LocalSessionFactoryBean oneSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(oneDataSource());
sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
#Bean(name="transactionManager1")
public HibernateTransactionManager oneTransactionManager() {
HibernateTransactionManager oneTransactionManager = new HibernateTransactionManager();
try {
oneTransactionManager.setSessionFactory(oneSessionFactory().getObject());
} catch (IllegalArgumentException | NamingException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return oneTransactionManager
}
#Bean(name = "twoDataSource", destroyMethod="")
public DataSource twoDataSource() throws IllegalArgumentException, NamingException, SQLException {
HikariConfig hkConfig = new HikariConfig();
System.out.println(env.getRequiredProperty("spring2-datasource.jdbcUrl"));
hkConfig.setJdbcUrl(env.getRequiredProperty("spring2-datasource.jdbcUrl"));
hkConfig.setUsername(env.getRequiredProperty("spring2-datasource.username"));
hkConfig.setPassword(env.getRequiredProperty("spring2-datasource.password"));
hkConfig.setDriverClassName(env.getRequiredProperty("spring2-datasource.driverClassName"));
return new HikariDataSource(hkConfig);
}
#Bean(name="twoSessionFactory")
#Qualifier("twoSessionFactory")
public LocalSessionFactoryBean twoSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(twoDataSource());
sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
#Bean(name="transactionManager2")
public HibernateTransactionManager twoTransactionManager() {
HibernateTransactionManager twoTransactionManager = new HibernateTransactionManager();
try {
twoTransactionManager.setSessionFactory(twoSessionFactory().getObject());
} catch (IllegalArgumentException | NamingException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return twoTransactionManager
}
#Bean(name = "threeDataSource", destroyMethod="")
public DataSource threeDataSource() throws IllegalArgumentException, NamingException, SQLException {
HikariConfig hkConfig = new HikariConfig();
System.out.println(env.getRequiredProperty("spring3-datasource.jdbcUrl"));
hkConfig.setJdbcUrl(env.getRequiredProperty("spring3-datasource.jdbcUrl"));
hkConfig.setUsername(env.getRequiredProperty("spring3-datasource.username"));
hkConfig.setPassword(env.getRequiredProperty("spring3-datasource.password"));
hkConfig.setDriverClassName(env.getRequiredProperty("spring3-datasource.driverClassName"));
return new HikariDataSource(hkConfig);
}
#Bean(name="threeSessionFactory")
#Qualifier("threeSessionFactory")
public LocalSessionFactoryBean threeSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(threeDataSource());
sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
#Bean(name="transactionManager3")
public HibernateTransactionManager threeTransactionManager() {
HibernateTransactionManager threeTransactionManager = new HibernateTransactionManager();
try {
threeTransactionManager.setSessionFactory(threeSessionFactory().getObject());
} catch (IllegalArgumentException | NamingException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return threeTransactionManager
}
}

Spring Data - no transaction is in progress

I'm trying to configure a custom Spring Data Repository to replace some funcionality of spring.
Everything works fine in #Repository interfaces, but in the #Repository implementations, I got no transaction.
Error:
javax.persistence.TransactionRequiredException: no transaction is in progress
Here is my Configuration File:
#Configuration
#ComponentScan ({"com.app.core.authentication", "com.app.core.service","com.app.core.repository"})
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.app.core.repository"})
public class AppCoreConfiguration implements TransactionManagementConfigurer {
#Bean
public DataSource dataSource() {
DataSource dataSource = null;
try {
Context ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:jboss/postgresDS");
} catch (NamingException e) {
e.printStackTrace();
}
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.app.core.entity");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
txManager.setDataSource(dataSource());
return txManager;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator(){
return new HibernateExceptionTranslator();
}
#Bean
public EntityManager entityManger () {
return entityManagerFactory().createEntityManager();
}
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager();
}
}
And my repository class:
#Repository
public class ClientRepository extends JPABaseRepository<String, Client> implements IClientRepository {
#Autowired
public ClienteRepository (EntityManager em) {
super(Cliente.class, em);
}
#Override
#Transactional
public Cliente save(Client client) {
return saveAndFlush(client);
}
}
And the interface:
#NoRepositoryBean
public interface IClientRepository extends IJPABaseRepository<String, Client> {
...
}
Did someone know why this custom #Repository class didn't get the transaction manager?
This is strange, because all interfaces not implemented works fine...
I already tried to put #Transaction's annotation everywhere... including change from RESOURCE_LOCAL to JTA and so on...
When using custom JPA Repositories which extend Spring Data JPA you need a factory to create instances of those repositories. As mentioned in the Spring Data JPA documentation.
The problem with your current approach is the fact that you are creating a, non-spring-managed, instance of an EntityManager.
#Bean
public EntityManager entityManger () {
return entityManagerFactory().createEntityManager();
}
Normally Spring creates a transaction aware proxy for the EntityManager but in your case (due to the #Bean method) your custom implementation gets a plain EntityManager. Creating a factory (as mentioned above) will solve this.

Resources