我在Oracle中有一个表,带有带时区(TIMESTAMPTZ)列类型的时间戳 . 我还在此表上有一个触发器,用于将传入时间戳从本地时区(EST)转换为GMT . 当我使用SqlPlus / SQL Developer将数据插入表时,触发器运行良好并正确转换时区 . 但是当我尝试从Java应用程序插入数据(使用JPA / EclipseLink)时,时间四舍五入到最接近的整秒(丢失小数部分) . 如果禁用触发器,则会正确插入时间,但在本地时区除外 .

我知道我可以通过在我的Java应用程序中执行GMT转换来解决这个问题 . 但是,有多种方法可以将数据插入到此表中,并且需要更改许多应用程序,一些Java和一些SQL . 因此,我们在触发器中执行转换更方便 . 以前有人遇到过这个吗?任何帮助修复扳机将不胜感激 .

样本记录,

触发器从Java禁用或从SQL开发人员插入

Id      TS_COL                          TS_TZ_COL
101     21-FEB-16 13.10.10.223000000    21-FEB-16 13.10.10.223000000 AMERICA/NEW_YORK

插入时启用触发器

Id      TS_COL                          TS_TZ_COL
103     21-FEB-16 14.22.02.654000000    21-FEB-16 19.22.02.000000000 GMT

这是一个用来说明问题的小例子 . 我正在使用Oracle 12.1.0并在Redhat Enterprise和Windows 10上运行的两个实例上都尝试过这个 . 任何帮助都会很有用 .

表和触发器定义

CREATE TABLE TZ_TEST (  myid  NUMBER (4,0) not null primary key, TS_COL TIMESTAMP (6), TS_TZ_COL TIMESTAMP (6) WITH TIME ZONE)


CREATE OR REPLACE 
TRIGGER TZ_TEST_TRIGGER 
BEFORE INSERT OR UPDATE ON TZ_TEST 
REFERENCING OLD AS OLD NEW AS NEW 
FOR EACH ROW
BEGIN
   IF (:NEW.TS_TZ_COL is not null)
   THEN
      :NEW.TS_TZ_COL := (from_tz(cast(:NEW.TS_TZ_COL as timestamp), 'America/New_York') at time zone 'GMT');
   END IF;
END;

JPA实体

import java.io.Serializable;
import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="TZ_TEST")
public class TzTest implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="myid")
    private long id;

    @Column(name="TS_COL")
    private Timestamp tsCol;

    @Column(name="TS_TZ_COL")
    private Timestamp tsTzCol;

    public TzTest() {
    }

    public long getId() {
        return this.id;
    }

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

    public Timestamp getTsCol() {
        return this.tsCol;
    }

    public void setTsCol(Timestamp tsCol) {
        this.tsCol = tsCol;
    }

    public Timestamp getTsTzCol() {
        return this.tsTzCol;
    }

    public void setTsTzCol(Timestamp tsTzCol) {
        this.tsTzCol = tsTzCol;
    }

}

测试插入记录的代码

@Test
public void test() throws ParseException {      
    Timestamp ts1 = new Timestamp(System.currentTimeMillis());
    TzTest tzTest1 = new TzTest();
    tzTest1.setId(103);
    tzTest1.setTsCol(ts1);
    tzTest1.setTsTzCol(ts1);

    em.getTransaction().begin();
    em.persist(tzTest1);
    em.getTransaction().commit();

}