【问题标题】:Update record based on primary key composite with Timestamp type基于时间戳类型的主键组合更新记录
【发布时间】:2017-08-11 19:42:48
【问题描述】:

在从时间戳数据更新记录时,我遇到了一个棘手的问题。

技术:

  • Spring 和 Java
  • 休眠和 JPA
  • 适用于 11g 版的 Oracle 数据库

为表创建 SQL 脚本:

CREATE TABLE DOSSIER(
  NUM_DOSS NUMBER NOT NULL,
  TYPE_DOSS CHAR(4) NOT NULL,
  DATE_DOSS TIMESTAMP(6) NOT NULL,
  DSC_DOSS VARCHAR(25),
  NUM_CNFR VARCHAR(25),
  TMS_CREA TIMESTAMP(6) NOT NULL,
  TMS_MAJ TIMESTAMP(6) NOT NULL,
  CONSTRAINT PK_TDECL_RMGV PRIMARY KEY(NUM_DOSS, TYPE_DOSS, DATE_DOSS)
);

这是我的更新 SQL 请求:

UPDATE DOSSIER
    SET
        NUM_CNFR='999'
    WHERE
        NUM_DOSS_='2006103009564900' 
        and TYP_DOSS='011' 
        and DATE_DOSS= TO_TIMESTAMP('2017-08-09 16:57:03.786586', 'YYYY-MM-DD HH24:MI:SS.FF6')

您应该知道记录可以具有相同的文件夹编号和类型,但不能具有相同的日期,因为它是一个以毫秒为单位的时间戳。

例如:

NUM_DOSS           TYP_DOSS   DATE_DOSS                    NUM_CNFR
2006103009564900   | 011      | 2017-08-09 16:57:03.786586 | null
2006103009564900   | 011      | 2017-08-09 16:57:03.786589 | 0125

我的 DossierEntityPK 类:

@Embeddable
public class DossierEntityPK implements Serializable {

    private static final long serialVersionUID = -4418929855229352729L;

    @Column(name = "NUM_DOSS", nullable = false)
    private String numDossier;

    @Column(name = "TYPE_DOSS", nullable = false)
    private String typeDossier;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "DATE_DOSS", updatable = false, nullable = false,  columnDefinition="TIMESTAMP DEFAULT")
    private Date dateDossier;
}

我的 DossierEntity 类:

@Entity
@Table(name = "TDECL_RMGV")
public class OERemiseGouvModele {

    @EmbeddedId
    private DossierEntityPK dossierEntityPK;

    @Column(name = "DSC_DOSS", nullable = true)
    private String descriptionDossier;

    @Column(name = "NUM_CNFR", nullable = true)
    private String numConfirmation;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "TMS_CREA", nullable = false)
    private Date tmsCreation;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "TMS_MAJ", nullable = false)
    private Date tmsMaj;
}

现在我将向您展示我在 JPQL 中的查询:

@Modifying
@Query("UPDATE DossierEntity d SET d.numConfirmation=:numConfirmation WHERE d.dossierEntityPK.numDossier=:numDossierAND d.dossierEntityPK.typeDossier=:typeDossier AND d.dossierEntityPK.dateDossier= TO_TIMESTAMP(:dateDossier, 'YYYY-MM-DD HH24:MI:SS.FF6')")
int updateFolder(@Param("numConfirmation") String numConfirmation, @Param("numDossier") String numDossier, @Param("typeDossier") String typeDossier, @Param("dateDossier") Date dateDossier);

然后,当我从我的 Web 应用程序执行此方法时,Hibernate 的结果为空。但是,如果我直接在我的数据库上执行这个 SQL 请求更新,它就会很好地工作!

我什至使用 JDBC 或 PreparedStatement 执行此 SQL 请求,但我得到相同的空结果,然后没有更新记录。

我已经知道在 WHERE 子句中使用时间戳不是一个好主意,但工作流程以这种方式工作,我无法更改时间戳是唯一的并且是具有文件夹编号的复合主键的一部分和类型。

你知道如何解决它吗?

【问题讨论】:

  • 不知道你为什么说在WHERE 中使用时间戳是个坏主意?正如您已经说过的那样,直接在数据库上进行查询可以正常工作。您是否尝试删除WHERE 的时间戳条件并查看是否可以获得任何结果(当然测试是否是开发人员数据库)。
  • 这是一个坏主意,因为要执行更新查询或删除查询,它应该仅基于标识号,但在我的情况下,我不能只使用文件夹的标识。是的,我做到了,我只使用文件夹编号和 WHERE 条件的类型没有任何结果
  • 你能把TYPE_DOSS CHAR(4)改成TYPE_DOSS VARCHAR(4)吗?如果没有,您需要填充您传入的三字符输入。
  • Hibernate 最有可能使用当前时区偏移量转换您的 Date 对象,确保您使用 -Duser.timezone=GMT 标志运行 JVM
  • 短字符串的 Oracle 类型是 varchar2Don't use char.

标签: java sql oracle hibernate spring-data-jpa


【解决方案1】:

使用 JDBC 或 PreparedStatement 执行此 SQL 请求,记录会更新并正常工作

【讨论】:

  • 是的,我已经使用 JDBC 或 PreparedStatement 执行了我的 SQL 请求,但结果相同。无论如何,感谢@MickMnemonic,我找到了解决方案:)
猜你喜欢
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-16
  • 1970-01-01
  • 2020-07-30
  • 1970-01-01
相关资源
最近更新 更多