Mybatis-plus解決兼容oracle批量插入的示例詳解
1. 自定義SQL注入器
新建一個名為EasySqlInjector的類,繼承DefaultSqlInjector
。
public class EasySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { // 注意:此SQL注入器繼承了DefaultSqlInjector(默認(rèn)注入器),調(diào)用了DefaultSqlInjector的getMethodList方法,保留了mybatis-plus的自帶方法 List<AbstractMethod> methodList = super.getMethodList(mapperClass); methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE)); return methodList; } }
2. 將SQL注入器交給Spring容器
在MybatisPlusConfig
類中,將剛才創(chuàng)建的SQL注入器EasySqlInjector,注冊為一個bean。
@EnableTransactionManagement(proxyTargetClass = true) @Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 設(shè)置請求的頁面大于最大頁后操作, true調(diào)回到首頁,false 繼續(xù)請求 默認(rèn)false // paginationInterceptor.setOverflow(false); // 設(shè)置最大單頁限制數(shù)量,默認(rèn) 500 條,-1 不受限制 // paginationInterceptor.setLimit(500); // 開啟 count 的 join 優(yōu)化,只針對部分 left join paginationInterceptor.setLimit(-1); // paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; } /** * 分頁插件,自動識別數(shù)據(jù)庫類型 https://baomidou.com/guide/interceptor-pagination.html */ public PaginationInnerInterceptor paginationInnerInterceptor() { PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); // 設(shè)置數(shù)據(jù)庫類型為mysql paginationInnerInterceptor.setDbType(DbType.ORACLE); // 設(shè)置最大單頁限制數(shù)量,默認(rèn) 500 條,-1 不受限制 paginationInnerInterceptor.setMaxLimit(-1L); return paginationInnerInterceptor; } /** * 樂觀鎖插件 https://baomidou.com/guide/interceptor-optimistic-locker.html */ public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { return new OptimisticLockerInnerInterceptor(); } /** * 如果是對全表的刪除或更新操作,就會終止該操作 https://baomidou.com/guide/interceptor-block-attack.html */ public BlockAttackInnerInterceptor blockAttackInnerInterceptor() { return new BlockAttackInnerInterceptor(); } @Bean public EasySqlInjector sqlInjector() { return new EasySqlInjector(); } }
3. 配置EasyBaseMapper繼承BaseMapper
新建EasyBaseMapper類,繼承BaseMapper
,并在此類中配置insertBatchSomeColumn()
方法。
public interface EasyBaseMapper<T> extends BaseMapper<T> { /** * @param entityList 實體列表 */ void insertBatchSomeColumn(Collection<T> entityList); }
4.自定義Mybatis攔截器OracleSqlInterceptor
這個地方要注意,表的主鍵我用觸發(fā)器已經(jīng)自動填入,所以keyGenerator設(shè)置為NoKeyGenerator.INSTANCE,這個地方有個坑,不那么設(shè)置,SQL一直報錯,折騰了兩個小時,實際上拼接的SQL沒問題
@Component @Slf4j @Order(1) @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class OracleSqlInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //當(dāng)前業(yè)務(wù),兼容pg 和 oracle,需要兼容oracle的批量插入語句 StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); BoundSql boundSql = statementHandler.getBoundSql(); String sql = boundSql.getSql(); StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(statementHandler, "delegate"); MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement"); ReflectUtil.setFieldValue(mappedStatement,"keyGenerator", NoKeyGenerator.INSTANCE); String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1); if("insertBatchSomeColumn".equals(mName)){ //開始兼容批量插入語句,并設(shè)置boundSql Field declaredField = boundSql.getClass().getDeclaredField("sql"); declaredField.setAccessible(true); declaredField.set(boundSql, convertOracleInsertSql(sql)); log.info("---轉(zhuǎn)換后的sql為:{}", boundSql.getSql()); } return invocation.proceed(); } /** * Oracle Insert語句轉(zhuǎn)化 * * @param sql 傳入的pg的sql * @return 轉(zhuǎn)化后的sql */ public String convertOracleInsertSql(String sql) { //用oracle中的批量語句代替 //查找values的位置,將后面全部括號里的東西取出,然后再用對應(yīng)的數(shù)據(jù)進行封裝 //獲取前面的sql,這段sql與Oracle的相同 String prefix = sql.substring(0, getKeywordValueIndex(sql)); //排除table中的括號,取后面的括號 String subSql = sql.substring(getKeywordValueIndex(sql)); String valueSql = subSql.substring(subSql.indexOf("(")); List<String> valueList = getValues(valueSql); //拼接sql StringBuilder sqlBuilder = new StringBuilder().append(prefix); //sqlBuilder.append("SELECT A.* FROM ("); String selectValue = "SELECT "; String endValue = " FROM DUAL "; String unionValue = "UNION ALL "; boolean start = true; for (String value : valueList) { if (!start) { sqlBuilder.append(unionValue); } else { start = false; } sqlBuilder.append(selectValue).append(value).append(endValue); } //sqlBuilder.append(") A"); return sqlBuilder.toString(); } /** * 使用棧實現(xiàn)獲取value中括號的值 * */ public List<String> getValues(String sql) { List<String> values = new ArrayList<>(); Stack<Character> brackets = new Stack<>(); StringBuilder splitValue = new StringBuilder(); for (Character c : sql.toCharArray()) { if ('(' == c) { //左括號進棧 brackets.push(c); } else if (')' == c) { //右括號則將左括號出棧,清空builder brackets.pop(); values.add(splitValue.toString()); splitValue.delete(0, splitValue.length()); } else if (!brackets.empty()) { //只有進入括號中才將值放入,排除括號外的逗號 splitValue.append(c); } } return values; } /** * 查找關(guān)鍵字value的位置 */ public int getKeywordValueIndex(String sql) { //先找values,再找value if (sql.contains("values")) { return sql.indexOf("values"); } else if (sql.contains("VALUES")) { return sql.indexOf("VALUES"); } else if (sql.contains("value")) { return sql.indexOf("value"); } else { return sql.indexOf("VALUE"); } } }
然后,用業(yè)務(wù)Mapper繼承EasyBaseMapper就可以調(diào)用insertBatchSomeColumn()
方法了。
到此這篇關(guān)于Mybatis-plus解決兼容oracle批量插入的示例詳解的文章就介紹到這了,更多相關(guān)Mybatis-plus oracle批量插入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javaweb設(shè)計中filter粗粒度權(quán)限控制代碼示例
這篇文章主要介紹了javaweb設(shè)計中filter粗粒度權(quán)限控制代碼示例,小編覺得還是挺不錯的,需要的朋友可以參考。2017-10-10java 實現(xiàn)將Object類型轉(zhuǎn)換為int類型
這篇文章主要介紹了java 實現(xiàn)將Object類型轉(zhuǎn)換為int類型的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07IntelliJ IDEA 小技巧之Bookmark(書簽)的使用
這篇文章主要介紹了IntelliJ IDEA 小技巧之Bookmark(書簽)的使用,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07servlet實現(xiàn)簡單的權(quán)限管理和敏感詞過濾功能
JavaEE課要求用servlet和過濾器實現(xiàn)權(quán)限管理和敏感詞過濾功能,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05關(guān)于解決iReport4.1.1無法正常啟動或者閃退或者JDK8不兼容的問題
在安裝使用iReport的過程中遇到一個問題,我的iReport始終不能打開,困擾了我好久。接下來通過本文給大家介紹iReport4.1.1無法正常啟動或者閃退或者JDK8不兼容的問題,需要的朋友可以參考下2018-09-09