当前位置: 首页 > 面试题库 >

如何使用Hibernate实现自定义字符串序列标识符生成器

刘曾琪
2023-03-14
问题内容

我正在将spring,h2和liquibase与hibernate一起使用,并且试图通过以本博客文章为例为我的实体创建自定义String id生成器,但出现错误:Caused by: org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String

这是我的SequenceStyleGenerator代码:

public class CTCIDGenerator extends SequenceStyleGenerator {

    @Override
    public Serializable generate(SessionImplementor session, Object obj) {
        if (obj instanceof Identifiable) {
            Identifiable identifiable = (Identifiable) obj;
            Serializable id = identifiable.getId();
            if (id != null) {
                return id;
            }
        }
        return "CTC"+super.generate(session, obj);
    }
}

我的实体代码:

@Entity
@Table(name = "contact")
public class Contact implements Serializable, Identifiable<String> {

    private static final long serialVersionUID = 1L;

    @Id
    @GenericGenerator(
        name = "assigned-sequence",
        strategy =     "net.atos.seirich.support.domain.idgenerator.CTCIDGenerator",
        parameters = @org.hibernate.annotations.Parameter(
            name = "sequence_name", 
            value = "hibernate_sequence"
        )
    )
    @GeneratedValue(generator = "assigned-sequence", strategy = GenerationType.SEQUENCE)
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

和liquibase XML:

<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">

    <property name="autoIncrement" value="true" dbms="mysql,h2,postgresql,oracle"/>

    <property name="floatType" value="float4" dbms="postgresql, h2"/>
    <property name="floatType" value="float" dbms="mysql, oracle"/>

    <changeSet id="20160513091901-1" author="jhipster">
        <createTable tableName="contact">
            <column name="id" type="longvarchar" autoIncrement="${autoIncrement}">
                <constraints primaryKey="true" nullable="false"/>
            </column>
    </changeSet>
</databaseChangeLog>

顺便说一句,有可能避免参数sequence_name,以便hibernate可以自行处理吗?

如果有人可以帮助我,谢谢!


问题答案:

问题是SequenceStyleGenerator期望返回一个数字值,而不是a String

我已经尝试过解决此问题的方法,它就像一个魅力。因此,您需要像这样更改生成器:

public class StringSequenceIdentifier implements IdentifierGenerator, Configurable {

    private String sequenceCallSyntax;

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
        final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService(JdbcEnvironment.class);
        final Dialect dialect = jdbcEnvironment.getDialect();

        final String sequencePerEntitySuffix = ConfigurationHelper.getString(CONFIG_SEQUENCE_PER_ENTITY_SUFFIX, params, DEF_SEQUENCE_SUFFIX);

        final String defaultSequenceName = ConfigurationHelper.getBoolean(CONFIG_PREFER_SEQUENCE_PER_ENTITY, params, false)
                ? params.getProperty(JPA_ENTITY_NAME) + sequencePerEntitySuffix
                : DEF_SEQUENCE_NAME;

        sequenceCallSyntax = dialect.getSequenceNextValString(ConfigurationHelper.getString(SEQUENCE_PARAM, params, defaultSequenceName));
    }

    @Override
    public Serializable generate(SessionImplementor session, Object obj) {
        if (obj instanceof Identifiable) {
            Identifiable identifiable = (Identifiable) obj;
            Serializable id = identifiable.getId();
            if (id != null) {
                return id;
            }
        }
        long seqValue = ((Number) Session.class.cast(session)
            .createSQLQuery(sequenceCallSyntax)
            .uniqueResult()).longValue();

        return "CTC" + seqValue;
    }
}

您的映射将变为:

@Entity(name = "Post")
@Table(name = "post")
public static class Post implements Identifiable<String> {

    @Id
    @GenericGenerator(
        name = "assigned-sequence",
        strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.StringSequenceIdentifier",
        parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "hibernate_sequence")
    )
    @GeneratedValue(generator = "assigned-sequence", strategy = GenerationType.SEQUENCE)
    private String id;

    @Version
    private Integer version;

    public Post() {
    }

    public Post(String id) {
        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }
}

现在,当您插入以下实体时:

doInJPA(entityManager -> {
    entityManager.persist(new Post());
    entityManager.persist(new Post("ABC"));
    entityManager.persist(new Post());
    entityManager.persist(new Post("DEF"));
});

Hibernate生成正确的标识符:

Query:["select nextval ('hibernate_sequence')"], Params:[()]
Query:["select nextval ('hibernate_sequence')"], Params:[()]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, CTC1)]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, ABC)]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, CTC2)]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, DEF)]

代码可在GitHub上获得。



 类似资料:
  • 问题内容: 我有以下映射 SACP表根据 当我尝试保存Sacp实例时,Hibernate抱怨 ORA-01438:此列允许的值大于指定的精度 即使使用Long而不是Integer,也会引发相同的错误 我该怎么解决? 问题答案: 我发现了这个 SEQ_GEN使用名为my_sequence的序列定义序列生成器。此基于序列的hilo算法使用的分配大小为20。请注意,此版本的Hibernate Annot

  • 要求-在二进制(20)类型的MySQL表中有主键,其中前4个字节表示当前时间戳(以秒为单位的历元),其余16个字节表示类型5(基于名称)UUID(去掉破折号)。 例如57093200aee62cab765950a48ef887bcfe87a065(57093200是历元的十六进制表示),其余是UUID的十六进制表示,不带破折号 我相信这在hibernate 4.2中是可能的,但是很难得到一个工作模

  • 比如,你用标准regex库来写一个正则表达式,但正则表达式中的反斜杠’\’其实却是一个“转义(escape)”操作符(用于特殊字符),这相当令人讨厌。考虑如何去写“由反斜杠隔开的两个词语”这样一个模式(\w\\w): string s = "\\w\\\\\\w"; // 希望它是对的(译注:不直观、不美观,且容易出错) 请注意,在正则表达式和普通C++字符串中,各自都需要使用连续两个反斜杠来

  • 问题内容: 我想使用注释指定以下hbm配置: 我不确定如何使用 我必须在每个实体类中指定吗? 我可以仅在注释下指定类名称吗? 问题答案: 请找到以下我在项目中使用过的相同代码集。

  • 本文向大家介绍C#在标识符中使用转义序列,包括了C#在标识符中使用转义序列的使用技巧和注意事项,需要的朋友参考一下 示例 转义序列不限于string和char文字。 假设您需要重写第三方方法: 并假定该字符Œ在用于C#源文件的字符编码中不可用。你是幸运的,它允许使用的类型逃逸\u####或者\U########在标识中的代码。所以写是合法的: 并且C#编译器将知道Œ并且\u0152是相同的字符。

  • 问题内容: 我有数据类/表“ User”,其中有“ preferences”列 首选项类型为TEXT,我在其中存储JSON。 所以价值是 如何使用一些注释将其包装起来,以便像 或无需包装到数据对象中 我想可能会有一些Jackson注释可以添加到字段中,例如 我对JPA相当陌生,文档非常丰富。 我相信我的情况很普遍。谁能举任何例子? 问题答案: 老实说,我认为最好的解决方案是为属性创建一个单独的表(