代码之家  ›  专栏  ›  技术社区  ›  ideasculptor

hibernate+postgres中的复合id由于返回的列顺序而中断

  •  0
  • ideasculptor  · 技术社区  · 14 年前

    值(value1,value2,value3,value4)返回*“

    有问题的表有一个btime和mtime字段,它们在insert时通过触发器更新。两者都是时间戳列。这是返回的前两列。我花了一段时间试图调试hibernate,但这是一个缓慢的过程。我相信发生的事情是,第一个timestamp列被假定为生成的id列,当它试图将timestamp字符串转换为Long时,它失败了。实际上,生成的id显示为第4列。

    Caused by: org.postgresql.util.PSQLException: Bad value for type long : 2010-02-21 18:11:19.774362
     at org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong(AbstractJdbc2ResultSet.java:2796)
     at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong(AbstractJdbc2ResultSet.java:2019)
     at org.hibernate.id.IdentifierGeneratorFactory.get(IdentifierGeneratorFactory.java:104)
     at org.hibernate.id.IdentifierGeneratorFactory.getGeneratedIdentity(IdentifierGeneratorFactory.java:92)
     at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:98)
     at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
    

    我认为这与使用复合键有关,因为我在另一个应用程序中对btime和mtime列使用了几乎相同的设置,它有一个特定于hibernate的模式,在任何地方都使用生成的长id。由于btime和mtime来自db中所有其他表继承的父表,因此无法更改列的顺序。

    最终的结果是父插入和级联子插入都成功了,但是hibernate在加载子实体的生成字段失败之后抛出了一个异常。这感觉很像冬眠中的虫子,它让我停止了寒冷。我希望有人知道一个解决方法或错误修复。

    CREATE TABLE parent_stat (
          btime timestamp DEFAULT NOW() NOT NULL,  -- Birth Time or Creation Time
          mtime timestamp DEFAULT NOW() NOT NULL,   -- Modified Time
          enabled boolean DEFAULT true NOT NULL
    );
    
    CREATE TABLE portal.parent_persistent (
        version  int   DEFAULT 1     NOT NULL   -- Version Number
    );
    
    
    CREATE TABLE portal.customers
    (
      customer_id int NOT NULL,
      zone_id int NOT NULL,
      <other properties go here>
      CONSTRAINT pk_customers PRIMARY KEY (zone_id, customer_id)
    ) INHERITS (portal.parent_stat, portal.parent_persistent);
    
    CREATE TABLE portal.users
    (
      user_id bigserial NOT NULL,
      customer_zone_id int NOT NULL,
      customer_id int NOT NULL,
      <more properties here>
      CONSTRAINT pk_users_user_id PRIMARY KEY (user_id),
      CONSTRAINT fk_users_customers FOREIGN KEY (customer_zone_id, customer_id) REFERENCES customers(zone_id, customer_id) ON UPDATE RESTRICT ON DELETE RESTRICT
    ) INHERITS (portal.parent_stat, portal.parent_persistent);
    
    <hibernate-mapping>
        <class name="CustomerImpl" proxy="Customer" schema="portal" table="customers">
            <composite-id name="key" class="CustomerKeyImpl">
                <key-property name="zoneId" type="int" column="zone_id"/>
                <key-property name="customerId" type="int" column="customer_id"/>
            </composite-id>
            &version;
            &auditable;
            <set name="users" lazy="true" inverse="true" order-by="lower(email) asc" cascade="save-update,delete">
                <key>
                    <column name="customer_zone_id"/>
                    <column name="customer_id"/>
                </key>
                <one-to-many class="UserImpl"/>
            </set>
        </class>
    </hibernate-mapping>
    
    <hibernate-mapping default-lazy="true">
        <class name="UserImpl" proxy="User" schema="portal" table="users">
            <id name="id" type="java.lang.Long" column="user_id">
                <generator class="identity"/>
            </id>
            &version;
            &auditable;
            <many-to-one name="customer" class="CustomerImpl" not-null="true" cascade="save-update">
                <column name="customer_zone_id"/>
                <column name="customer_id"/>
            </many-to-one>
        </class>
    </hibernate-mapping>
    

    版本实体和可审核实体的定义如下:

    <version name="version" column="version" unsaved-value="null" type="java.lang.Long"/>
    

    <property name="created" type="java.util.Calendar" column="btime" generated="insert" insert="false" update="false"/>
    <property name="modified" type="java.util.Calendar" column="mtime" generated="always" insert="false" update="false"/>
    

    最后,将以下存储过程设置为在两个表上插入之前执行,这就是mtime的更新方式。

    CREATE OR REPLACE FUNCTION touchrow() RETURNS TRIGGER AS $$
    DECLARE
     mtime timestamp NOT NULL DEFAULT NOW();
    BEGIN
    
    NEW.mtime := mtime;
    
    RAISE DEBUG 'mtime=%', NEW.mtime;
    
    RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    

    1 回复  |  直到 14 年前
        1
  •  1
  •   ideasculptor    14 年前

    我一直没能想出解决这个问题的办法。唯一合理的解决方法是停止使用标识密钥生成,转而使用序列id生成器。这导致hibernate不尝试使用insert/update语句的'returning'子句。

    推荐文章