日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Mabtyis无侵入式编程

發布時間:2024/10/5 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mabtyis无侵入式编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

場景:最近碰到一個問題,本身項目擁有開源入軟件包,我需要按時間維度對數據進行歸檔,但是因為我引用的軟件包也引用了這些表的數據,我一旦刪除數據,可能導致部分原生接口報錯。所以我需要在不能修改原生接口的情況下,但是這個軟件包使用的mybatis作為持久化框架,那么我需要考慮的就是如何對在mybatis調用查詢接口之前,修改原生接口的表名,使之查詢我歸檔之后的表。

首先我們需要來復習一下mybatis的知識:

原生mybatis:

1.先看一個mybatis最簡單的Demo

1.先看一個mybatis最簡單的DemoString resource = "mybatis-config.xml"; //1.流形式讀取mybatis配置文件 InputStream stream = Resources.getResourceAsStream(resource); //2.通過配置文件創建SqlSessionFactory SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(stream); //3.通過SqlSessionFactory創建sqlSession SqlSession session = sessionFactory.openSession(); //4.通過SqlSession執行Sql語句獲取結果 List<User> userList = session.selectList("selectAll"); System.out.println(userList.size());

1.通過InputStream獲取mybatis的配置文件(mybatis-config.xml 為 MyBatis 的全局配置文件,配置了 MyBatis 的運行環境等信息,例如數據庫連接信息和映射文件,映射文件即 SQL 映射文件,該文件中配置了操作數據庫的 SQL 語句,需要在 MyBatis 配置文件 mybatis-config.xml 中加載。mybatis-config.xml 文件可以加載多個映射文件,每個文件對應數據庫中的一張表

2.通過SqlSessionFactoryBuilder創建SqlSessionFactory(通過 MyBatis 的環境等配置信息構建會話工廠 SqlSessionFactory

3.通過SqlSessionFactory創建一個SqlSession(由會話工廠創建 SqlSession 對象,該對象中包含了執行 SQL 語句的所有方法

5)Executor 執行器:MyBatis 底層定義了一個 Executor 接口來操作數據庫,它將根據 SqlSession 傳遞的參數動態地生成需要執行的 SQL 語句,同時負責查詢緩存的維護。
6)MappedStatement 對象:在 Executor 接口的執行方法中有一個 MappedStatement 類型的參數,該參數是對映射信息的封裝,用于存儲要映射的 SQL 語句的 id、參數等信息。
7)輸入參數映射:輸入參數類型可以是 Map、List 等集合類型,也可以是基本數據類型和 POJO 類型。輸入參數映射過程類似于 JDBC 對 preparedStatement 對象設置參數的過程。
8)輸出結果映射:輸出結果類型可以是 Map、 List 等集合類型,也可以是基本數據類型和 POJO 類型。輸出結果映射過程類似于 JDBC 對結果集的解析過程。

源碼分析:https://www.cnblogs.com/jackion5/p/9477798.html

總結:

1.先獲取mybatis的配置文件,解析成流對象(字符流和字節流都可以)Reader和InputStream都可以

2.通過SqlSessionFactoryBuilder根據mybatis的配置文件流創建一個Configuration對象

3.SqlSessionFactoryBuilder根據Configuration對象創建一個DefaultSqlSessionFactory(SqlSessionFactory的默認實現類)

4.DefaulatSqlSessionFacotry根據傳入的參數,創建一個DefaultSqlSession對象(SqlSession的默認實現類)

這里重點介紹下Configuration:
Configuration類位于mybatis包的org.apache.ibatis.session目錄下,是mybatis的全局變量,屬性就是對應于mybatis的全局配置文件mybatis-config.xml的配置,將XML配置中的內容解析賦值到Configuration對象中。

