From e38aca8134570513435c003c25dc05f1ae51c9c9 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期四, 08 十月 2026 13:56:28 +0800
Subject: [PATCH] 实现 Ticket04:采集器辅助测量与登记入口,拆除开发模拟器
---
battery-device-neware/src/main/java/com/battery/device/neware/ReadOnlyVendorDataSource.java | 29 +++++++++++++++++++++++++++--
1 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/battery-device-neware/src/main/java/com/battery/device/neware/ReadOnlyVendorDataSource.java b/battery-device-neware/src/main/java/com/battery/device/neware/ReadOnlyVendorDataSource.java
index f682c0d..ea088fe 100644
--- a/battery-device-neware/src/main/java/com/battery/device/neware/ReadOnlyVendorDataSource.java
+++ b/battery-device-neware/src/main/java/com/battery/device/neware/ReadOnlyVendorDataSource.java
@@ -33,6 +33,12 @@
public final class ReadOnlyVendorDataSource implements DataSource
{
private static final List<String> ALLOWED_PREFIXES = List.of("select", "show", "describe", "desc");
+ /**
+ * 加锁读会真的阻塞厂商写入,所以它虽然以 {@code select} 开头也要单独拒绝:
+ * 现场实测厂商库 {@code tx_isolation=REPEATABLE-READ},行锁会挡住上位机的写库。
+ */
+ private static final List<String> LOCKING_CLAUSES = List.of("for update", "for share",
+ "lock in share mode", "updlock", "holdlock", "xlock", "tablock");
private final DataSource delegate;
private final String sourceLabel;
@@ -117,13 +123,17 @@
private void requireQuery(String sql)
{
- if (isQuery(sql))
+ boolean query = isQuery(sql);
+ boolean locking = query && containsLockingClause(sql);
+ if (query && !locking)
{
audit.recordForwarded(sql);
return;
}
audit.recordRejected(sql);
- throw new NonQueryStatementException("厂商数据源只允许查询语句:" + abbreviate(sql));
+ throw new NonQueryStatementException(locking
+ ? "厂商数据源禁止加锁读(会阻塞厂商写入):" + abbreviate(sql)
+ : "厂商数据源只允许查询语句:" + abbreviate(sql));
}
/** 只按语句首关键字判定,避免用正则近似 SQL 语法。 */
@@ -144,6 +154,21 @@
return false;
}
+ /**
+ * 语句里是否带加锁读子句。这是**语法层的拦截**,不是 SQL 解析器:厂商取数的语句由本模块固定给出,
+ * 不会把加锁子句藏在字符串常量里;新增取数语句时由 {@code ReadOnlyVendorDataSourceTest} 一起覆盖。
+ */
+ static boolean containsLockingClause(String sql)
+ {
+ if (sql == null) return false;
+ String normalized = stripLeadingComments(sql).toLowerCase(Locale.ROOT).replaceAll("\\s+", " ");
+ for (String clause : LOCKING_CLAUSES)
+ {
+ if (normalized.contains(clause)) return true;
+ }
+ return false;
+ }
+
private static String stripLeadingComments(String sql)
{
String remaining = sql.trim();
--
Gitblit v1.7.1