手动使用 Hibernate 序列生成器
题
基本上,我想要一种以与数据库无关的方式访问序列值的方法。用例是我在实体上有一个字段,我想根据递增值(ID 除外)来设置该字段。
例如,假设我有一个 Shipment
实体。在创建货件后的某个时刻,它就会被发货。一旦发货,就会为其生成并分配清单编号。清单号码看起来像 M000009
(“M”之后的内容是序列中的左填充值)。
有人问过类似的问题 在SO这里 ,但我不喜欢该解决方案,因为它需要另一个表来维护,并且看起来像是一种奇怪的关系。
有谁知道是否可以使用像 hibernate 这样的东西 MultipleHiLoPerTableGenerator
作为 ID 生成器以外的东西?
如果这是不可能的,有谁知道有什么库可以处理这个问题(使用 hibernate 甚至只是纯 JDBC)。我不想自己编写这个(并且必须处理预取值、锁定和同步)。
谢谢。
解决方案
我认为您的任务的复杂性取决于您的清单编号是否需要连续:
- 如果您不需要连续的清单编号,那么很高兴,可以使用序列。
- 如果您确实需要顺序清单编号(或者您的数据库不支持序列),则使用具有适当锁定的 id 表,以便每个事务获得唯一的顺序值。
那么我能想到的有两个选择:
- 在客户端上编写必要的 JDBC 代码,确保(如果清单编号是连续的)正在使用的事务与数据库更新的事务相同。
- 当发生适当的更新时,使用触发器创建清单编号。
我认为我的偏好是触发器,因为事务方面的事情将得到处理,尽管这意味着对象需要在客户端上刷新。
其他提示
我没有阅读链接的类似解决方案,但听起来像是我做的事情。我为序列创建了一个表。我在表中为我需要的每个序列类型添加了一行。
然后我有一个序列生成器类,它将执行必要的sql查询以获取和更新特定命名序列的序列值。
我使用hibernate的Dialect类以db中立方式执行它。
我也会'缓存'序列。我会将存储的序列值碰到一个大数字,然后从我的生成器类中分配那些分配的序列。如果类被销毁(即app关闭),序列生成器的新实例将以存储的值启动。 (我的序列号有差距并不重要)
这是一个代码示例。我想提醒一下 - 我没有提到这个,它需要弹簧代码。说完这个之后,它仍然应该提供你想要做的事情。
public Long getManifestNumber() {
final Object result = getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session sess) throws HibernateException, SQLException {
SQLQuery sqlQuery = sess.createSQLQuery("select MY_SEQUENCE.NEXTVAL from dual");
sqlQuery.uniqueResult();
}
});
Long toReturn;
if (result instanceof BigDecimal) {
toReturn = ((BigDecimal)result).longValue();
}
return toReturn;
}