第一讲:entityManager的配置详解

以前一直使用着hibernate,一直不知道entityManager的作用,这次搭建的项目采用的orm框架我采取的是以jpa规范得以实现。

不喜欢讲太多,直接看配置

 

我喜欢将配置尽可能地写在properties中,而不是在xml中直接写上值,虽然效果一样,但是写在properties中更有一种控制感

复制代码
 1 hibernate.jdbc.fetch_size=50
 2 hibernate.jdbc.batch_size=30
 3 hibernate.sessionFactory.class=org.springframework.orm.hibernate4.LocalSessionFactoryBean
 4 hibernate.dialect=org.hibernate.dialect.MySQLDialect
 5 hibernate.show_sql=true
 6 hibernate.format_sql=false;
 7 hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
 8 hibernate.query.substitutions=true 1,false 0
 9 hibernate.default_batch_fetch_size=16
10 hibernate.max_fetch_depth=2
11 hibernate.generate_statistics=true
12 hibernate.bytecode.use_reflection_optimizer=true
13 hibernate.cache.use_second_level_cache=true
14 hibernate.cache.use_query_cache=true
15 hibernate.cache.region.factory_class=org.hibernate.cache.internal.RegionFactoryInitiator
16 hibernate.cache.use_structured_entries=true
复制代码

接下来是熟悉的applicationContext-orm.xml

复制代码
 1     <beans:bean id="entityManagerFactory"
 2         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 3         <beans:property name="dataSource" ref="dataSource" />
 4         <beans:property name="persistenceXmlLocation" value="classpath:persistence.xml" />
 5         <beans:property name="persistenceUnitName" value="persistenceUnit" />
 6         <beans:property name="jpaVendorAdapter">
 7             <beans:bean
 8                 class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
 9                 <beans:property name="showSql" value="true" />
10                 <beans:property name="generateDdl" value="false" />
11             </beans:bean>
12         </beans:property>
13         <beans:property name="jpaProperties">
14             <beans:props>
15                 <beans:prop key="hibernate.dialect">${hibernate.dialect}</beans:prop>
16                 <beans:prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy
17                 </beans:prop>
18                 <beans:prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}
19                 </beans:prop>
20                 <beans:prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}
21                 </beans:prop>
22                 <beans:prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}
23                 </beans:prop>
24                 <beans:prop key="hibernate.jdbc.fetch_size">${hibernate.jdbc.fetch_size}</beans:prop>
25                 <beans:prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</beans:prop>
26                 <beans:prop key="hibernate.connection.isolation">2</beans:prop>
27                 <beans:prop key="javax.persistence.validation.mode">none</beans:prop>
28                 <beans:prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider
29                 </beans:prop>
30                 <beans:prop key="hibernate.search.default.indexBase">${java.io.tmpdir}/${system.project_name}/index
31                 </beans:prop>
32             </beans:props>
33         </beans:property>
34     </beans:bean>
复制代码

以前我也一直是从网上copy出一份直接写上来,直到那天出了一个奇葩的基础框架的问题,让我不得不从配置上去找问题,抛开百度,抛开谷歌,只剩下source code.

下面一层一层地拨开一个它的真面目。

首先是dataSource:

复制代码
 1 private final DefaultPersistenceUnitManager internalPersistenceUnitManager =
 2             new DefaultPersistenceUnitManager();
 3 
 4 
 5 /**
 6      * Specify the JDBC DataSource that the JPA persistence provider is supposed
 7      * to use for accessing the database. This is an alternative to keeping the
 8      * JDBC configuration in {@code persistence.xml}, passing in a Spring-managed
 9      * DataSource instead.
10      * <p>In JPA speak, a DataSource passed in here will be used as "nonJtaDataSource"
11      * on the PersistenceUnitInfo passed to the PersistenceProvider, as well as
12      * overriding data source configuration in {@code persistence.xml} (if any).
13      * Note that this variant typically works for JTA transaction management as well;
14      * if it does not, consider using the explicit {@link #setJtaDataSource} instead.
15      * <p><b>NOTE: Only applied if no external PersistenceUnitManager specified.</b>
16      * @see javax.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource()
17      * @see #setPersistenceUnitManager
18      */
19     public void setDataSource(DataSource dataSource) {
20         this.internalPersistenceUnitManager.setDataSourceLookup(new SingleDataSourceLookup(dataSource));
21         this.internalPersistenceUnitManager.setDefaultDataSource(dataSource);
22     }
复制代码

 dataSource在SingleDataSourceLookup中进行了非空处理之后,就作为了默认持久单元管理的数据池,参与了jpa的持久化流程了。