由于XML配置項有很多,所以Configuration類的屬性也很多。先來看下Configuration對于的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><!-- 屬性配置,讀取properties中的配置文件 --><properties resource="db.propertis"><property name="XXX" value="XXX"/></properties><!-- 類型別名 --><typeAliases><!-- 在用到User類型的時候,可以直接使用別名,不需要輸入User類的全部路徑 --><typeAlias type="com.luck.codehelp.entity.User" alias="user"/></typeAliases><!-- 類型處理器 --><typeHandlers><!-- 類型處理器的作用是完成JDBC類型和java類型的轉換,mybatis默認已經由了很多類型處理器,正常無需自定義--></typeHandlers><!-- 對象工廠 --><!-- mybatis創建結果對象的新實例時,會通過對象工廠來完成,mybatis有默認的對象工廠,正常無需配置 --><objectFactory type=""></objectFactory><!-- 插件 --><plugins><!-- 可以自定義攔截器通過plugin標簽加入 --><plugin interceptor="com.lucky.interceptor.MyPlugin"></plugin></plugins><!-- 全局配置參數 --><settings><setting name="cacheEnabled" value="false" /><setting name="useGeneratedKeys" value="true" /><!-- 是否自動生成主鍵 --><setting name="defaultExecutorType" value="REUSE" /><setting name="lazyLoadingEnabled" value="true"/><!-- 延遲加載標識 --><setting name="aggressiveLazyLoading" value="true"/><!--有延遲加載屬性的對象是否延遲加載 --><setting name="multipleResultSetsEnabled" value="true"/><!-- 是否允許單個語句返回多個結果集 --><setting name="useColumnLabel" value="true"/><!-- 使用列標簽而不是列名 --><setting name="autoMappingBehavior" value="PARTIAL"/><!-- 指定mybatis如何自動映射列到字段屬性;NONE:自動映射;PARTIAL:只會映射結果沒有嵌套的結果;FULL:可以映射任何復雜的結果 --><setting name="defaultExecutorType" value="SIMPLE"/><!-- 默認執行器類型 --><setting name="defaultFetchSize" value=""/><setting name="defaultStatementTimeout" value="5"/><!-- 驅動等待數據庫相應的超時時間 ,單位是秒--><setting name="safeRowBoundsEnabled" value="false"/><!-- 是否允許使用嵌套語句RowBounds --><setting name="safeResultHandlerEnabled" value="true"/><setting name="mapUnderscoreToCamelCase" value="false"/><!-- 下劃線列名是否自動映射到駝峰屬性:如user_id映射到userId --><setting name="localCacheScope" value="SESSION"/><!-- 本地緩存(session是會話級別) --><setting name="jdbcTypeForNull" value="OTHER"/><!-- 數據為空值時,沒有特定的JDBC類型的參數的JDBC類型 --><setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/><!-- 指定觸發延遲加載的對象的方法 --><setting name="callSettersOnNulls" value="false"/><!--如果setter方法或map的put方法,如果檢索到的值為null時,數據是否有用 --><setting name="logPrefix" value="XXXX"/><!-- mybatis日志文件前綴字符串 --><setting name="logImpl" value="SLF4J"/><!-- mybatis日志的實現類 --><setting name="proxyFactory" value="CGLIB"/><!-- mybatis代理工具 --></settings><!-- 環境配置集合 --><environments default="development"><environment id="development"><transactionManager type="JDBC"/><!-- 事務管理器 --><dataSource type="POOLED"><!-- 數據庫連接池 --><property name="driver" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8" /><property name="username" value="root" /><property name="password" value="*****" /></dataSource></environment></environments><!-- mapper文件映射配置 --><mappers><mapper resource="com/luck/codehelp/mapper/UserMapper.xml"/></mappers> </configuration>

而對于XML的配置,Configuration類的屬性是和XML配置對應的。Configuration類屬性如下:

protected Environment environment;//運行環境protected boolean safeRowBoundsEnabled = false;protected boolean safeResultHandlerEnabled = true;protected boolean mapUnderscoreToCamelCase = false;protected boolean aggressiveLazyLoading = true; //true:有延遲加載屬性的對象被調用時完全加載任意屬性;false:每個屬性按需要加載protected boolean multipleResultSetsEnabled = true;//是否允許多種結果集從一個單獨的語句中返回protected boolean useGeneratedKeys = false;//是否支持自動生成主鍵protected boolean useColumnLabel = true;//是否使用列標簽protected boolean cacheEnabled = true;//是否使用緩存標識protected boolean callSettersOnNulls = false;//protected boolean useActualParamName = true;protected String logPrefix;protected Class <? extends Log> logImpl;protected Class <? extends VFS> vfsImpl;protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;protected JdbcType jdbcTypeForNull = JdbcType.OTHER;protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));protected Integer defaultStatementTimeout;protected Integer defaultFetchSize;protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;//指定mybatis如果自動映射列到字段和屬性,PARTIAL會自動映射簡單的沒有嵌套的結果,FULL會自動映射任意復雜的結果protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;protected Properties variables = new Properties();protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();protected ObjectFactory objectFactory = new DefaultObjectFactory();protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();protected boolean lazyLoadingEnabled = false;//是否延時加載,false則表示所有關聯對象即使加載,true表示延時加載protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNLprotected String databaseId;protected Class<?> configurationFactory;protected final MapperRegistry mapperRegistry = new MapperRegistry(this);protected final InterceptorChain interceptorChain = new InterceptorChain();protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");protected final Set<String> loadedResources = new HashSet<String>(); //已經加載過的resource(mapper)protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();protected final Map<String, String> cacheRefMap = new HashMap<String, String>();

而Configuration中的方法也差不多都是關于這些屬性的set和get方法。由于屬性太多,就不一一解析,現在只知道Configuration類是和mybatis的XML配置是對應的。加載的過程是SqlSessionFactoryBuilder根據xml配置的文件流,通過XMLConfigBuilder的parse方法進行解析得到一個Configuration對象。那么Configuration什么時候會用到呢?

由之前解析可知,mybatis啟動的時候會加載XML配置文件解析生成全局配置對象Configuration對象,SqlSessionFactoryBuilder類會根據Configuration對象創建一個DefaultSqlSessionFactory對象,而DefaultSqlSessionFactory對象實現了SqlSessionFactory中的創建SqlSession的方法,最終新建了一個SqlSession接口的默認實現類DefaultSqlSession,sql的具體執行是通過調用SqlSession接口的對應的方法去執行的,而SqlSession最終都是通過調用了自己的Executor對象的query和update去執行的。

package org.apache.ibatis.session;import java.io.Closeable; import java.sql.Connection; import java.util.List; import java.util.Map;import org.apache.ibatis.cursor.Cursor; import org.apache.ibatis.executor.BatchResult;public interface SqlSession extends Closeable {//根據Sql語句查詢單條記錄<T> T selectOne(String statement);<T> T selectOne(String statement, Object parameter);//根據Sql語句和參數查詢單條記錄//根據Sql語句查詢多條記錄<E> List<E> selectList(String statement);<E> List<E> selectList(String statement, Object parameter);//根據Sql語句和參數查詢多條記錄<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);//根據Sql語句和參數以及分頁參數查詢多條記錄//selectMap和selectList原理一樣,只是將結果集映射成Map對象返回<K, V> Map<K, V> selectMap(String statement, String mapKey);<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);//返回游標對象<T> Cursor<T> selectCursor(String statement);<T> Cursor<T> selectCursor(String statement, Object parameter);<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);//查詢的結果對象由指定的ResultHandler處理void select(String statement, Object parameter, ResultHandler handler);void select(String statement, ResultHandler handler);void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);//執行insert語句int insert(String statement);int insert(String statement, Object parameter);//執行update語句int update(String statement);int update(String statement, Object parameter);//執行delete語句int delete(String statement);int delete(String statement, Object parameter);//提交事務void commit();void commit(boolean force);//事務回滾void rollback();void rollback(boolean force);//將請求刷新到數據庫List<BatchResult> flushStatements();//關閉sqlSession@Overridevoid close();//清除緩存void clearCache();//獲取Configuration對象Configuration getConfiguration();//獲取Type對象的Mapper對象<T> T getMapper(Class<T> type);//獲取sqlSession對象的數據庫連接Connection getConnection(); }

以select方法為例,最終都是調用了selectList方法,然后調用configuration的getMapped的Statement方法獲取MappedStatement對象,然后調用執行器executor的query方法獲取查詢結果

由此可得出結論sqlSession雖然叫程序和數據庫之間的SQL會話,但是它并沒有具體去執行sql語句,最終的sql語句的執行是由執行器Executor執行的,而SqlSession的作用只是創建了MappedStatement對象以及調用執行器去執行SQL

其他的commit、rollback方法同樣最終都是調用的執行器Executor的對應的方法,那么接下來就去了解下執行器Executor是干嘛的

Executor是mybatis的sql執行器,SqlSession是面向程序的,而Executor則就是面向數據庫的,先看下Executor接口的方法有哪些,源碼如下:

public interface Executor {ResultHandler NO_RESULT_HANDLER = null;int update(MappedStatement ms, Object parameter) throws SQLException;<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;List<BatchResult> flushStatements() throws SQLException;void commit(boolean required) throws SQLException;void rollback(boolean required) throws SQLException;CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);boolean isCached(MappedStatement ms, CacheKey key);void clearLocalCache();void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);Transaction getTransaction();void close(boolean forceRollback);boolean isClosed();void setExecutorWrapper(Executor executor);

和SqlSession一樣定義了各種各樣的sql執行的方法,有查詢的query方法,有更新的update方法,以及和事務有關的commit方法和rollback方法等,接下來就以query方法為例,看下具體是如何執行的。

Executor接口共有兩個實現類,分別是BaseExecutor和CachingExecutor,CachingExecutor是緩存執行器,后面會提到,現在先看下BaseExecutor

BaseExecutor會優先從緩存中查詢數據,如果緩存不為空再從數據庫數

BaseExecutor共有SimpleExecutor、ReuseExecutor、BatchExecutor以及ClosedExecutor四個子類,這個后面再分析,現在我們以及知道了SqlSession是調用了Executor的方法來執行sql,而Executor的默認實現類的BaseExecutor,而BaseExecutor又是調用了其子類的方法。而BaseExecutor則對查詢的結果進行了緩存處理以及查詢的時候會從緩存中進行查詢。

Executor中的大部分方法的調用鏈其實是差不多的,下面都是深入源碼分析執行過程,如果你沒有時間或者暫時不想深入研究的話,給你下面的執行流程圖作為參考。

?

Executor初始化

首先我們先了解一下mybatis是怎么樣生成executor的。我們看到生成Executor的地方(org.apache.ibatis.session.Configuration):

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor executor;if (ExecutorType.BATCH == executorType) {executor = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {executor = new SimpleExecutor(this, transaction);}if (cacheEnabled) {executor = new CachingExecutor(executor);}executor = (Executor) interceptorChain.pluginAll(executor);return executor;}


這里大部分都很好理解,但是有個地方就好不好理解,它就是:

executor = (Executor) interceptorChain.pluginAll(executor);

這是一段非常重要的代碼,它是采用責任鏈模式,來產生代理對象。我們需要再深入理解它,打開它具體的pluginAll方法:

public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;}


我們這里先介紹一下這段代碼:

Interceptor它是mybatis攔截器必須要實現的接口,換句話說,這個遍歷就是遍歷mybatis的攔截器。

然后調用plugin方法,這個方法是為了生成代理對象(占位)的。

于是可以想象我們的插件的代理對象將會是一層層的嵌套,所以當中任何一個插件(Interceptor)都有機會攔截這個真是的服務對象(executor),則便是責任鏈模式,我們完全可以提供插件(Interceptor),進入到代理對象的invoke方法里面,來改變executor的行為和方法。

這里確定我們需要自定義攔截器,并在生成Executor的時候將其設置進去。

mybatis-spring

MyBatis-Spring 會幫助你將 MyBatis 代碼無縫地整合到 Spring 中。它將允許 MyBatis 參與到 Spring 的事務管理之中,創建映射器 mapper 和?SqlSession?并注入到 bean 中,以及將 Mybatis 的異常轉換為 Spring 的?DataAccessException。 最終,可以做到應用代碼不依賴于 MyBatis,Spring 或 MyBatis-Spring。

要和 Spring 一起使用 MyBatis,需要在 Spring 應用上下文中定義至少兩樣東西:一個?SqlSessionFactory?和至少一個數據映射器類。

在基礎的 MyBatis 用法中,是通過?SqlSessionFactoryBuilder?來創建?SqlSessionFactory?的。而在 MyBatis-Spring 中,則使用?SqlSessionFactoryBean?來創建。

