What Situation Is This?
With Spring Data JPA, you define entity classes like this.
@Entity
@Table(name = "article")
public class Article {
@Id
private Long id; // id
private String title; // title
private String description; // summary
private String group; // group the article belongs to
}
At first glance, nothing looks unusual.
Now insert data using this entity class.
When JPA Repository save runs, you can see an error like below.
To inspect runtime SQL,
hibernate.show_sqlandhibernate.format_sqlare set totrue.
Hibernate:
insert
into
Article
(description,
order, title, id)
values
(?, ?, ?, ?)
...omitted o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1064, SQLState: 42000
...omitted o.h.engine.jdbc.spi.SqlExceptionHelper : You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near 'order, title, id) values ('testtest', '1', 'test', 1)' at line 1
Why Does This Happen?
Because the message contains your MySQL server version for the right syntax to use near...,
you might think query logic is wrong. But the cause is simple.
A field declared in the entity class overlaps a reserved database word, GROUP.
Other words such as SELECT, FROM, and ORDER can also cause errors, not only in fields but also in class names.
How Do You Solve It?
First option: explicitly define column names with @Column, quoted as shown below.
@Entity
@Table(name = "article")
public class Article {
@Id
private Long id;
private String title;
private String description;
@Column(name = "\"group\"")
private String group;
}
Another option: set hibernate.globally_quoted_identifiers.
When this is true, Hibernate automatically wraps table/column names with backticks (`) when SQL runs.
So you can use keywords/reserved words in entity definitions without this issue.
Set it in yml/properties, or in Java config if you configure directly.
spring:
jpa:
properties:
hibernate:
globally_quoted_identifiers: true # add this setting
show_sql: true # print SQL
format_sql: true # pretty-print SQL
generate_statistics: true # show query execution stats
# add this setting
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
# for reference, these settings print executed SQL queries
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
# show query execution statistics
spring.jpa.properties.hibernate.generate_statistics=true
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
// ... omitted JpaVendorAdapter and Datasource setup
Properties properties = new Properties();
properties.setProperty("hibernate.globally_quoted_identifiers", "true"); // add this setting
properties.setProperty("hibernate.show_sql", "true"); // print SQL
properties.setProperty("hibernate.format_sql", "true"); // pretty-print SQL
properties.setProperty("hibernate.generate_statistics", "true"); // query execution stats
factoryBean.setJpaProperties(properties);
After enabling globally_quoted_identifiers, query output looks like this.
You can see quotes around both entity and column names.
Hibernate:
insert
into
`
Article` (
`description`, `
group`, `title`, `id`
)
values
(?, ?, ?, ?)
However, if you use native SQL via @Query, you still need to quote manually as below.
So even with global configuration, do not miss this exception case.
@Transactional
@Modifying
@Query(value = "INSERT INTO article (id, title, `group`) VALUES (:id, :title, :group)", nativeQuery = true)
void saveArticle(Long id, String title, String group);
If this handling feels cumbersome, avoiding reserved words in entity names is also a good option.