我想在主键中嵌入日期信息,用于将在PostgreSQL数据库中分区(每月(的表。从理论上讲,这应该会加快找出在哪个分区中查找数据的过程。我根据这篇文章将日期嵌入序列中。然而,现在我面临的问题是,我无法获得Hibernate使用过的Id。
c.f.应该给出尝试方法的想法的sql。
CREATE SEQUENCE test_serial START 1;
CREATE OR REPLACE FUNCTION gen_test_key() RETURNS BIGINT AS $$
DECLARE
new_id bigint;
BEGIN
new_id = (nextval('public.test_serial'::regclass)::bigint % 10000000000000::bigint
+ ( (EXTRACT(year from now())-2000)::bigint * 10000::bigint
+ EXTRACT(month from now())::bigint * 100::bigint
+ EXTRACT(day from now())::bigint
)::bigint * 10000000000000::bigint
)::bigint;
RETURN new_id;
END;
$$ LANGUAGE plpgsql;
CREATE TABLE test
( id bigint primary key default gen_test_key(),
something text,
tstamp timestamp default now()
) PARTITION BY RANGE (id);
CREATE TABLE test_2022_10 PARTITION OF test
FOR VALUES FROM (2210100000000000000::bigint ) TO (2211010000000000000::bigint);
我遇到了一个类似的问题,其中建议使用存储过程。不幸的是,在表定义中只允许函数作为默认值,因此存储过程中不允许使用seam
我认为这里需要的是SequenceStyleGenerator
的一个子类型,它覆盖determineBulkInsertionIdentifierGenerationSelectFragment
来运行此函数的代码。您应该能够使用@GenericGenerator
在您的实体上配置此生成器。当您不想更改现有查询时,我理解使用这个概念的愿望,但您确定分区在您的用例中会对您有所帮助吗?
此外,要小心,不要依赖主键中的日期信息,因为使用池优化器,可能会在值实际用作行的主键之前生成值。
因此,这是一个最终如@ChristianBeikov所建议的解决方案,这里是带有指向CustomIdGenerator
的注释的实体。
public class Test {
@Id
@GenericGenerator(name = "CustomIdGenerator", strategy = "nl.test.components.CustomIdGenerator")
@GeneratedValue(generator = "CustomIdGenerator")
private Long id;
private String something;
private OffsetDateTime tstamp;
}
正如@Mr_Thorynque所解释的,类似地,可以将存储函数调用为过程。只需将"CALL gen_test_key()"
替换为"SELECT gen_test_key()"
,不要将其传递给存储过程connection.prepareCall(CALL_STORE_PROC);
的错误方法,而是传递给connection.prepareStatement(STORED_FUNCTION);
。因此,这就是CustomIdGenerator
。
public class CustomIdGenerator implements IdentifierGenerator {
private static final String STORED_FUNCTION = "select gen_test_key()";
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
Long result = null;
try {
Connection connection = session.connection();
PreparedStatement pstmt = connection.prepareStatement(STORED_FUNCTION);
ResultSet resultSet = pstmt.executeQuery();
if (resultSet.next()) {
result = resultSet.getLong(1);
System.out.println("Generated Id: " + result);
}
} catch (SQLException sqlException) {
throw new HibernateException(sqlException);
}
return result;
}
}