要創建工廠 bean,將下面的代碼放到 Spring 的 XML 配置文件中:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /> </bean>

需要注意的是?SqlSessionFactoryBean?實現了 Spring 的?FactoryBean?接口(參見 Spring 官方文檔 3.8 節?通過工廠 bean 自定義實例化邏輯?)。 這意味著由 Spring 最終創建的 bean?并不是?SqlSessionFactoryBean?本身,而是工廠類(SqlSessionFactoryBean)的 getObject() 方法的返回結果。這種情況下,Spring 將會在應用啟動時為你創建?SqlSessionFactory,并使用?sqlSessionFactory?這個名字存儲起來。

等效的 Java 代碼如下:

@Configuration public class MyBatisConfig {@Beanpublic SqlSessionFactory sqlSessionFactory() {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource());return factoryBean.getObject();} }

通常,在 MyBatis-Spring 中,你不需要直接使用?SqlSessionFactoryBean?或對應的?SqlSessionFactory。 相反,session 的工廠 bean 將會被注入到?MapperFactoryBean?或其它繼承于?SqlSessionDaoSupport?的 DAO(Data Access Object,數據訪問對象)中。這里我們使用

SpringBoot 自定義 Mybatis 攔截器,實現 SQL 的改寫

1、攔截器應用場景:

(1)分頁,如com.github.pagehelper的分頁插件實現。

(2)攔截sql做日志監控;

(3)統一對某些sql進行統一條件拼接,類似于分頁。

2、相關配置類實現:

(1)MySqlInterceptor 類:

package spcommon.config;import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.*; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.util.Properties;/*** 自定義 MyBatis 攔截器*/ @Intercepts({@Signature(type = Executor.class, method = "query",args = {MappedStatement.class, Object.class, RowBounds.class,ResultHandler.class})}) public class MySqlInterceptor implements Interceptor {private static final Logger logger= LoggerFactory.getLogger(MySqlInterceptor.class);/*** intercept 方法用來對攔截的sql進行具體的操作* @param invocation* @return* @throws Throwable*/@Overridepublic Object intercept(Invocation invocation) throws Throwable {logger.info("執行intercept方法:{}", invocation.toString());Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement) args[0];Object parameterObject = args[1];// id為執行的mapper方法的全路徑名,如com.mapper.UserMapperString id = ms.getId();// sql語句類型 select、delete、insert、updateString sqlCommandType = ms.getSqlCommandType().toString();// 僅攔截 select 查詢//if (!sqlCommandType.equals(SqlCommandType.SELECT.toString())) {// return invocation.proceed();//}BoundSql boundSql = ms.getBoundSql(parameterObject);String origSql = boundSql.getSql();logger.info("原始SQL: {}", origSql);// 組裝新的 sqlString newSql = origSql + " limit 1";// 重新new一個查詢語句對象BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), newSql,boundSql.getParameterMappings(), boundSql.getParameterObject());// 把新的查詢放到statement里MappedStatement newMs = newMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));for (ParameterMapping mapping : boundSql.getParameterMappings()) {String prop = mapping.getProperty();if (boundSql.hasAdditionalParameter(prop)) {newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));}}Object[] queryArgs = invocation.getArgs();queryArgs[0] = newMs;logger.info("改寫的SQL: {}", newSql);return invocation.proceed();}/*** 定義一個內部輔助類,作用是包裝 SQL*/class BoundSqlSqlSource implements SqlSource {private BoundSql boundSql;public BoundSqlSqlSource(BoundSql boundSql) {this.boundSql = boundSql;}public BoundSql getBoundSql(Object parameterObject) {return boundSql;}}private MappedStatement newMappedStatement (MappedStatement ms, SqlSource newSqlSource) {MappedStatement.Builder builder = newMappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());builder.resource(ms.getResource());builder.fetchSize(ms.getFetchSize());builder.statementType(ms.getStatementType());builder.keyGenerator(ms.getKeyGenerator());if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {builder.keyProperty(ms.getKeyProperties()[0]);}builder.timeout(ms.getTimeout());builder.parameterMap(ms.getParameterMap());builder.resultMaps(ms.getResultMaps());builder.resultSetType(ms.getResultSetType());builder.cache(ms.getCache());builder.flushCacheRequired(ms.isFlushCacheRequired());builder.useCache(ms.isUseCache());return builder.build();}@Overridepublic Object plugin(Object target) {logger.info("plugin方法:{}", target);if (target instanceof Executor) {return Plugin.wrap(target, this);}return target;}@Overridepublic void setProperties(Properties properties) {// 獲取屬性// String value1 = properties.getProperty("prop1");logger.info("properties方法:{}", properties.toString());}}

(2)MyBatisConfig 類:

package spcommon.config;import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration; import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct; import java.util.List; import java.util.Properties;@Configuration @AutoConfigureAfter(PageHelperAutoConfiguration.class) public class MyBatisConfig {@Autowiredprivate List<SqlSessionFactory> sqlSessionFactoryList;@PostConstructpublic void addMySqlInterceptor() {MySqlInterceptor interceptor = new MySqlInterceptor();for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {// 添加自定義屬性 // Properties properties = new Properties(); // properties.setProperty("prop1", "value1"); // interceptor.setProperties(properties);sqlSessionFactory.getConfiguration().addInterceptor(interceptor);}}}

或者直接設置到sqlSessionFactoy中去:

package com.muses.taoshop.common.core.database.config;import com.muses.taoshop.common.core.database.annotation.MybatisRepository; import com.muses.taoshop.common.core.database.annotation.TypeAliasesPackageScanner; import org.apache.ibatis.io.VFS; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.*; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource;import static com.muses.taoshop.common.core.database.config.BaseConfig.*;/*** <pre>* Mybatis配置類* </pre>** @author nicky* @version 1.00.00* <pre>* 修改記錄* 修改后版本: 修改人: 修改日期: 修改內容:* </pre>*/ @MapperScan(basePackages = MAPPER_PACKAGES,annotationClass = MybatisRepository.class,sqlSessionFactoryRef = SQL_SESSION_FACTORY ) @ComponentScan @EnableTransactionManagement @Configuration public class MybatisConfig {@AutowiredMybatisSqlInterceptor mybatisSqlInterceptor;TypeAliasesPackageScanner packageScanner = new TypeAliasesPackageScanner();@Bean(name = DATA_SOURCE_NAME)@ConfigurationProperties(prefix = DATA_SOURCE_PROPERTIES)@Primarypublic DataSource dataSource(){return DataSourceBuilder.create().build();}@Primary@Bean(name = SQL_SESSION_FACTORY)public SqlSessionFactory sqlSessionFactory(@Qualifier(DATA_SOURCE_NAME)DataSource dataSource)throws Exception{//SpringBoot默認使用DefaultVFS進行掃描,但是沒有掃描到jar里的實體類VFS.addImplClass(SpringBootVFS.class);SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setPlugins(new Interceptor[]{mybatisSqlInterceptor});factoryBean.setDataSource(dataSource);//factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();try{factoryBean.setMapperLocations(resolver.getResources("classpath*:/mybatis/*Mapper.xml"));String typeAliasesPackage = packageScanner.getTypeAliasesPackages();factoryBean.setTypeAliasesPackage(typeAliasesPackage);SqlSessionFactory sqlSessionFactory = factoryBean.getObject();return sqlSessionFactory;}catch (Exception e){e.printStackTrace();throw new RuntimeException();}}@Bean(name = MYBATIS_TRANSACTION_MANAGER)public DataSourceTransactionManager transactionManager(@Qualifier(DATA_SOURCE_NAME)DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}}

參考文獻:1、http://c.biancheng.net/view/4302.html

2、https://www.jianshu.com/p/f409def7d696

3、mybatis源碼解析:https://www.cnblogs.com/jackion5/p/9482052.html

4、SpringBoot 通過自定義 Mybatis 攔截器,實現 SQL 的改寫:https://www.cnblogs.com/d0usr/p/12448639.html

?

5、mybatis-spring:http://mybatis.org/spring/zh/sqlsession.html

?

?

?

?


?

?

?

?

?

?

?

總結

以上是生活随笔為你收集整理的Mabtyis无侵入式编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。