sql关键字作为jpa实体列名的用法

Posted

技术标签:

【中文标题】sql关键字作为jpa实体列名的用法【英文标题】:Sql keyword usage as a jpa entity column name 【发布时间】:2020-05-27 18:16:09 【问题描述】:

我正在使用 JPA 和 PostgreSQL, 我有一个错误

org.postgresql.util.PSQLException: ERROR: syntax error at or near "default"

当我想更新现有数据时,却显示错误。如何检查导致此错误的原因是什么?

这是我的代码

Resume.java

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Table(name = "resume")
public class Resume extends AuditModel implements Serializable 

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    @Column(name = "resume_id", updatable = false, nullable = false)
    private UUID id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JsonIgnore
    private User user;

    @NotNull(message = "First name may not be blank")
    @Column(name = "first_name")
    private String firstName;

    @NotNull(message = "Last name may not be blank")
    @Column(name = "last_name")
    private String lastName;

    @Column(name = "default")
    private boolean isDefault;

    @ElementCollection
    @CollectionTable(
            name = "resume_experience",
            joinColumns = @JoinColumn(name = "resume_id")
    )
    private List<Experience> experiences;

    ...


Experience.java

@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class Experience implements Serializable 

    @Column(name = "current_job")
    private boolean currentJob;

    @NotNull
    @Column(name = "start_date")
    private Date startDate;

    ...

这是更新简历的方法。 ResumeService.java

public Resume updateResume(UUID resumeId, Resume resume) throws ResumeNotFoundException 

   Resume targetResume = resumeRepository.findById(resumeId).orElseGet(null);

   if (targetResume != null)
      resume.setId(targetResume.getId());
      resume.setUser(targetResume.getUser());
      resume.setCreatedAt(targetResume.getCreatedAt());
      return resumeRepository.save(resume);
    else 
      throw new ResumeNotFoundException("Resume not found");
   

错误信息

2020-02-12 00:23:20.113 ERROR 78958 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: syntax error at or near "default"
  Position: 124
2020-02-12 00:23:20.182 ERROR 78958 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement] with root cause

org.postgresql.util.PSQLException: ERROR: syntax error at or near "default"
  Position: 124
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2505) ~[postgresql-42.2.9.jar:42.2.9]

【问题讨论】:

@Column(name = "default") - 你确定吗? default 是关键字 default 是 SQL 中的关键字,请勿将其用作列名 【参考方案1】:

根据休眠documentation:

您可以强制 Hibernate 在生成的 SQL 中引用标识符,方法是在映射文档中将表或列名括在反引号中。传统上,Hibernate 使用反引号来转义 SQL 保留关键字,而 JPA 使用双引号。

因此,您可以通过这种方式更正您的映射:

@Column(name = "`default`")
private boolean isDefault;

或者这样:

@Column(name = "\"default\"")
private boolean isDefault;

【讨论】:

【参考方案2】:

上面代码的问题是@Column(name = "default") 解决这个需要重命名“default”列名。我还用 mysql 数据库验证了相同的场景。

【讨论】:

以上是关于sql关键字作为jpa实体列名的用法的主要内容,如果未能解决你的问题,请参考以下文章

无法选择作为 SQL 关键字的列名

将jpa实体作为弹簧组件是一个好主意

在 SQL Server 存储过程中查找表名的列名作为保留关键字

7表的列名与实体类列名不对应,如何将查询结果封装到实体类对象中

SQL 常用关键字释义和用法

MySQL如何查询一个表的所有列名?