简体   繁体   中英

Hibernate doesn't use PostgreSQL sequence to generate primary key

I have a Java Server Faces project using Hibernate to store data into a PostgreSQL database.

The problem I'm having is that Hibernate doesn't take the existing sequence (fifo_id_seq) into consideration while saving the data into the db; it saves with the id = 0;

The answer may be very obvious, as I'm new to Hibernate.

I'm sorry for the tons of code, but I wanted to post everything that may be relevant.

The fifo table:

                                    Table "public.fifo"
       Column        |       Type       |                     Modifiers                     
---------------------+------------------+---------------------------------------------------
 id                  | integer          | not null default nextval('fifo_id_seq'::regclass)
 number_of_processes | integer          | 
 total_time          | integer          | 
 average_time        | double precision | 
 average_wait_time   | double precision | 
 total_wait_time     | integer          | 
Indexes:
"fifo_pkey" PRIMARY KEY, btree (id)

The fifo_id_seq sequence:

         Sequence "public.fifo_id_seq"
    Column     |  Type   |        Value        
---------------+---------+---------------------
 sequence_name | name    | fifo_id_seq
 last_value    | bigint  | 1
 start_value   | bigint  | 1
 increment_by  | bigint  | 1
 max_value     | bigint  | 9223372036854775807
 min_value     | bigint  | 1
 cache_value   | bigint  | 1
 log_cnt       | bigint  | 0
 is_cycled     | boolean | f
 is_called     | boolean | f

FifoEntity.java: *note: constructors and annotations for @Id added by me, the rest is generated

@Entity
@Table(name = "fifo", schema = "public", catalog = "processmanagement")
public class FifoEntity {
private int id;
private Integer numberOfProcesses;
private Integer totalTime;
private Double averageTime;
private Double averageWaitTime;
private Integer totalWaitTime;

public FifoEntity()
{
    // empty
}

public FifoEntity(int numberOfProcesses, int totalTime, double averageTime, double averageWaitTime, int totalWaitTime)
{
    this.numberOfProcesses = numberOfProcesses;
    this.totalTime = totalTime;
    this.averageTime = averageTime;
    this.averageWaitTime = averageWaitTime;
    this.totalWaitTime = totalWaitTime;
}

@Id
@SequenceGenerator(name="fifo_pkey", sequenceName="fifo_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="fifo_pkey")
@Column(name = "id", unique = true, nullable = false)
public int getId() {
    return id;
}

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

@Basic
@Column(name = "number_of_processes")
public Integer getNumberOfProcesses() {
    return numberOfProcesses;
}

public void setNumberOfProcesses(Integer numberOfProcesses) {
    this.numberOfProcesses = numberOfProcesses;
}

@Basic
@Column(name = "total_time")
public Integer getTotalTime() {
    return totalTime;
}

public void setTotalTime(Integer totalTime) {
    this.totalTime = totalTime;
}

@Basic
@Column(name = "average_time")
public Double getAverageTime() {
    return averageTime;
}

public void setAverageTime(Double averageTime) {
    this.averageTime = averageTime;
}

@Basic
@Column(name = "average_wait_time")
public Double getAverageWaitTime() {
    return averageWaitTime;
}

public void setAverageWaitTime(Double averageWaitTime) {
    this.averageWaitTime = averageWaitTime;
}

@Basic
@Column(name = "total_wait_time")
public Integer getTotalWaitTime() {
    return totalWaitTime;
}

public void setTotalWaitTime(Integer totalWaitTime) {
    this.totalWaitTime = totalWaitTime;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    FifoEntity that = (FifoEntity) o;

    if (id != that.id) return false;
    if (averageTime != null ? !averageTime.equals(that.averageTime) : that.averageTime != null) return false;
    if (averageWaitTime != null ? !averageWaitTime.equals(that.averageWaitTime) : that.averageWaitTime != null)
        return false;
    if (numberOfProcesses != null ? !numberOfProcesses.equals(that.numberOfProcesses) : that.numberOfProcesses != null)
        return false;
    if (totalTime != null ? !totalTime.equals(that.totalTime) : that.totalTime != null) return false;
    if (totalWaitTime != null ? !totalWaitTime.equals(that.totalWaitTime) : that.totalWaitTime != null)
        return false;

    return true;
}

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + (numberOfProcesses != null ? numberOfProcesses.hashCode() : 0);
    result = 31 * result + (totalTime != null ? totalTime.hashCode() : 0);
    result = 31 * result + (averageTime != null ? averageTime.hashCode() : 0);
    result = 31 * result + (averageWaitTime != null ? averageWaitTime.hashCode() : 0);
    result = 31 * result + (totalWaitTime != null ? totalWaitTime.hashCode() : 0);
    return result;
}
}

