30 Ağustos 2018 Perşembe

SpringData LocalContainerEntityManagerFactoryBean Sınıfı

Giriş
Şu satırı dahil ederiz.
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
Bu sınıf SpringBoot tarafından otomatik olarak yaratılır. Amacı EntityManagerFactory nesnesi yaratmaktır. Bu nesne de EntityManager nesnesi yaratır. Bence LocalContainerEntityManagerFactoryBean sınıfı ayarlaması oldukaç zor :)

EntityManager bir bean'e şöyle atanır.
@PersistenceContext(unitName = "JPA_PU")
private EntityManager em;
Spring + JPA kullanmak için şu bean'ler gerekir.

1. JpaVendorAdapter. Bu sınıf genellikle HibernateJpaVendorAdapter olur. Eğer persistence.xml dosyasında provider yazılı ise bu maddeyi yapmaya gerek yok. Şöyle yaparız.
<persistence-unit name="myPU" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  ...
</persistence-unit>
2. LocalContainerEntityManagerFactoryBean. Bu bean'e setJpaVendorAdapter() çağrısı ile JpaVendorAdapter atanır.
3. JpaTransactionManager. JpaTransactionManager bean LocalContainerEntityManagerFactoryBean tarafından yaratılan EntityManagerFactory nesnesini kullanır.

constructor
Örnek
Şöyle yaparız.
LocalContainerEntityManagerFactoryBean emfb =
  new LocalContainerEntityManagerFactoryBean();
Örnek
Şöyle yaparız.
@Bean
public LocalContainerEntityManagerFactoryBean getEntityManagerFactory(
  EntityManagerFactoryBuilder builder, 
  DataSource dataSource, 
  JpaProperties jpaProperties) {
  return builder
         .dataSource(dataSource)
         .packages(YourEntity.class)
         .persistenceUnit("yourEmName")
         // Important. load properties
         .properties(jpaProperties.getHibernateProperties(dataSource))
         .build();
}
afterPropertiesSet metodu
Şöyle yaparız.
em.setJpaProperties(...);
em.afterPropertiesSet();
getObject metodu
Şöyle yaparız.
@Bean(destroyMethod="")
@Primary
public EntityManagerFactory entityManagerFactory() {
  LocalContainerEntityManagerFactoryBean emfb = ...;
  ...
  return em.getObject();
}
setDataSource metodu
Şöyle yaparız.
DataSource dataSource = ...;
emfb.setDataSource(dataSource);
setJpaDialect metodu
Şöyle yaparız.
emfb.setJpaDialect(new HibernateJpaDialect());
setJpaProperties metodu
Örnek
Şöyle yaparız.
emfb.setJpaProperties(properties());
Örnek
Şöyle yaparız.
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
  LocalContainerEntityManagerFactoryBean entityManagerFactoryBean =
  new LocalContainerEntityManagerFactoryBean();
  entityManagerFactoryBean.setDataSource(dataSource);
  entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
  entityManagerFactoryBean.setPackagesToScan("mediabeast.data.hibernate.model");

  Properties jpaProperties = new Properties();

  jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");

  jpaProperties.put("hibernate.hbm2ddl.auto","update");

  jpaProperties.put("hibernate.show_sql","true");

  entityManagerFactoryBean.setJpaProperties(jpaProperties);

  return entityManagerFactoryBean;
}
setJPaPropertyMap metodu
Şu satırı dahil ederiz.
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.cfg.Environment;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
Şöyle yaparız.
MultiTenantConnectionProvider multiTenantConnectionProviderImpl = ...;
CurrentTenantIdentifierResolver currentTenantIdentifierResolverImpl = ...;
Map<String, Object> properties = new HashMap<>();

properties.putAll(jpaProperties.getHibernateProperties(dataSource));
properties.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
properties.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER,
  multiTenantConnectionProviderImpl);
properties.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER,
  currentTenantIdentifierResolverImpl);

LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
...
em.setJpaPropertyMap(properties);

setJpaVendorAdapter metodu
JPA için kullanılacak vendor belirtilir. HibernateJpaVendorAdapter kullanılabilir.

Örnek
Şöyle yaparız.
emfb.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Örnek
Şöyle yaparız.
emfb.setJpaVendorAdapter(jpaVendorAdapter());

@Bean
public JpaVendorAdapter jpaVendorAdapter() {
  return new HibernateJpaVendorAdapter();
}
setPackagesToScan metodu
Şöyle yaparız.
emfb.setPackagesToScan("com.test.entity");
setPersistenceUnitName metodu
Şöyle yaparız.
emfb.setPersistenceUnitName("JPA_PU");
setPersistenceXmlLocation metodu
Yüklenmesi istenen "Persistance Unit" xml'i belirtilir.

Örnek ver

setSharedCacheMode metodu
Şöyle yaparız.
em.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
Örnek
Şöyle yaparız.
<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="jpaDataSource" />
  <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
  <property name="packagesToScan" value="${persistence.jpa.packagesToScan}" />
  <property name="jpaProperties">
    <props>
      <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
      <prop key="hibernate.jdbc.use_get_generated_keys">true</prop>
    </props>
  </property>
  <property name="sharedCacheMode" value="ENABLE_SELECTIVE" />
  <property name="validationMode" value="NONE" />
</bean>
setValidationMode metodu
Örnek ver

XML İle Tanımlama
jpaVendorAdapter
Örnek
Şöyle yaparız. Diğer ayarlar persistence.xml dosyasındadır. persistence.xml kullanılırsa packagesToScan çalışmaz.
<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
      p:database="MYSQL" p:databasePlatform="org.hibernate.dialect.MySQL5Dialect"
      p:showSql="true" />
  </property>
  <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
  <property name="persistenceUnitName" value="streamJpaDB" />
</bean>
Örnek
Elimizde şöyle bir adapter olsun.
<bean id="jpaVendorAdapter"
  class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
  <property name="databasePlatform"
    value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
  <property name="generateDdl" value="false"/>
  <property name="showSql" value="true"/>
</bean>
Eğer iki farklı jpaVendorAdapter kullanmak istersek şöyle yaparız.
<bean id="entityManagerFactory1"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="JPA_1"/>
  <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
  <property name="jpaDialect">
    <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
  </property>
  <property name="jpaPropertyMap">
    <props>
      <prop key="eclipselink.weaving">false</prop> 
    </props>
  </property>
  <property name="loadTimeWeaver">
    <bean 
    class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">
    </bean>
  </property>
</bean>

<bean id="entityManagerFactory2"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="JPA_2"/>
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
    </property>
    <property name="jpaPropertyMap">
        <props>
            <prop key="eclipselink.weaving">false</prop>
        </props>
    </property>
  <property name="loadTimeWeaver">
    <bean
    class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">
    </bean>
  </property>
</bean> 
Kullanmak için şöyle yaparız.
@PersistenceContext(unitName ="JPA_1")
private EntityManager em_1; 

@PersistenceContext(unitName ="JPA_2")
private EntityManager em_2; 
packagesToScan
Şöyle yaparız.
<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
  p:dataSource-ref="phoenixDataSource">
  <property name="packagesToScan">
    <array>
      <value>com.test.entities.postgres</value>
    </array>
  </property>

  <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
  </property>

  <property name="jpaProperties">
    <props>
      <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
      <prop key="hibernate.show_sql">false</prop>
      <prop key="hibernate.hbm2ddl.auto">update</prop>
    </props>
  </property>

</bean>