3

org.hibernate.id.IdentifierGenerator用来生成一个主键列,如下所示。在下面给出的示例中,目前它只是INT(11)按顺序递增类型(MySQL)的键,即它确实像auto_increment在 MySQL 中一样,但它可以用于生成任何自定义模式的值,如 E0001、E0002、E0003 ... E0010 ... E0100 ... E1000 ... E12345 ...

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;

public final class TestIdGenerator implements IdentifierGenerator {

    @Override
    public Serializable generate(SessionImplementor session, Object object) throws HibernateException {

        try {
            Connection connection = session.connection();
            PreparedStatement ps = connection.prepareStatement("SELECT MAX(id) AS id FROM test");
            ResultSet rs = ps.executeQuery();

            if (rs.next()) {
                int id = rs.getInt("id");
                return id <= 0 ? 1 : id + 1;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;
    }
}

Test使用上述 id 生成器的实体:

public class Test implements Serializable {

    @Id
    @GenericGenerator(name = "test_sequence", strategy = "com.example.TestIdGenerator")
    @GeneratedValue(generator = "test_sequence")
    @Basic(optional = false)
    @Column(name = "id", nullable = false)
    private Integer id;

    //...
}

然而,这是 Hibernate 特有的功能。有没有办法让它与提供者无关,即 JPA (2.1) 中是否有这样的功能?

我正在使用具有 JPA 2.1 的 Hibernate 5.1.0 final。


这种方法在持久化、合并和删除实体时是否会导致一些并发问题并需要某种锁定?

4

1 回答 1

2

你不能像你希望的那样使用注释来做到这一点。您可以使用@PrePersist挂钩。

@PrePersist
public void ensureId() {
    id = ...
}

也就是说,您可能无法从该@PrePersist方法访问数据库... JPA 2 规范 (JSR 317) 声明如下:

通常,可移植应用程序的生命周期方法不应调用 EntityManager 或 Query 操作、访问其他实体实例或修改同一持久性上下文中的关系。

就实现而言,Hibernate 明确禁止它:

回调方法不得调用 EntityManager 或 Query 方法!

我的建议:如果您需要指定类型,请使用序列并有一个单独的列。此外,您始终可以修改 aSELECT以撤回您选择的模式:

select 'E' || id as id from schema.table;

或者您可以使用@PostLoad/@PostPersist 拉回瞬态字段“formattedId”:

@PostLoad
@PostPersist
private void setFormattedId() {
    this.formattedId = "E" + id;
}
于 2016-05-20T18:17:46.867 回答