FifoEntity mapped in hbm.xml: *

<class name="com.processmanagement.hibernate.entities.FifoEntity" table="fifo" schema="public" catalog="processmanagement">
    <id name="id" column="id">
        <generator class="sequence-identity">
            <param name="sequence">fifo_id_seq</param>
        </generator>
    </id>
    <property name="numberOfProcesses" column="number_of_processes"/>
    <property name="totalTime" column="total_time"/>
    <property name="averageTime" column="average_time"/>
    <property name="averageWaitTime" column="average_wait_time"/>
    <property name="totalWaitTime" column="total_wait_time"/>
</class>

And this is how I'm trying to save the data into the db using Hibernate:

    FifoEntity fifoEntity = new FifoEntity(processList.size(), totalTime,
            averageProcessTime, averageWaitTime, totalWaitTime);

    databaseHelper.saveOutcomeToDatabase(fifoEntity);
.
.
.
    public void saveOutcomeToDatabase(Object object)
{
//        session.beginTransaction();
//        session.save(object);
//        session.getTransaction().commit();
    Transaction transaction = session.beginTransaction();
    session.persist(object);
    transaction.commit();
    session.clear();
}

Of course, the error when trying to save a consecutive object:

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "fifo_pkey"
  Detail: Key (id)=(0) already exists.

To be able to use sequence on hibernate entity we could use @SequenceGenerator and @Generated value for example :

@Id
@Basic(optional = false)
@Column(name = "id")
@SequenceGenerator(name="third_party_seq", sequenceName="third_party_seq",allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="third_party_seq")
private Long id;

I'm using Hibernate and Postgresql. For more reference we could read from this - http://goo.gl/RQ0Dxg

Just ran into the same thing. When using Postgres sequences with Hibernate, do not set the default on the primary key column being used with the sequence, since Hibernate wants to set the sequence value itself. ie. remove this from your table definition: "default nextval('fifo_id_seq'::regclass)"

you must use GenerationType.IDENTITY if you want use postgresql default SERIAL definition like so:

@Entity
public class Foo {

    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private long fooId;

}

One thing to note is that IDENTITY generation disables batch updates as hibernate documentation says.

After hours of messing with the code, even remaking the project from scratch, I just couldn't get it to work.

Ended up with using SQL queries for saving data to the db, like so:

        session.getTransaction().begin();
        SQLQuery sqlQuery = session.createSQLQuery("INSERT into public.fifo" +
                " (number_of_processes, total_time, average_time, average_wait_time, total_wait_time) VALUES " +
                "(" +((FifoEntity) object).getNumberOfProcesses() + ", " +
                ((FifoEntity) object).getTotalTime()+ ", " +
                ((FifoEntity) object).getAverageTime() + ", " +
                ((FifoEntity) object).getAverageWaitTime() + ", " +
                ((FifoEntity) object).getTotalWaitTime() + ");");
       session.getTransaction().commit();

It's a bit messy, but it works and gives me time to get to know Hibernate better without abandoning the project or massively modifying the whole idea behind it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM