Spring Boot + JSqlParser:全面解析數據隔離最佳實踐

Spring Boot + JSqlParser:全面解析數據隔離最佳實踐

在構建多租戶系統或需要進行數據權限控制的應用時,數據隔離是一個至關重要的課題。不同租戶之間的數據隔離不僅能夠確保數據的安全性,還能提高系統的靈活性和可維護性。隨著業務的擴展和需求的變化,單純依靠傳統的分表分庫策略往往難以滿足日益復雜的業務場景,而更加精細的權限控制和數據隔離機制顯得尤為關鍵。

在這種背景下,Spring Boot結合Mybatis的強大攔截器機制,以及JSqlParser作為SQL解析工具,為我們提供了一個行之有效的解決方案。通過在數據庫訪問層對SQL進行動態過濾和改造,我們可以在不同的查詢、插入、更新、刪除操作中靈活地加入租戶信息,從而實現多租戶數據的有效隔離。本文將深入介紹如何利用這兩者的優勢,借助攔截器與SQL解析技術,在不修改現有數據結構的基礎上,實現對數據的透明隔離。

工具簡介

MyBatis 攔截器

MyBatis 提供了豐富的攔截機制,允許在 SQL 執行的各個階段插入自定義邏輯。本文將通過攔截 StatementHandler 接口的 prepare 方法來修改 SQL 語句,實現數據隔離的目標。

JSqlParser

JSqlParser 是一個開源的 SQL 解析工具,支持 SQL 語句的解析、重構等多種操作。它能夠將 SQL 字符串轉化為抽象語法樹(AST),并允許程序操作和修改 SQL 語句的各個部分。通過對解析后的 AST 進行修改(例如添加環境變量過濾條件),我們可以在 SQL 查詢中實現動態的數據隔離。

實現步驟

添加依賴
在 pom.xml 文件中添加 MyBatis 和 JSqlParser 的依賴:

<!-- MyBatis 依賴 -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version>
</dependency><!-- JSqlParser 依賴 -->
<dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>4.6</version>
</dependency>

注意:如果項目中已經使用了 MyBatis Plus,那么無需單獨添加 MyBatis 和 JSqlParser 依賴,因為 MyBatis Plus 自帶這兩個依賴并且確保它們的兼容性。避免重復添加,避免版本沖突。

定義攔截器
我們通過自定義攔截器來修改所有查詢 SQL,動態加入基于環境變量的過濾條件。

