【Java.Spring.DataAccess】ORM Data Access - JPA

Spring JPA

在Spring包 org.springframework.orm.jpa中提供了对JPA的支持。

在Spring中设置JPA

Spring JPA提供了3张方式来设置JPA的 EntityManagerFactory,该类用来获取entity manager示例

LocalEntityManagerFactoryBean

该方法通常用于比较简单的环境,如stand-alone或者测试应用程序

LocalEntityManagerFactoryBean创建了一个EntityManagerFactory,其适用于只使用JPA来访问数据的应用程序。

该factory bean使用JPA PersistenceProvider的自动检测机制,并且需要指定persistence unit name;例如:

<beans>
    <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="myPersistenceUnit"/>
    </bean>
</beans>

该种形式的JPA使用是最简单同时也是受限最多的。不能应用JDBC的DataSource bean,不支持全局事务。而且需要特殊的JVM设置。

从JNDI获得一个EntityManagerFactory

该选项用于Java EE5 server。

XML配置如下:

<beans>
    <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>


LocalContainerEntityManagerFactoryBean

该选项在基于Spring的应用程序中可以使用JPA的全部特性,例如使用在Tomcat或者stand-alone的应用程序中。

LocalContainerEntityManagerFactoryBean基于persistence.xml文件创建了一个PersistenceUnitInfo示例,其包含dataSourceLookUp strategy, loadTimeWeaver属性。其可以使用除JNDI之外的自定义data source,并控制织入过程。

典型的bean 定义如下:

<beans>
    <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="someDataSource"/>
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>
    </bean>
</beans>

该使用方式可能同Java EE5 server内建的JPA功能相冲突,server会从JNDI获得EntityManagerFactory。Java EE5 server只会寻找默认的META-INF/persistence.xml文件,因此,在LocalContainerEntityManagerFactoryBean中指定一个自定以的persistenceXmlLocation值,如META-INF/my-persistence.xml,这将避免冲突。

load-time weaving

不是所有的JPA实现都要求一个JVM agent。Hibernate即不要求。如果使用的JPA实现不要求JVM agent或者有其他的替代方式,那么不应该使用load-time weaver。


定义多个persistence units

对于依赖与多个persistence units的应用程序,Spring提供了PersistenceUnitManager作为一个central repository,避免了persistence units的检测过程(该过程耗时)。默认的实现可以指定多个persistence units locations,解析并通过persistence unit name获取。

例如:

<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
    <property name="persistenceXmlLocations">
        <list>
            <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
            <value>classpath:/my/package/**/custom-persistence.xml</value>
            <value>classpath*:META-INF/persistence.xml</value>
        </list>
    </property>
    <property name="dataSources">
        <map>
            <entry key="localDataSource" value-ref="local-db"/>
            <entry key="remoteDataSource" value-ref="remote-db"/>
        </map>
    </property>
    <!-- if no datasource is specified, use this one -->
    <property name="defaultDataSource" ref="remoteDataSource"/>
</bean>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitManager" ref="pum"/>
    <property name="persistenceUnitName" value="myCustomUnit"/>
</bean>


使用JPA实现DAOs

EntityManagerFactory是线程安全的,但是EntityManager不是

使用@PersistenceUnit注解EntityManagerFactory实现DAOs

注入的JPA EntityManager的表现同从application server's JDNI中得到的EntityManager一样。如果存在可用的,其会代理当前可用的EntityManager,否则会创建一个新的EntityManager。从而保证EntityManager使用的线程安全性。

[Note]

Although EntityManagerFactory instances are thread-safe, EntityManager instances are not. The injected JPA EntityManager behaves like an EntityManager fetched from an application server’s JNDI environment, as defined by the JPA specification. It delegates all calls to the current transactional EntityManager, if any; otherwise, it falls back to a newly created EntityManager per operation, in effect making its usage thread-safe.



通过使用注入EntityManagerFactory或者EntityManger,可以不依赖任何Spring特性而使用JPA。如果PersistenceAnnotationBeanPostProcessor被激活,Spring可以在field和method层次上使用@PersistenceUnit和@PersistenceContext。

使用@PersistenceUnit注解的原生JPA DAO实现如下:

public class ProductDaoImpl implements ProductDao {

    private EntityManagerFactory emf;

    @PersistenceUnit
    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public Collection loadProductsByCategory(String category) {
        EntityManager em = this.emf.createEntityManager();
        try {
            Query query = em.createQuery("from Product as p where p.category = ?1");
            query.setParameter(1, category);
            return query.getResultList();
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
    }
}

<beans>

    <!-- bean post-processor for JPA annotations -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

    <bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

上述的DAO实现不依赖与Spring,并可用于Spring应用程序上下文。


另一种不显式定义PersistenceAnnotationBeanPostProcessor的方式是在application context配置文件中使用xml元素: context:annotation-config,

<beans>

    <!-- post-processors for all standard config annotations -->
    <context:annotation-config/>

    <bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>


* 使用@PersistenceContext注入EntityManager实现DAO

上述DAO实现的主要问题在于其总是会通过factory创建一个新的EntityManager。可以通过注入一个transactional EntityManager(而不是注入一个EntityManagerFactory)来避免上述问题,transactional EntityManager 也称为shared EntityManager,其是实际的transactional EntityManager的共享的,线程安全的代理。

public class ProductDaoImpl implements ProductDao {

    @PersistenceContext
    private EntityManager em;

    public Collection loadProductsByCategory(String category) {
        Query query = em.createQuery("from Product as p where p.category = :category");
        query.setParameter("category", category);
        return query.getResultList();
    }
}


注入的EntityManager是由Spring来进行管理的。

使用该种DAO方式的优点在于其仅仅依赖于JPA API,没有引任何的Spring类。


事务管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEmf"/>
    </bean>

    <bean id="myProductService" class="product.ProductServiceImpl">
        <property name="productDao" ref="myProductDao"/>
    </bean>

    <aop:config>
        <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="myTxManager">
        <tx:attributes>
            <tx:method name="increasePrice*" propagation="REQUIRED"/>
            <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>

</beans>


JpaDialect

JpaTemplate的一个高级特性是,JpaTransactionManager和AbstractEntityManagerFactoryBean的子类支持自定义的JpaDialect作为jpaDialect bean属性。在这种情况下,DAOs不会获取一个EntityManagerFactory应用,而是使用JpaTemplate实例。JpaTemplate实现可以利用一些Spring提供的高级特性:

  • Applying specific transaction semantics such as custom isolation level or transaction timeout)
  • Retrieving the transactional JDBC Connection for exposure to JDBC-based DAOs)
  • Advanced translation of PersistenceExceptions to Spring DataAccessExceptions

默认的实现使用DefaultJpaDialect,不提供任何上述的能力。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值