跟我学OpenJPA之四(与其他JPA实现的互换与对比---实践是检验真理的唯一标准)

 

感谢jinnianshilongnian和kjj的建议,我已经修改了文章的标题,以后会多多注意细节

 

上节,我们已经成功的把OpenJPA的实体对象增强,那么问题出现了。为什么我们要花费如此的代价,去修改实体类的字节码。这些修改能在实际的应用中体现出优化吗?在写这篇文章之前,我也没有针对这个做过完整的测试,实践是检验真理的唯一标准,那么让我们用实际行动来检验之。

 

本来想专门开一节讲解如何快速的将项目从OpenJPA转换到其他的JPA实现,但是由于确实太简单,单独一章介绍似乎有赚稿费的嫌疑(^_^) ,那么就在这里把项目转换到Hibernate和EclipseLink的JPA实现,同时也好与他们做个简单的性能比较。

 

================介绍完毕的分割线====================

 

在上节的测试中,我们发现entityManager.persist(entity)并没有把数据持久化保存到数据库,显然是因为没有启用事务的原因。在测试开始之前,我们先修改一下之前的代码。

 

1、建立DAO类

接口:StrongDAO.java

public abstract interface StrongDAO<E, PK extends Serializable> {

  /**
   * 执行SQL
   * 
   * @param strSQL
   * @return
   */
  public int executeSQL(final String strSQL);

  /**
   * 保存实体到数据库
   * 
   * @param entity
   */
  public void save(final E entity);
} 

实现:StrongDAOImpl.java

public abstract class StrongDAOImpl<E, PK extends Serializable> implements StrongDAO<E, PK> {

  @PersistenceContext
  private EntityManager entityManager;

  public EntityManager getEntityManager() {
    return this.entityManager;
  }

  public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  @Override
  public int executeSQL(String strSQL) {
    // TODO Auto-generated method stub
    return entityManager.createNativeQuery(strSQL).executeUpdate();
  }

  @Override
  public void save(E entity) {
    entityManager.persist(entity);
  }
}

 

2、为便于事务管理,建立Service类

接口:TXxService.java

@Transactional
public interface TXxService {

  /**
   * 单事务循环插入1000
   */
  public void doDanSHiWuXunHuan1000();

  /**
   * 单事务循环插入2000
   */
  public void doDanSHiWuXunHuan2000();

  /**
   * 单事务循环插入8000
   */
  public void doDanSHiWuXunHuan8000();

  /**
   * 单事务循环插入20000
   */
  public void doDanSHiWuXunHuan20000();

  /**
   * 使用事务添加单条记录
   */
  public void doShiWuTianJia(TXx txx);

  /**
   * 直接执行SQL清空记录
   */
  public void doQingKong();
}

实现:TXxServiceImpl.java

@Service
public class TXxServiceImpl implements TXxService {

  @Autowired
  public TXxDAO txxDAO;

  private void doDanSHiWuXunHuan(int intCiShu) {
    for (int i = 0; i < intCiShu; i++) {
      TXx txx = new TXx();
      txx.setXxMc("第一选项" + i);
      txxDAO.save(txx);
    }
  }

  @Override
  public void doDanSHiWuXunHuan1000() {
    doDanSHiWuXunHuan(1000);
  }

  @Override
  public void doDanSHiWuXunHuan2000() {
    doDanSHiWuXunHuan(2000);
  }

  @Override
  public void doDanSHiWuXunHuan8000() {
    doDanSHiWuXunHuan(8000);
  }

  @Override
  public void doDanSHiWuXunHuan20000() {
    doDanSHiWuXunHuan(20000);
  }

  @Override
  public void doShiWuTianJia(TXx txx) {
    txxDAO.save(txx);
  }

  @Override
  public void doQingKong() {
    System.out.println(txxDAO.executeSQL("delete from t_xx where xx_id > 22"));
  }
}

 

4、修改pom.xml,导入Hibernate的JPA实现包和EclipseLink的包,增加如下:

    <dependency>
      <groupId>org.eclipse.persistence</groupId>
      <artifactId>eclipselink</artifactId>
      <version>2.3.2</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>4.1.0.Final</version>
    </dependency>

 

5、修改persistence.xml便于随时转换为其他的JPA实现

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="StrongOpenJPAPU" transaction-type="RESOURCE_LOCAL">
    <!-- 使用OpenJPA -->
    <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
    <!-- 使用Hibernate-JPA 
    <provider>org.hibernate.ejb.HibernatePersistence</provider>-->
    <!-- 使用EclipseLink
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> -->
    <class>com.strong.module.txx.jpa.TXx</class>
    <properties>
      <!-- JPA标准配置 使用OpenJPA和EclipseLink时使用 -->
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/strongjpa" />
      <property name="javax.persistence.jdbc.user" value="root" />
      <property name="javax.persistence.jdbc.password" value="root" />
      
      <!-- OpenJPA不增强 -->
      <property name="openjpa.ClassLoadEnhancement" value="false" />
      <property name="openjpa.DynamicEnhancementAgent" value="false" />
      <property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
      
      <!-- Hibernate配置  使用Hibernate的JPA实现时使用
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/strongjpa" />
      <property name="hibernate.connection.username" value="root" />
      <property name="hibernate.connection.password" value="root" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />-->

    </properties>
  </persistence-unit>