package com.icoderoad.interceptor;import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.sql.Connection;@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class DataIsolationInterceptor implements Interceptor {@Value("${spring.profiles.active}")private String env;@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object target = invocation.getTarget();if (target instanceof StatementHandler) {StatementHandler statementHandler = (StatementHandler) target;BoundSql boundSql = statementHandler.getBoundSql();String originalSql = boundSql.getSql();String newSql = applyEnvFilter(originalSql);boundSql.setSql(newSql); // 更新SQL語句}return invocation.proceed(); // 執行SQL}private String applyEnvFilter(String originalSql) {Statement statement;try {statement = CCJSqlParserUtil.parse(originalSql);} catch (JSQLParserException e) {throw new RuntimeException("SQL解析失敗: " + originalSql, e);}if (statement instanceof Select) {Select select = (Select) statement;PlainSelect selectBody = (PlainSelect) select.getSelectBody();Expression newWhereExpression = addEnvCondition(selectBody.getWhere());selectBody.setWhere(newWhereExpression);}return statement.toString(); // 返回修改后的SQL語句}private Expression addEnvCondition(Expression whereExpression) {// 生成用于數據隔離的 WHERE 條件AndExpression andExpression = new AndExpression();EqualsTo equalsTo = new EqualsTo();equalsTo.setLeftExpression(new Column("env"));equalsTo.setRightExpression(new StringValue(env));if (whereExpression == null) {return equalsTo;} else {andExpression.setLeftExpression(whereExpression);andExpression.setRightExpression(equalsTo);return andExpression;}}
}

測試查詢
假設有以下 SQL 查詢:

<select id="queryAllByOrgLevel" resultType="com.icoderoad.entity.AllInfo">SELECT a.username, a.code, o.org_code, o.org_name, o.levelFROM admin aLEFT JOIN organize o ON a.org_id = o.idWHERE a.dr = 0 AND o.level = #{level}
</select>

修改前:
原始 SQL 查詢:

SELECT a.username, a.code, o.org_code, o.org_name, o.level
FROM admin a
LEFT JOIN organize o ON a.org_id = o.id
WHERE a.dr = 0 AND o.level = ?

修改后:
經過攔截器處理后:

SELECT a.username, a.code, o.org_code, o.org_name, o.level
FROM admin a
LEFT JOIN organize o ON a.org_id = o.id
WHERE a.dr = 0 AND o.level = ? AND a.env = 'test' AND o.env = 'test'

其他操作
對于 INSERT、UPDATE 和 DELETE 操作,我們同樣可以在 SQL 語句中添加 env 字段:

INSERT
在插入數據時,env 字段會自動添加到 SQL 語句中:

INSERT INTO admin (id, username, code, org_id, env) VALUES (?, ?, ?, ?, 'test')
UPDATE

更新操作會在 WHERE 子句中添加 env 條件:

UPDATE admin SET username = ?, code = ?, org_id = ? WHERE id = ? AND env = 'test'

DELETE
刪除操作也會被加上 env 條件:

DELETE FROM admin WHERE id = ? AND env = 'test'

為什么攔截 prepare 方法?
在 MyBatis 中,prepare 方法負責準備 SQL 語句和參數綁定,而 query 和 update 方法主要執行已經準備好的 PreparedStatement。通過攔截 prepare 方法,我們可以確保 SQL 在執行前就已經被修改,從而實現對數據隔離的控制。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/896252.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/896252.shtml
英文地址,請注明出處:http://en.pswp.cn/news/896252.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

51單片機編程學習筆記——點亮LED

大綱 器件51單片機開發板總結 安裝驅動點亮LED燒錄 隨著最近機器人爆火&#xff0c;之前寫的ROS2系列博客《Robot Operating System》也獲得了更多的關注。我決定在機器人領域里再走一步&#xff0c;于是想到可以學習單片機。研究了下學習路徑&#xff0c;最后還是選擇先從51單…

Java String 類

Java String 類常用方法詳解 在 Java 編程里&#xff0c;字符串操作十分常見&#xff0c;而 String 類作為 Java 標準庫的核心類&#xff0c;用于表示不可變的字符序列。任何對字符串的修改操作都會返回一個新的字符串對象&#xff0c;不會改變原始字符串。本文將詳細介紹 Str…

9.【線性代數】—— 線性相關性, 向量空間的基,維數

九 線性相關性&#xff0c; 向量空間的基&#xff0c;維數 Ax0 什么情況下無解(x不為零向量)1. 向量組的線性無關性2.向量組生成一個空間(S)3. 向量空間的一組基&#xff1a;都滿足向量個數相同4. 空間維數 基向量的個數 Ax0 什么情況下無解(x不為零向量) Ax0無解&#xff0c…

藍橋杯單片機組第十二屆省賽第二批次

前言 第十二屆省賽涉及知識點&#xff1a;NE555頻率數據讀取&#xff0c;NE555頻率轉換周期&#xff0c;PCF8591同時測量光敏電阻和電位器的電壓、按鍵長短按判斷。 本試題涉及模塊較少&#xff0c;題目不難&#xff0c;基本上準備充分的都能完整的實現每一個功能&#xff0c;并…

opencv:距離變換 cv2.distanceTransform

函數 cv2.distanceTransform() 用于計算圖像中每一個非零點像素與其最近的零點像素之間的距離&#xff08;Distance Transform&#xff0c; DT算法&#xff09;,輸出的是保存每一個非零點與最近零點的距離信息&#xff1b;圖像上越亮的點&#xff0c;代表了離零點的距離越遠。 …

基于Spring Boot的黨員學習交流平臺設計與實現(LW+源碼+講解)

專注于大學生項目實戰開發,講解,畢業答疑輔導&#xff0c;歡迎高校老師/同行前輩交流合作?。 技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;…

自動駕駛兩個傳感器之間的坐標系轉換

有兩種方式可以實現兩個坐標系的轉換。 車身坐標系下一個點p_car&#xff0c;需要轉換到相機坐標系下&#xff0c;旋轉矩陣R_car2Cam&#xff0c;平移矩陣T_car2Cam。點p_car在相機坐標系下記p_cam. 方法1&#xff1a;先旋轉再平移 p_cam T_car2Cam * p_car T_car2Cam 需要注…

k8s ssl 漏洞修復

針對Kubernetes集群中SSL/TLS協議信息泄露漏洞&#xff08;CVE-2016-2183&#xff09;的修復&#xff0c;需重點修改涉及弱加密算法的組件配置。以下是具體修復步驟及驗證方法&#xff1a; 一、漏洞修復步驟 1. 修復etcd服務 修改配置文件 &#xff1a; 編輯 /etc/kubernetes/…

數字IC后端培訓教程| 芯片后端實戰項目中base layer drc violation解析

今天分享一個咱們社區IC后端訓練營學員遇到的一個經典DRC案例。這個DRC Violation的名字為PP.S.9(這里的PP就是Plus P)。這一層是屬于管子的base layer。更多關于base layer的介紹&#xff0c;可以查看下面這份教程。 https://alidocs.dingtalk.com/api/doc/transit?spaceId5…

從零到一學習c++(基礎篇--筑基期十一-類)

從零到一學習C&#xff08;基礎篇&#xff09; 作者&#xff1a;羨魚肘子 溫馨提示1&#xff1a;本篇是記錄我的學習經歷&#xff0c;會有不少片面的認知&#xff0c;萬分期待您的指正。 溫馨提示2&#xff1a;本篇會盡量用更加通俗的語言介紹c的基礎&#xff0c;用通俗的語言去…

DeepSeek技術全景解析:架構創新與行業差異化競爭力

一、DeepSeek技術體系的核心突破 架構設計&#xff1a;效率與性能的雙重革新 Multi-head Latent Attention (MLA)&#xff1a;通過將注意力頭維度與隱藏層解耦&#xff0c;實現顯存占用降低30%的同時支持4096超長上下文窗口。深度優化的MoE架構&#xff1a;結合256個路由專家…

插入排序:一種簡單而直觀的排序算法

大家好&#xff01;今天我們來聊聊一個簡單卻非常經典的排序算法——插入排序&#xff08;Insertion Sort&#xff09;。在所有的排序算法中&#xff0c;插入排序是最直觀的一個。 一、插入排序的基本思想 插入排序的核心思想是&#xff1a;將一個待排序的元素&#xff0c;插…

2025年校園網絡招聘會匯總

1、衛生健康行業2025屆畢業生春季校園網絡招聘會 企業數量職位數量崗位數量10020002000 訪問地址&#xff1a; https://www.weirenjob.com/zph/zph_wsjkxy2025jbyscjxywlzph/ 2、山東地區面向2025屆高校畢業生網絡招聘活動 企業數量職位數量崗位數量909271052434 訪問地址&a…

Windows 10 GPU STACK 0.5.1 安裝

Windows 10 GPU STACK 0.5.1 安裝 1 GPUStack 安裝1.Python安裝&#xff08;3.10/11/12&#xff09;2.GPUStack 下載3.生成密碼4.訪問5.設置模型下載目錄6.禁用開機自啟并重啟服務7.安裝模型8.查看安裝的進度 2.試驗場聊天測試1.對話模式 3.API Key 測試 1 GPUStack 安裝 1.Py…

【數據結構】快指針和慢指針

一、 給你單鏈表的頭結點 head ,請你找出并返回鏈表的中間結點。如果有兩個中間結點,則返回第二個中間結點。 要求&#xff1a;只遍歷一遍鏈表 可以使用快慢指針&#xff1a;fast 一次走兩步&#xff0c;slow 一次走一步。當 fast NULL&#xff08;偶數個結點&#xff09;或…

1.3 嵌入式系統的固件

嵌入式系統的固件&#xff0c;一般情況下的作用是: 1.硬件抽象層&#xff08;HAL&#xff09;&#xff1a;固件提供了一個硬件抽象層&#xff0c;它將硬件的復雜性隱藏起來&#xff0c;為上層軟件提供了一套標準的接口。這樣&#xff0c;操作系統和應用程序不需要直接與硬件打交…

中國工業互聯網研究院:人工智能大模型年度發展趨勢報告

當前&#xff0c;以大模型為代表的人工智能正快速演進&#xff0c;激發全球科技之變、產業之變、時代之變&#xff0c;人工智能發展迎來新高潮。隨著大模型推理、多模態生成、智能體等創新技術的發展&#xff0c;大模型賦能千行百業將進一步提速。中國工業互聯網研究院全方位剖…

【cv】vs2022配置opencv

release下配置包含目錄和庫目錄 E:\sdk\sdk_cuda12.3\opencv490\include E:\sdk\sdk_cuda12.3\opencv490\include\opencv2 E:\sdk\sdk_cuda12.3\opencv490\lib release下配置包含鏈接器輸入的依附依賴項 opencv_world490.lib release編譯文件夾下需手動復制opencv_world49…

Python Pandas庫使用指南:從入門到精通

1. 引言 Pandas 是 Python 中用于數據處理和分析的核心庫之一。它提供了高效的數據結構(如 DataFrame 和 Series),能夠輕松處理結構化數據,支持數據清洗、過濾、聚合、合并等操作。Pandas 在數據分析、機器學習和科學計算領域中被廣泛使用。 本文將詳細介紹 Pandas 的基本…

Visual Studio中打開多個項目

1) 找到解決方案窗口 2) 右鍵添加→ 選擇現有項目 3) 選擇.vcxproj文件打開即可