Aissasa
Aissasa

Reputation: 231

Spring data JPA configuration

I'm working on a spring web application using Spring Data JPA lately

I'm having problems with the persistanceConfiguration

@Configuration
@EnableTransactionManagement
@PropertySource({ "/resources/hibernate.properties" })
@EnableJpaRepositories(basePackages = "com.servmed.repositories")

public class PersistenceConfig {

    @Autowired
    private Environment env;


    Properties jpaProperties() {
        return new Properties() {
            {
                setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
                setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); //allows Hibernate to generate SQL optimized for a particular relational database.
                setProperty("hibernate.show_sql",env.getProperty("hibernate.show_sql"));
            }
        };
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory()
    {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        vendorAdapter.setShowSql(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(dataSource());
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setJpaProperties(jpaProperties());
        factory.setPackagesToScan("com.servmed.models");

        factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
        return factory;
    }

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

    @Bean
    public HibernateExceptionTranslator hibernateExceptionTranslator(){
        return new HibernateExceptionTranslator();
    }


    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.user"));
        dataSource.setPassword(env.getProperty("jdbc.pass"));

        return dataSource;
    }
}

And here's my pom.xml

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!--Spring dependencies-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-dao</artifactId>
            <version>2.0.8</version>
        </dependency>


        <!-- spring security-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring-security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring-security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring-security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring-security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>

        <!-- Spring Data JPA dependencies -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.6.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>


        <!--com.mysema.querydsl dependencies-->
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-sql</artifactId>
            <version>${com.mysema.querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>${com.mysema.querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-core</artifactId>
            <version>${com.mysema.querydsl.version}</version>
        </dependency>


        <!--Hibernate dependencies-->
         <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-core</artifactId>
          <version>${hibernate.version}</version>
        </dependency>

        <!--db-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.23</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

        <!--connection pool-->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-dbcp</artifactId>
            <version>8.0.9</version>
        </dependency>


        <!--thymeleaf and servlet api-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring4</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>

    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
    </build>

It doesn't seem to work for me, i get this error:

Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration.transactionAdvisor()] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionInterceptor' defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'transactionManager' is required

any idea why ?

EDIT

it doesn't seem that the entityManagerFactory method is creating properly the bean used in transactionManager, i had the same problem with hibernate (sessionFactory bean is not created, and cannot be used in transactionManager method )

EDIT 2

I got rid of this problem(it was because of a wrong properties file) but now i gey another error :

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/servmed/configuration/PersistenceConfig.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory

Upvotes: 2

Views: 5245

Answers (2)

Subhasish Sahu
Subhasish Sahu

Reputation: 1341

@Aissasa-You can use similar JPA Configuration class and you dont have to have any xm file also.

JpaConfiguration

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.eclipse.persistence.config.BatchWriting;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration
@EnableJpaRepositories(basePackages = "com.subu")
public class JpaConfiguration extends JpaBaseConfiguration {

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(final EntityManagerFactoryBuilder builder) {
        final LocalContainerEntityManagerFactoryBean ret =
                builder.dataSource(dataSource())
                .packages("com.subu")
                .properties(jpaProperties())
                .persistenceUnit("com.subu")
                .build();
        return ret;
}

@Bean
public DataSource dataSource() {
        // In classpath from spring-boot-starter-web
        final Properties props = new Properties();
        props.put("driverClassName", "com.mysql.jdbc.Driver");
        props.put("jdbcUrl", "jdbc:mysql://localhost:3306/master?createDatabaseIfNotExist=false");
        props.put("username", "root");
        props.put("password", "mysql");
        HikariConfig hc = new HikariConfig(props);
        HikariDataSource ds = new HikariDataSource(hc);
        return ds;
}

@Bean
public Map<String, String> jpaProperties() {
        Map<String, String> props = new HashMap<>();
        props.put("eclipselink.weaving", "false");
        props.put("eclipselink.logging.level.sql", "FINE");
        props.put("eclipselink.logging.parameters", "true");
        props.put("javax.persistence.schema-generation.database.action", "create");
        //props.put("javax.persistence.sql-load-script-source", "sql/import.sql");
        return props;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        final MultiTenantJpaTransactionManager transactionManager = new MultiTenantJpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
}

@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
        return new EclipseLinkJpaVendorAdapter();
}



@Override
protected Map<String, Object> getVendorProperties() {
        final Map<String, Object> ret = new HashMap<>();
        ret.put(PersistenceUnitProperties.BATCH_WRITING, BatchWriting.JDBC);
        return ret;
}


}

MultiTenantJpaTransactionManager

import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class MultiTenantJpaTransactionManager extends JpaTransactionManager {

@Override
protected void doBegin(final Object transaction, final TransactionDefinition definition) {
        super.doBegin(transaction, definition);
        final EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
                                             .getResource(getEntityManagerFactory());
        final EntityManager em = emHolder.getEntityManager();

}
}

Upvotes: 0

NoDataFound
NoDataFound

Reputation: 11949

Here is how I defined my transaction manager:

  @Bean
  public Object transactionManager() {
    return new org.springframework.orm.jpa.JpaTransactionManager();
  }

And instead of calling the entityFactory method, you should perhaps inject it: this would avoid dependency injection errors in entityManagerFactory.

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory factory)
{
    return new JpaTransactionManager(factory);
}

EDIT

Apart from persistence.xml, the call of afterPropertiesSet() and the setLoadTimeWeaver, we have the same code.

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(true);
    vendorAdapter.setShowSql(true);

    Properties jpaProperties = new Properties();
    jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
    jpaProperties.put("hibernate.dialect"     , env.getProperty("hibernate.dialect"));
    jpaProperties.put("hibernate.show_sql"    , pgadenv.getProperty("hibernate.show_sql"));

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setDataSource(dataSource());
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setJpaProperties(jpaProperties);
    factory.setPackagesToScan("com.servmed.models");

    // factory.afterPropertiesSet(); <-- why ?
    // does it work without Weaving ?
    factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
    return factory;
}

EDIT (2)

I did not have time to answer you, here is a sample persistence.xml:

<?xml version="1.0"  encoding="UTF-8"?>
<persistence version="2.1"
  xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <!-- transaction-type="JTA" -->
  <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

    <!-- Your probably won't need it. -->
    <!-- <class>com.servmed.models.YourClass</class> -->
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

    <properties>
      <property name="javax.persistence.schema-generation.database.action"       value="none" />
      <property name="javax.persistence.schema-generation.scripts.action"        value="none" />
      <!-- <property name="javax.persistence.schema-generation.scripts.create-target" value="" /> -->
      <!-- <property name="javax.persistence.schema-generation.scripts.drop-target"   value=""/> -->
    </properties>
  </persistence-unit>
</persistence>

You probably won't need to list your classes (like in the commented example), otherwise list them.

And in the Spring configuration, add:

factory.setPersistenceXmlLocation("classpath:META-INF/persistence.xml");
factory.setPersistenceUnitName("persistenceUnit");

However, I'm beginning to think it might be a completely unrelated problem.

Upvotes: 3

Related Questions