复制代码
1 /**
2      * Create a new instance of the {@link SingleDataSourceLookup} class.
3      * @param dataSource the single {@link DataSource} to wrap
4      */
5     public SingleDataSourceLookup(DataSource dataSource) {
6         Assert.notNull(dataSource, "DataSource must not be null");
7         this.dataSource = dataSource;
8     }
复制代码

 

接下来是persistenceXmlLocation,这个.......这么简单我也不想说啥了

复制代码
 1 /**
 2      * Set the location of the {@code persistence.xml} file
 3      * we want to use. This is a Spring resource location.
 4      * <p>Default is "classpath:META-INF/persistence.xml".
 5      * <p><b>NOTE: Only applied if no external PersistenceUnitManager specified.</b>
 6      * @param persistenceXmlLocation a Spring resource String
 7      * identifying the location of the {@code persistence.xml} file
 8      * that this LocalContainerEntityManagerFactoryBean should parse
 9      * @see #setPersistenceUnitManager
10      */
11     public void setPersistenceXmlLocation(String persistenceXmlLocation) {
12         this.internalPersistenceUnitManager.setPersistenceXmlLocation(persistenceXmlLocation);
13     }
复制代码

因为连接信息在dataSource中已经有了,所以我的persistence.xml是一个很简单的文件

后续再讲解persistence.xml的作用

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <persistence xmlns="http://java.sun.com/xml/ns/persistence"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
 5              http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
 6     version="2.0">
 7 
 8     <persistence-unit name="persistenceUnit"
 9         transaction-type="RESOURCE_LOCAL"></persistence-unit>
10 
11 </persistence>
复制代码

 

然后是persistenceUnitName,一样一样的

复制代码
 1 /**
 2      * Uses the specified persistence unit name as the name of the default
 3      * persistence unit, if applicable.
 4      * <p><b>NOTE: Only applied if no external PersistenceUnitManager specified.</b>
 5      * @see DefaultPersistenceUnitManager#setDefaultPersistenceUnitName
 6      */
 7     @Override
 8     public void setPersistenceUnitName(String persistenceUnitName) {
 9         super.setPersistenceUnitName(persistenceUnitName);
10         this.internalPersistenceUnitManager.setDefaultPersistenceUnitName(persistenceUnitName);
11     }
复制代码

 

由于jpa只是一套规范,而没有具体的实现,因此必不可少地需要给这个规范接上实现,这个就是常见的适配器,jpa的适配器就是jpaVendorAdapter,我选用的是HibernateJpaVendorAdapter。

至于这个适配接入和showSql和generateDdl,嗯。。。。。。好奇的童鞋打开看看吧,

复制代码
 1 public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter
 2 
 3 public abstract class AbstractJpaVendorAdapter implements JpaVendorAdapter
 4 
 5 /**
 6      * Specify the JpaVendorAdapter implementation for the desired JPA provider,
 7      * if any. This will initialize appropriate defaults for the given provider,
 8      * such as persistence provider class and JpaDialect, unless locally
 9      * overridden in this FactoryBean.
10      */
11     public void setJpaVendorAdapter(JpaVendorAdapter jpaVendorAdapter) {
12         this.jpaVendorAdapter = jpaVendorAdapter;
13     }
复制代码
复制代码
 1 /**
 2      * Set whether to generate DDL after the EntityManagerFactory has been initialized,
 3      * creating/updating all relevant tables.
 4      * <p>Note that the exact semantics of this flag depend on the underlying
 5      * persistence provider. For any more advanced needs, specify the appropriate
 6      * vendor-specific settings as "jpaProperties".
 7      * @see org.springframework.orm.jpa.AbstractEntityManagerFactoryBean#setJpaProperties
 8      */
 9     public void setGenerateDdl(boolean generateDdl) {
10         this.generateDdl = generateDdl;
11     }
复制代码
View Code

 

