Hibernate注释用于自动增量,但如果我们在保存之前设置它也应保存该值

时间:2017-02-14 08:11:31

标签: java postgresql hibernate

我有一个带有2个自动增量字段的表(PostgreSQL),第一个用@Id和@GeneratedValue注释,第二个应该自动递增并保存,直到我故意设置它。

有没有办法做到这一点?

@Entity
@Table(name = "route")
public class Route extends BaseEntity {

 private Integer id;
 private Integer routeNumberId;

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @Column(name = "id")
 public Integer getId() {
    return id;
 }
 ...
 @XmlAttribute
 @Id
 @Basic(optional = false)
 @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="route_number_seq")
 @GenericGenerator(name="route_number_seq",
                   strategy="com.tripms.models.master.UseIdOrGenerate")
 @Column(name = "route_number_id", nullable = false)
 public Integer getRouteNumberId() {
     return routeNumberId;
 }

}

我无法对@Id进行两次注释,而且我不想要复合pk。

1 个答案:

答案 0 :(得分:1)

混合自动增量和手动值不是一个好主意。当你的当前序列指向11时,你应该如何插入一个值为20的条目?一旦序列达到20,您将获得唯一约束违规。为了防止这种情况,您必须验证生成的序列值是否与任何现有条目冲突 - 这将引入重试,锁定等所有其他问题。

重新考虑您的模型或要求可能是个好主意,为什么第二个伪Id?为什么要手动和自动填充它? 如果您坚持使用此功能,如果您保证,手动条目不会与自动生成的条目冲突,您可以使其正常工作。然后你可以为你的真实ID“列(整数id)创建一个自定义ID生成器并覆盖generate方法,这样除了生成ID之外,你还要检查你的,伪Id的值”( routeNumberId)。如果是null,您可以要求DB从某个序列中为您提供下一个值。虚拟实现如下:

@Override
public synchronized Serializable generate(SessionImplementor session, Object object) throws HibernateException {
    Serializable result;
    if (object instanceof Route ) {
        Route reoute= ((Route ) object);
        if (route.getid() != null) {
            result = (Serializable) route.getId();
        } else {
            result = <GENERATE new ID(e.g. call super, etc)> ;
        }
        if (route.getRouteNumberId() == null) {
            long autoIncrRouteId = <GENERATE new routeID,>
            route.setRouteNumberId(autoIncrRouteId );
        }
        return result;
    } else {
        result = super.generate(session, object);
    }

    return result;
}

另一种选择是使用@PrePersist实体监听器并在那里进行检查和/或序列调用。但是,从侦听器访问实体管理器或JPA上下文可能很棘手,因为大多数JPA提供程序不完全支持注入实体侦听器。您可以进行手动jndi查找,但首先要重新考虑您尝试实现的目标。

编辑:功能Id生成器代码(postgres)。

@Override
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException {
    Connection connection = session.connection();
    try {
        Route route= ((Route ) obj);
        String seqName = "you_db_id_sequence";
        PreparedStatement ps = connection.prepareStatement("SELECT nextval ('" + seqName + "') as nextval");
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            int id = rs.getInt("nextval");
            log.info("Generated order id {} ", id);
            if (route.getRouteNumberId() == null) {
                route.setrouteNumberid(id); //or call another sequence to get a different id 
            }
            return Long.parseLong(code);
        } else {
           throw new IllegalStateException("could not generate new id");
        }
    } catch (SQLException e) {
        log.error("Could not generate id!", e);
        throw new HibernateException("Unable to generate id from Sequence");
    }
    return null;
}