MyBatis插件開發(fā)的完整詳細例子(附注釋和總結(jié))

MyBatis 插件(Interceptor)允許開發(fā)者在已映射語句執(zhí)行過程中的某一點進行攔截調(diào)用,從而實現(xiàn)自定義邏輯。以下是一個完整的 MyBatis 插件開發(fā)示例,涵蓋所有使用場景,并附有詳細注釋和總結(jié)。
1. MyBatis 插件基礎(chǔ)
MyBatis 允許攔截以下接口的方法:
- Executor:
update,query,flushStatements,commit,rollback,getTransaction,close,isClosed - ParameterHandler:
getParameterObject,setParameters - ResultSetHandler:
handleResultSets,handleCursorResultSets,handleOutputParameters - StatementHandler:
prepare,parameterize,batch,update,query
2. 插件開發(fā)示例
2.1. 自定義插件類
創(chuàng)建一個自定義插件類 MyPlugin,該插件將攔截 Executor 的 query 方法和 StatementHandler 的 prepare 方法。
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.statement.StatementHandler;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 獲取被攔截方法的參數(shù)
Object[] args = invocation.getArgs();
// 攔截 Executor.query 方法
if (invocation.getTarget() instanceof Executor) {
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
RowBounds rowBounds = (RowBounds) args[2];
ResultHandler resultHandler = (ResultHandler) args[3];
BoundSql boundSql = ms.getBoundSql(parameter);
String sql = boundSql.getSql();
System.out.println("Executing SQL: " + sql);
// 執(zhí)行原方法
return invocation.proceed();
}
// 攔截 StatementHandler.prepare 方法
if (invocation.getTarget() instanceof StatementHandler) {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
Connection connection = (Connection) args[0];
Integer integer = (Integer) args[1];
// 獲取原始 SQL
BoundSql boundSql = statementHandler.getBoundSql();
String originalSql = boundSql.getSql();
System.out.println("Original SQL: " + originalSql);
// 修改 SQL(例如添加注釋)
String newSql = "/* MyPlugin */ " + originalSql;
BoundSql newBoundSql = new BoundSql(
boundSql.getMappedStatement().getConfiguration(),
newSql,
boundSql.getParameterMappings(),
boundSql.getParameterObject()
);
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
metaObject.setValue("delegate.boundSql", newBoundSql);
// 執(zhí)行原方法
return invocation.proceed();
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 使用 Plugin.wrap 包裝目標對象
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 設(shè)置插件屬性(可選)
}
}
2.2. 配置插件
在 mybatis-config.xml 中配置自定義插件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置插件 -->
<plugins>
<plugin interceptor="com.example.plugin.MyPlugin">
<!-- 可以設(shè)置插件屬性 -->
<!-- <property name="propertyName" value="propertyValue"/> -->
</plugin>
</plugins>
<!-- 其他配置... -->
</configuration>
2.3. 測試插件
編寫測試代碼來驗證插件的功能:
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
public class PluginTest {
public static void main(String[] args) throws Exception {
// 讀取 MyBatis 配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 執(zhí)行查詢操作,觸發(fā)插件攔截
User user = mapper.selectUserById(1L);
System.out.println("User: " + user.getName());
}
}
}
3. 核心使用場景
3.1. 日志記錄
在 Executor 的 query 和 update 方法中添加日志記錄,便于調(diào)試和監(jiān)控。
3.2. SQL 修改
在 StatementHandler 的 prepare 方法中修改 SQL 語句,例如添加統(tǒng)一的注釋或進行性能優(yōu)化。
3.3. 參數(shù)處理
在 ParameterHandler 的 setParameters 方法中對參數(shù)進行預(yù)處理,如加密、格式化等。
3.4. 結(jié)果集處理
在 ResultSetHandler 的 handleResultSets 方法中對結(jié)果集進行后處理,如數(shù)據(jù)脫敏、緩存等。
4. 表格整理總結(jié)
| 場景 | 攔截接口及方法 | 具體應(yīng)用 | 示例代碼片段 |
|---|---|---|---|
| 日志記錄 | Executor.query, Executor.update | 在執(zhí)行 SQL 前后記錄日志 | System.out.println("Executing SQL: " + sql); |
| SQL 修改 | StatementHandler.prepare | 修改或優(yōu)化 SQL 語句 | String newSql = "/* MyPlugin */ " + originalSql; |
| 參數(shù)處理 | ParameterHandler.setParameters | 對參數(shù)進行預(yù)處理(如加密) | preparedStatement.setString(1, encrypt(parameter)); |
| 結(jié)果集處理 | ResultSetHandler.handleResultSets | 對查詢結(jié)果進行后處理(如脫敏) | resultList.forEach(item -> item.setEmail(maskEmail(item.getEmail()))); |
| 性能監(jiān)控 | Executor.query, Executor.update | 記錄 SQL 執(zhí)行時間 | long startTime = System.currentTimeMillis(); ... long endTime = ... |
| 分頁支持 | StatementHandler.parameterize | 動態(tài)添加分頁參數(shù) | preparedStatement.setInt(1, offset); preparedStatement.setInt(2, limit); |
5. 最佳實踐建議
- 理解底層行為:在重寫方法時,需理解其底層行為,避免破壞 MyBatis 的核心功能。
- 謹慎修改 SQL:修改 SQL 時要確保語法正確,避免引入潛在的 SQL 注入風(fēng)險。
- 合理使用屬性:通過
setProperties方法為插件設(shè)置屬性,增強靈活性。 - 單元測試:編寫單元測試驗證插件功能,確保其在各種場景下的穩(wěn)定性。
- 文檔記錄:詳細記錄插件的使用方法和注意事項,便于團隊成員理解和維護。
通過以上示例和總結(jié),可以全面掌握 MyBatis 插件的開發(fā)和應(yīng)用場景。
到此這篇關(guān)于MyBatis插件開發(fā)的完整詳細例子的文章就介紹到這了,更多相關(guān)MyBatis插件開發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Runtime.getRuntime().exec 路徑包含空格的解決
這篇文章主要介紹了Runtime.getRuntime().exec 路徑包含空格的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
如何使用Java調(diào)用Linux系統(tǒng)命令
這篇文章主要介紹了如何使用Java調(diào)用Linux系統(tǒng)命令,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
@TableField(typeHandler = FastjsonTypeHandler.clas
文章總結(jié)個人前端上傳經(jīng)驗,提出了一些優(yōu)化上傳方法的建議,旨在提高上傳效率和用戶體驗,希望能為開發(fā)者提供參考2026-04-04
利用SpringMVC接收復(fù)雜對象和多個文件(前端使用JQuery)
這篇文章主要介紹了利用SpringMVC接收復(fù)雜對象和多個文件(前端使用JQuery),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
Spring boot 默認靜態(tài)資源路徑與手動配置訪問路徑的方法
這篇文章主要介紹了Spring boot 默認靜態(tài)資源路徑與手動配置訪問路徑的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-05-05