最后一个配置是:jpaProperties,

复制代码
 1 /**
 2      * Specify JPA properties, to be passed into
 3      * {@code Persistence.createEntityManagerFactory} (if any).
 4      * <p>Can be populated with a String "value" (parsed via PropertiesEditor) or a
 5      * "props" element in XML bean definitions.
 6      * @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
 7      * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
 8      */
 9     public void setJpaProperties(Properties jpaProperties) {
10         CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.jpaPropertyMap);
11     }
复制代码

spring会将这个jpaProperties的map重新封装给jpaPropertyMap

该类中还有一个方法,看方法名称是执行完上面的方法将执行这个方法,中间没看清怎么跑的,总之,debug时,它进来了

复制代码
 1 @Override
 2     public final void afterPropertiesSet() throws PersistenceException {
 3         if (this.jpaVendorAdapter != null) {
 4             if (this.persistenceProvider == null) {
 5                 this.persistenceProvider = this.jpaVendorAdapter.getPersistenceProvider();
 6             }
 7             Map<String, ?> vendorPropertyMap = this.jpaVendorAdapter.getJpaPropertyMap();
 8             if (vendorPropertyMap != null) {
 9                 for (Map.Entry<String, ?> entry : vendorPropertyMap.entrySet()) {
10                     if (!this.jpaPropertyMap.containsKey(entry.getKey())) {
11                         this.jpaPropertyMap.put(entry.getKey(), entry.getValue());
12                     }
13                 }
14             }
15             if (this.entityManagerFactoryInterface == null) {
16                 this.entityManagerFactoryInterface = this.jpaVendorAdapter.getEntityManagerFactoryInterface();
17                 if (!ClassUtils.isVisible(this.entityManagerFactoryInterface, this.beanClassLoader)) {
18                     this.entityManagerFactoryInterface = EntityManagerFactory.class;
19                 }
20             }
21             if (this.entityManagerInterface == null) {
22                 this.entityManagerInterface = this.jpaVendorAdapter.getEntityManagerInterface();
23                 if (!ClassUtils.isVisible(this.entityManagerInterface, this.beanClassLoader)) {
24                     this.entityManagerInterface = EntityManager.class;
25                 }
26             }
27             if (this.jpaDialect == null) {
28                 this.jpaDialect = this.jpaVendorAdapter.getJpaDialect();
29             }
30         }
31 
32         this.nativeEntityManagerFactory = createNativeEntityManagerFactory();
33         if (this.nativeEntityManagerFactory == null) {
34             throw new IllegalStateException(
35                     "JPA PersistenceProvider returned null EntityManagerFactory - check your JPA provider setup!");
36         }
37         if (this.jpaVendorAdapter != null) {
38             this.jpaVendorAdapter.postProcessEntityManagerFactory(this.nativeEntityManagerFactory);
39         }
40 
41         // Wrap the EntityManagerFactory in a factory implementing all its interfaces.
42         // This allows interception of createEntityManager methods to return an
43         // application-managed EntityManager proxy that automatically joins
44         // existing transactions.
45         this.entityManagerFactory = createEntityManagerFactoryProxy(this.nativeEntityManagerFactory);
46     }
复制代码

首先jpaPropertyMap会将适配器中有且自己没有的键值对占为己有。

接着它会调用适配器,将自己的entityManageFactory和entityManage指向hibernate的地址。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值