</persistence>

两点需要注意:

1、由于Hibernate的顽固,不兼容标准的javax.persistence.jdbc.driver等参数,所以这里只能使用Hibernate自己的配置参数。

2、从增强OpenJPA转换到非增强OpenJPA的时候,首先要把上节中增加的Ant Builder禁用,然后要修改一次TXx类,以便Eclipse重新编译他,否则运行的时候使用的依然是增强过的实体对象。

3、EclipseLink运行的时候,必须给VM增加参数:-javaagent:****/spring-instrument-****.jar,否则会报错。使用的方法请参见上节中的介绍或参见Spring3(MVC)+OpenJPA2构建及发布

 

通过以上修改,大家很容易就发现:有了JPA的接口,我们可以非常方便地转换其他的实现,在Spring3.1之前,仍然使用回调的方式实现DAO,这样还会与JPA的具体实现有部分耦合,Spring3.1之后的注入方式彻底实现了解耦合。所以这里强烈大家升级到3.1以上并修改之前的耦合部分。

 

6、修改测试单元

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class StringOpenJPATest {

  @Autowired
  public TXxService txxService;

  private void doDuoShiWuXunHuan(int intCiShu) {
    for (int i = 0; i < intCiShu; i++) {
      TXx txx = new TXx();
      txx.setXxMc("第一选项" + i);
      txxService.doShiWuTianJia(txx);
    }
  }

  @Test
  public void doCeShiDuoShiWuXunHuan100() {
    doDuoShiWuXunHuan(100);
    txxService.doQingKong();
  }

  @Test
  public void doCeShiDuoShiWuXunHuan200() {
    doDuoShiWuXunHuan(200);
    txxService.doQingKong();
  }

  @Test
  public void doCeShiDuoShiWuXunHuan800() {
    doDuoShiWuXunHuan(800);
    txxService.doQingKong();
  }

  @Test
  public void doCeShiDuoShiWuXunHuan2000() {
    doDuoShiWuXunHuan(2000);
    txxService.doQingKong();
  }

  @Test
  public void doCeShiDanSHiWuXunHuan1000() {
    txxService.doDanSHiWuXunHuan1000();
    txxService.doQingKong();
  }

  @Test
  public void doCeShiDanSHiWuXunHuan2000() {
    txxService.doDanSHiWuXunHuan2000();
    txxService.doQingKong();
  }

  @Test
  public void doCeShiDanSHiWuXunHuan8000() {
    txxService.doDanSHiWuXunHuan8000();
    txxService.doQingKong();
  }

  @Test
  public void doCeShiDanSHiWuXunHuan20000() {
    txxService.doDanSHiWuXunHuan20000();
    txxService.doQingKong();
  }
}

测试顺序是先执行循环多次事务,每次事务插入一条记录(数量分别为100,200,800,2000);然后执行一次事务插入多条记录(数量分别为1000,2000,8000,20000),下面是测试的对比图

 


跟我学OpenJPA之四(与其他JPA实现的互换与对比---实践是检验真理的唯一标准)


跟我学OpenJPA之四(与其他JPA实现的互换与对比---实践是检验真理的唯一标准)

 

结论:

      分析结果我们发现,OpenJPA使用增强后的实体对象相较未增强时有明显性能提升,对比其他的JPA实现,OpenJPA的性能也没有太大的差别,尤其是在单事务多操作时其性能相较其他两种也有一定的优势。奇怪的时OpenJPA在连续执行多个简单事务时性能明显滞后。

      OpenJPA的官方文档中说实体对象增强后在“延迟加载”、“脏检查”等方面性能有一定的优化,由于时间和精力有限这里就不对这两项进行测试,把这个任务留给大家吧^_^

 

 

      最后,希望通过本节能让大家接受JPA,认可OpenJPA。从之前三篇文章的情况来看,感兴趣的朋友还是不多。顺便介绍一个OpenJPA入门和学习非常好课程:使用 Apache OpenJPA 开发 EJB 3.0 应用系列 有兴趣的朋友请传送过去学习。

      之前有人问我为什么不写写OpenJPA的基础概念和研究,其实主要是对比这个系列我觉得我的能力和协作的水平确实有限,并且也没有必要重复他人的工作。

 

本节资源:

本节的源码:StrongOpenJPA.tar.gz

Ant Builder需要的openjpa-all的jar包:openjpa_libs.tar.gz

 

你可能感兴趣的:(openjpa)