在看pro jpa 2 这本书的时候,老外提到了 id 的生成策略如果是 identity 效率上会不如其他 id 预先生成好的策略(如 table,sequence),他解释说是 identity 策略只有在 insert 的时候才能知道分配的 id。我对此有一些疑惑,所以我对进行了一些测试,结果却有一些出人意料。
先说一下,我有这样一下非常简单的实体:@Entity
public class Foo {
  
    @Id    
    private Long id;
    private String bar;    public Long getId() {
        return id;
    }    public void setId(Long id) {
        this.id = id;
    }
我对他进行这样的操作: EntityManager em =...;        em.getTransaction().begin();        long start = System.nanoTime();
        for (int i = 0; i < 1000; i++) {            Foo foo = new Foo();
            em.persist(foo);
        }
        long end = System.nanoTime();
        em.getTransaction().commit();
        System.out.println(end - start);这个对象保存1000次,对计算这个过程花费的时间。第一个测试场景,数据库为 mysql , jpa provider 用的是 eclipseLink ,Foo 实体的 id 的生成策略为 identity,得到如下结果:
第一次输出
22743952,
第二次输出
22258694
然后,其他的都没有变,我将策略变为 table,则得到如下结果:
第一次输出
471251235,
第二次输出
522187876这个结果出乎我的意料,竟然与老外说的相反。而且竟然差的这么远,identity 要比 table 的效率至少高一个数量级。我不知该如何解释,我怀疑可能是不是 jpa 实现的原因,我用的是 eclipseLink。所以我又其他的实现。第二个测试场景,只是 jpa provider 我换成了 hibernate ,其他的都更第一个测试场景情况一样,当 id 为 identity 时,得到如下结果:
第一次输出
1119812155,
第二次输出
1078923160然后我再将 id 的生成策略变为 table,则得到如下结果:
第一次输出
577731248,
第二次输出
640952970这次得到的结果却跟 eclipseLink 实现得到的结果也是相反的。所以我也不知道如何来解释这个。
有能指点小弟的,就请大家敞开说。

解决方案 »

  1.   

    TABLE 和 SEQUENCE 会使用 J2EE 中的主键批量生成器模式进行缓存。在 @TableGenerator 和 @SequenceGenerator 中有 allocationSize 值指的是查询主键一次可以使用多少次。如果置为 1 的话那就是说每次主键值都需要通过 TABLE 或 SEQUENCE 得知,如果置为 50 的话(默认值)那就能查一次可以使用 50 次!会在内存中进行缓存。
      

  2.   

    可以看一下 Pro JPA 2 第 84 页 TIP 上面的那段文字,以及 TIP。
      

  3.   

    现在还流行 UUID 的主键模式,有兴趣的话可以看一下 JPA 实现模式之一的“使用 UUID 作为主键”http://blog.xebia.com/2009/06/03/jpa-implementation-patterns-using-uuids-as-primary-keys/UUID 作为主键的话,可以使用应用程序生成,不需要通过数据库服务器,在数据安全性和效率上应该是个不错的方案。可惜截止到 JPA 2 中的主键策略没有 UUID,需要使用 Provider 特有的配置。
      

  4.   

    uuid做主建很好。不喜欢用自增等主建了。
      

  5.   

    那如何解释在第一个测试,用 ecliseLink  实现的时候,为什么 identity 会比 table 快呢?