Hibernate 自带的 Optimizer [size=1.166em]Optimizer 可以翻译成优化器,使用优化器是为了避免每次生成主键时都会访问数据库。从 Hibernate 官方文档中找不到优化器的说明,需要查阅源码,在 org.hibernate.id.enhanced.OptimizerFactory 类中可以找到这些优化器的名字及对应的实现类,其中优化器的名字就是新 TableGenerator 中 optimizer 参数中能够使用的值: 表 3. Optimizer 名字及实现类Optimizer 名字 | 类名 | 特点 | none | NoopOptimizer.class | 没有任何优化,每次主键生成都需要访问数据库。 | hilo | HiLoOptimizer.class | hilo 算法实现的主键生成机制,数据库中的值是 bucket 的序号。 | legacy-hilo | LegacyHiLoAlgorithmOptimizer.class | 旧 hilo 算法。 | pooled | PooledOptimizer.class | 也使用 hilo 算法,不同之处在于 bucket 内部数值保存在数据库中。 | pooled-lo | PooledLoOptimizer.class | 算法与 pooled 完全相同,但保存在数据库中的值不同于 pooled。 |
[size=1.166em]Hibernate 自带了 5 种优化器,那么现在就可以加到上一节提到的问题了:默认情况下,新 TableGenerator 会选择哪个优化器呢? [size=1.166em]又一次,在 Hibernate 文档中找不到答案,还是要去查阅源码。通过分析 TableGenerator,可以看到 optimizer 的选择策略。具体过程可用下图来描述: 图 2. 选定优化器的过程[size=0.8em]关于 allocationSize[size=1.166em]JPA 的 @TableGenerator 注解有一个参数 allocationSize,如果用 Hibernate 来提供 JPA,并且开启 new_generator_mapping 参数,那么 allocationSize 的值就会是这里的 increment_size。经常可以在网络上看到把 allocationSize 设置成 1 的例子,这种行为无异于应用程序的自残。这种情况下还不如使用 AUTO。值得庆幸的是 allocationSize 的默认值为 50。
[size=1.166em]可以看出,hilo 和 legacy-hilo 两种优化器,除非指定,一般不会在实践中出现。接下来很重要的一步就是判断 increment_size 的值,如果 increment_size 不做指定,使用默认的 1,那么最终选择的优化器会是“none”。选中了“none”也就意味着没有任何优化,每次主键的生成都需要访问数据库。这种情况下 TableGenerator 的优势丧失殆尽,如果再用同一张表生成多个实体的主键,构造出来的系统在性能上会是程序员的噩梦。 [size=1.166em]在 increment_size 值大于 1 的情况下,只有 pooled 和 pooled-lo 两种优化器可供选择,选择条件由布尔型参数 hibernate.id.optimizer.pooled.prefer_lo 确定,该参数默认为 false,这也意味着,大多数情况下选中的优化器会是 pooled。 [size=1.166em]我们不去讨论 none 和 legacy-hilo,前者不应该使用,后者的名字看上去像是古董。剩下 hilo、pooled 和 pooled-lo 其实是同一种算法,它们的区别在于主键生成辅助表的数值。
|