diff --git a/pigx-common/pigx-common-sentinel/pom.xml b/pigx-common/pigx-common-sentinel/pom.xml
index c1e6320a8..87882a35d 100755
--- a/pigx-common/pigx-common-sentinel/pom.xml
+++ b/pigx-common/pigx-common-sentinel/pom.xml
@@ -55,5 +55,15 @@
org.springframework.boot
spring-boot-jackson2
+
+ org.springframework
+ spring-tx
+ true
+
+
+ org.springframework
+ spring-jdbc
+ test
+
diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java
index ceabf12a4..49b2dc579 100644
--- a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java
+++ b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java
@@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
+import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
@@ -108,6 +109,19 @@ public class GlobalBizExceptionHandler {
return R.failed("数据库调用异常,请联系管理员处理");
}
+ /**
+ * Spring 包装的数据访问异常,避免向客户端回显 SQL 和数据库结构
+ * @param exception 数据访问异常
+ * @return 统一失败响应,不向客户端暴露底层 SQL 细节
+ */
+ @ExceptionHandler(DataAccessException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public R handleDataAccessException(DataAccessException exception) {
+ log.error("数据库调用异常 ex={}", exception.getMessage(), exception);
+ Tracer.trace(exception);
+ return R.failed("数据库调用异常,请联系管理员处理");
+ }
+
/**
* Feign 远程调用异常,透传远端 R 响应体
* @param e Feign 调用异常
diff --git a/pigx-common/pigx-common-sentinel/src/test/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandlerTests.java b/pigx-common/pigx-common-sentinel/src/test/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandlerTests.java
new file mode 100644
index 000000000..5e3caf8d7
--- /dev/null
+++ b/pigx-common/pigx-common-sentinel/src/test/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandlerTests.java
@@ -0,0 +1,39 @@
+package com.pig4cloud.pigx.common.sentinel.handle;
+
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.SphU;
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import com.pig4cloud.pigx.common.core.util.R;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpStatus;
+import org.springframework.jdbc.BadSqlGrammarException;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
+
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class GlobalBizExceptionHandlerTests {
+
+ @Test
+ void dataAccessExceptionMustNotExposeSql() throws Exception {
+ String sql = "select password, salt from sys_user where username = 'admin'";
+ BadSqlGrammarException exception = new BadSqlGrammarException("query", sql, new SQLException("syntax error"));
+ ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(GlobalBizExceptionHandler.class);
+ Method method = resolver.resolveMethodByThrowable(exception);
+
+ assertThat(method).isNotNull();
+ try (Entry entry = SphU.entry("dataAccessExceptionMustNotExposeSql")) {
+ R> result = (R>) method.invoke(new GlobalBizExceptionHandler(), exception);
+
+ assertThat(result.getCode()).isEqualTo(CommonConstants.FAIL);
+ assertThat(result.getMsg()).isEqualTo("数据库调用异常,请联系管理员处理");
+ assertThat(result.getData()).isNull();
+ assertThat(method.getAnnotation(ResponseStatus.class).value()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
+ assertThat(entry.getError()).isSameAs(exception);
+ }
+ }
+
+}