首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Hibernate 執行 Oracle SQL 報 ORA-00911 無效字符?多半是分號惹的禍

     編輯:程式設計綜合問答

在 Oracle 資料庫客戶端直接執行 SQL 正常,但放入 Hibernate createSQLQuery() 執行卻拋出 java.sql.SQLException: ORA-00911: 無效字符,這是經典的「分號陷阱」。

錯誤代碼定位

原代碼結尾拼接:

sqlsb.append(" group by bb.datetime order by bb.datetime desc);");
//                                              ↑ 這裡多了一個分號

根本原因

  • Oracle SQL*Plus、PL/SQL Developer 等客戶端工具允許以分號 ; 作為語句結束符
  • JDBC 驅動程式傳送給資料庫的是**單條純 SQL 語句**,**不需要也不允許**結尾分號
  • 分號被視為 SQL 文本的一部分,Oracle 解析器識別為無效字符 → ORA-00911

修復方案

// 錯誤
sqlsb.append(" group by bb.datetime order by bb.datetime desc);");

// 正確:移除結尾分號
sqlsb.append(" group by bb.datetime order by bb.datetime desc)");

Hibernate 執行原生 SQL 最佳實踐

1. 使用命名參數防止注入

String sql = "SELECT * FROM users WHERE create_time >= :start AND create_time <= :end";
SQLQuery query = session.createSQLQuery(sql);
query.setParameter("start", startDate);
query.setParameter("end", endDate);
List results = query.list();

2. 複雜查詢建議使用 @NamedNativeQuery

@NamedNativeQuery(
    name = "User.findByDateRange",
    query = "SELECT * FROM users WHERE create_time BETWEEN :start AND :end",
    resultClass = User.class
)

// 使用
List users = session.getNamedQuery("User.findByDateRange")
    .setParameter("start", start)
    .setParameter("end", end)
    .list();

3. 避免字串拼接 SQL,改用 StringBuilder + 參數綁定

StringBuilder sql = new StringBuilder("SELECT * FROM orders WHERE 1=1");
if (startDate != null) sql.append(" AND create_time >= :start");
if (endDate != null) sql.append(" AND create_time <= :end");
sql.append(" ORDER BY create_time DESC");

SQLQuery query = session.createSQLQuery(sql.toString());
if (startDate != null) query.setParameter("start", startDate);
if (endDate != null) query.setParameter("end", endDate);

常見 ORA-00911 其他原因

  • SQL 中包含中文全形字符(如全形分號 ;、全形括號)
  • 註釋語法錯誤(Oracle 不支援 // 單行註釋,需用 --)
  • 關鍵字拼寫錯誤導致解析器誤判
  • 多條語句未分開執行(JDBC 一次只能執行一條)

總結:Hibernate/JDBC 執行原生 SQL 時,**絕不可在語句末尾加分號**。養成使用參數綁定、命名查詢的習慣,既能避免此類語法錯誤,又能防止 SQL 注入,提升代碼可維護性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved