前言
在使用 JPA 进行数据库操作时,我们常常会遇到各种问题。本文将详细记录一次在根据roleId查询角色和权限关联表过程中遇到的报错及解决思路。
一、Jpa查询
实体类(PO)定义
在我们的项目中,定义了如下的实体类(PO,Persistent Object)来映射角色和权限关联表。
@Entity
@Table(name = "role_privilege", schema = "g-auth")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GAuthRoleMenuPO {
@Id
private String id;
private String roleId;
private String privilegeId;
}
数据访问对象(Dao)定义
为了实现对GAuthRoleMenuPO实体类的数据访问,我们定义了如下的数据访问对象(Dao,Data Access Object)。
@Repository
public interface GAuthRoleMenuDao extends JpaRepository<GAuthRoleMenuPO, String>, JpaSpecificationExecutor<GAuthRoleMenuPO> {
List<GAuthRoleMenuPO> findAllByRoleId(String roleId);
}
二、调用报错
当我们在实际应用中调用上述查询方法时,遇到了如下错误:
Caused by: org.postgresql.util.PSQLException: 错误: 语法错误 在 "-" 或附近的
位置:123
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2440)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2183)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:308)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:143)
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:106)
at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227)
三、报错信息分析
从报错信息可以看出,这是一个由 PostgreSQL 数据库抛出的语法错误。错误提示指出在某个位置(这里显示为 123)附近的-字符导致了语法问题。但是报错的类是postgresql的相关类。
在 SQL 中,模式名(schema)里包含 - 这样的特殊字符,会导致语法解析问题。大多数数据库在处理包含特殊字符的标识符时,需要进行转义。不同数据库的转义方式略有不同。
四、解决
使用双引号转义:在大多数支持 SQL 标准的数据库(如 PostgreSQL、MySQL 8.0 + 等)中,可以使用双引号来转义包含特殊字符的标识符(模式名、表名等)。在 JPA 的 @Table 注解中,可以这样修改:
@Entity
@Table(name = "role_privilege", schema = "\"g-auth\"")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GAuthRoleMenuPO {
@Id
private String id;
private String roleId;
private String privilegeId;
}
MySQL 特定处理(MySQL 8.0 之前):如果使用的是 MySQL 8.0 之前的版本,它对模式名中 - 的支持不太友好。一种解决办法是修改模式名,避免使用 - 这样的特殊字符。如果无法修改模式名,可以考虑使用存储过程或视图来间接访问数据,绕过模式名中特殊字符带来的直接访问问题。
其他数据库:不同数据库对于特殊字符的处理方式不同。例如,Oracle 中标识符默认不区分大小写(除非用双引号括起来),但同样对于包含特殊字符的标识符需要用双引号处理。在 SQL Server 中,可以使用方括号 [] 来转义标识符,不过在 JPA 的 @Table 注解中,仍然使用双引号来设置模式名,因为 JPA 会根据不同的数据库方言来正确生成 SQL 语句。
总结
记住了就行