欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatisPuls多數(shù)據(jù)源操作數(shù)據(jù)源偶爾報(bào)錯(cuò)問(wèn)題

 更新時(shí)間:2024年06月15日 14:09:56   作者:Q?z1997  
這篇文章主要介紹了MyBatisPuls多數(shù)據(jù)源操作數(shù)據(jù)源偶爾報(bào)錯(cuò)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

MyBatisPuls多數(shù)據(jù)源操作數(shù)據(jù)源偶爾報(bào)錯(cuò)

昨天同事在開(kāi)發(fā)一個(gè)項(xiàng)目的時(shí)候使用了 MybatisPlus 的多數(shù)據(jù)源, 但是在登陸的時(shí)候偶然就會(huì)報(bào)錯(cuò) 如下 說(shuō)使用錯(cuò)庫(kù)了

但是刷新幾次有好了 我去看了看這個(gè)問(wèn)題 我當(dāng)時(shí)表示十分震驚 debug 了 一個(gè)多小時(shí)也沒(méi)找到錯(cuò)誤 正當(dāng)我快放棄的時(shí)候 我想起了我以前排除過(guò)的一個(gè)問(wèn)題 mybatis的 幽靈分頁(yè) (錯(cuò)誤的使用分頁(yè)插件 導(dǎo)致的ThreadLocal 重復(fù)使用的問(wèn)題)

版本是

		<dependency>
			    <groupId>com.baomidou</groupId>
			    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
			    <version>3.1.0</version>
			</dependency>

org.springframework.jdbc.BadSqlGrammarException: 
### Error querying database.  Cause: java.sql.SQLSyntaxErrorException: Table 'constdatacenterx_company.sys_dict_type' doesn't exist
### The error may exist in vip/xiaonuo/sys/modular/dict/mapper/SysDictTypeMapper.java (best guess)
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT  id,name,code,sort,remark,status,create_time,create_user,update_time,update_user  FROM sys_dict_type     WHERE (status <> ?)
### Cause: java.sql.SQLSyntaxErrorException: Table 'constdatacenterx_company.sys_dict_type' doesn't exist
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: Table 'constdatacenterx_company.sys_dict_type' doesn't exist
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:235)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:88)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440)
    at com.sun.proxy.$Proxy124.selectList(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:223)
    at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:173)
    at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:78)
    at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148)
    at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
    at com.sun.proxy.$Proxy353.selectList(Unknown Source)
    at com.baomidou.mybatisplus.extension.service.IService.list(IService.java:279)
    at vip.xiaonuo.sys.modular.dict.service.impl.SysDictTypeServiceImpl.tree(SysDictTypeServiceImpl.java:199)
    at vip.xiaonuo.sys.modular.dict.service.impl.SysDictTypeServiceImpl$$FastClassBySpringCGLIB$$5dedd210.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor.invoke(DynamicDataSourceAnnotationInterceptor.java:50)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
    at vip.xiaonuo.sys.modular.dict.service.impl.SysDictTypeServiceImpl$$EnhancerBySpringCGLIB$$8ee9f21c.tree(<generated>)
    at vip.xiaonuo.sys.modular.dict.controller.SysDictTypeController.tree(SysDictTypeController.java:170)

雖然一個(gè)多小時(shí)沒(méi)有找到問(wèn)題的原因 看到了mybatis plus 在切換數(shù)據(jù)源的時(shí)候使用了 ThreadLocal 直覺(jué)告訴我 可能是它的問(wèn)題 但是現(xiàn)在沒(méi)有證據(jù) (不能冤枉一個(gè)好的ThreadLocal)

/**
 * Copyright ? 2018 organization baomidou
 * <pre>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * <pre/>
 */
package com.baomidou.dynamic.datasource.toolkit;

import java.util.ArrayDeque;
import java.util.Deque;
import org.springframework.core.NamedInheritableThreadLocal;
import org.springframework.util.StringUtils;

/**
 * 核心基于ThreadLocal的切換數(shù)據(jù)源工具類(lèi)
 *
 * @author TaoYu Kanyuxia
 * @since 1.0.0
 */
public final class DynamicDataSourceContextHolder {

  /**
   * 為什么要用鏈表存儲(chǔ)(準(zhǔn)確的是棧)
   * <pre>
   * 為了支持嵌套切換,如ABC三個(gè)service都是不同的數(shù)據(jù)源
   * 其中A的某個(gè)業(yè)務(wù)要調(diào)B的方法,B的方法需要調(diào)用C的方法。一級(jí)一級(jí)調(diào)用切換,形成了鏈。
   * 傳統(tǒng)的只設(shè)置當(dāng)前線程的方式不能滿足此業(yè)務(wù)需求,必須模擬棧,后進(jìn)先出。
   * </pre>
   */
  @SuppressWarnings("unchecked")
  private static final ThreadLocal<Deque<String>> LOOKUP_KEY_HOLDER = new NamedInheritableThreadLocal("dynamic-datasource") {
    @Override
    protected Object initialValue() {
      return new ArrayDeque();
    }
  };

  private DynamicDataSourceContextHolder() {
  }

  /**
   * 獲得當(dāng)前線程數(shù)據(jù)源
   *
   * @return 數(shù)據(jù)源名稱(chēng)
   */
  public static String peek() {
    return LOOKUP_KEY_HOLDER.get().peek();
  }

  /**
   * 設(shè)置當(dāng)前線程數(shù)據(jù)源
   * <p>
   * 如非必要不要手動(dòng)調(diào)用,調(diào)用后確保最終清除
   * </p>
   *
   * @param ds 數(shù)據(jù)源名稱(chēng)
   */
  public static void push(String ds) {
    LOOKUP_KEY_HOLDER.get().push(StringUtils.isEmpty(ds) ? "" : ds);
  }

  /**
   * 清空當(dāng)前線程數(shù)據(jù)源
   * <p>
   * 如果當(dāng)前線程是連續(xù)切換數(shù)據(jù)源 只會(huì)移除掉當(dāng)前線程的數(shù)據(jù)源名稱(chēng)
   * </p>
   */
  public static void poll() {
    Deque<String> deque = LOOKUP_KEY_HOLDER.get();
    deque.poll();
    if (deque.isEmpty()) {
      LOOKUP_KEY_HOLDER.remove();
    }
  }

  /**
   * 強(qiáng)制清空本地線程
   * <p>
   * 防止內(nèi)存泄漏,如手動(dòng)調(diào)用了push可調(diào)用此方法確保清除
   * </p>
   */
  public static void clear() {
    LOOKUP_KEY_HOLDER.remove();
  }
}

最后修改他的源碼 增加日志

/**
 * Copyright ? 2018 organization baomidou
 * <pre>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * <pre/>
 */
package com.baomidou.dynamic.datasource.toolkit;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.core.NamedInheritableThreadLocal;
import org.springframework.util.StringUtils;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * 核心基于ThreadLocal的切換數(shù)據(jù)源工具類(lèi)
 *
 * @author TaoYu Kanyuxia
 * @since 1.0.0
 */
public final class DynamicDataSourceContextHolder {

    /**
     * 為什么要用鏈表存儲(chǔ)(準(zhǔn)確的是棧)
     * <pre>
     * 為了支持嵌套切換,如ABC三個(gè)service都是不同的數(shù)據(jù)源
     * 其中A的某個(gè)業(yè)務(wù)要調(diào)B的方法,B的方法需要調(diào)用C的方法。一級(jí)一級(jí)調(diào)用切換,形成了鏈。
     * 傳統(tǒng)的只設(shè)置當(dāng)前線程的方式不能滿足此業(yè)務(wù)需求,必須模擬棧,后進(jìn)先出。
     * </pre>
     */
    private static final ThreadLocal<Deque<String>> LOOKUP_KEY_HOLDER = new NamedInheritableThreadLocal<Deque<String>>("dynamic-datasource") {
        // @Override
        // protected Deque<String> childValue(Deque<String> parentValue) {
        //     return new ArrayDeque<>();
        // }

        @Override
        protected ArrayDeque<String> initialValue() {
            return new ArrayDeque<>();
        }
    };

    private DynamicDataSourceContextHolder() {
    }

    /**
     * 獲得當(dāng)前線程數(shù)據(jù)源
     *
     * @return 數(shù)據(jù)源名稱(chēng)
     */
    public static String peek() {
        Deque<String> strings = LOOKUP_KEY_HOLDER.get();
        String peek = strings.peek();
        String format = LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss:SSS");
        System.out.printf("時(shí)間 %s 當(dāng)前線程 %s 獲得當(dāng)前線程數(shù)據(jù)源 %s 棧針 %s ", format, Thread.currentThread().getName(), peek, JSON.toJSONString(strings));
        System.out.println();
        return peek;
    }

    /**
     * 設(shè)置當(dāng)前線程數(shù)據(jù)源
     * <p>
     * 如非必要不要手動(dòng)調(diào)用,調(diào)用后確保最終清除
     * </p>
     *
     * @param ds 數(shù)據(jù)源名稱(chēng)
     */
    public static void push(String ds) {
        Deque<String> strings = LOOKUP_KEY_HOLDER.get();
        System.out.printf("時(shí)間 %s 當(dāng)前線程 %s 設(shè)置當(dāng)前線程數(shù)據(jù)源 %s 棧針 %s 引用 %s", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss:SSS"), Thread.currentThread().getName(), ds, JSON.toJSONString(strings), strings.hashCode());
        System.out.println();
        strings.push(StringUtils.isEmpty(ds) ? "" : ds);
        System.out.printf("時(shí)間 %s 當(dāng)前線程 %s 之后設(shè)置當(dāng)前線程數(shù)據(jù)源 %s 棧針 %s 引用 %s", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss:SSS"), Thread.currentThread().getName(), ds, JSON.toJSONString(strings), strings.hashCode());
        System.out.println();
    }

    /**
     * 清空當(dāng)前線程數(shù)據(jù)源
     * <p>
     * 如果當(dāng)前線程是連續(xù)切換數(shù)據(jù)源 只會(huì)移除掉當(dāng)前線程的數(shù)據(jù)源名稱(chēng)
     * </p>
     */
    public static void poll() {
        Deque<String> deque = LOOKUP_KEY_HOLDER.get();
        System.out.printf("時(shí)間 %s 清空當(dāng)前線程 %s  棧針 %s ", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss:SSS"), Thread.currentThread().getName(), JSON.toJSONString(deque));
        System.out.println();
        String poll = deque.poll();
        System.out.printf("時(shí)間 %s 當(dāng)前線程 %s 清空 %s 棧針 %s ", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss:SSS"), Thread.currentThread().getName(), poll, JSON.toJSONString(deque));
        System.out.println();
        if (deque.isEmpty()) {
            LOOKUP_KEY_HOLDER.remove();
        }
    }

    /**
     * 強(qiáng)制清空本地線程
     * <p>
     * 防止內(nèi)存泄漏,如手動(dòng)調(diào)用了push可調(diào)用此方法確保清除
     * </p>
     */
    public static void clear() {
        LOOKUP_KEY_HOLDER.remove();
    }
}

當(dāng)我查看日志的時(shí)候 讓我發(fā)現(xiàn)了一個(gè) 令我震驚的是 ThreadLocal 維護(hù)的value 竟然兩個(gè)線程共享了 震驚!!!

    /**
     * 設(shè)置當(dāng)前線程數(shù)據(jù)源
     * <p>
     * 如非必要不要手動(dòng)調(diào)用,調(diào)用后確保最終清除
     * </p>
     *
     * @param ds 數(shù)據(jù)源名稱(chēng)
     */
    public static void push(String ds) {
        Deque<String> strings = LOOKUP_KEY_HOLDER.get();
        System.out.printf("時(shí)間 %s 當(dāng)前線程 %s 設(shè)置當(dāng)前線程數(shù)據(jù)源 %s 棧針 %s 引用 %s", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss:SSS"), Thread.currentThread().getName(), ds, JSON.toJSONString(strings), strings.hashCode());
        System.out.println();
        strings.push(StringUtils.isEmpty(ds) ? "" : ds);
        System.out.printf("時(shí)間 %s 當(dāng)前線程 %s 之后設(shè)置當(dāng)前線程數(shù)據(jù)源 %s 棧針 %s 引用 %s", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss:SSS"), Thread.currentThread().getName(), ds, JSON.toJSONString(strings), strings.hashCode());
        System.out.println();
    }

所以出現(xiàn)了上述的查詢數(shù)據(jù)異常 !!!

但是這不符合常理的 ThreadLocal 肯定沒(méi)有線程安全問(wèn)題 我將這個(gè)變量修改成 NamedInheritableThreadLocal 改成 ThreadLocal 測(cè)試發(fā)現(xiàn)也沒(méi)有問(wèn)題了

我們來(lái)看看這個(gè) NamedInheritableThreadLocal 類(lèi)吧

package org.springframework.core;

import org.springframework.util.Assert;

public class NamedInheritableThreadLocal<T> extends InheritableThreadLocal<T> {
    private final String name;

    public NamedInheritableThreadLocal(String name) {
        Assert.hasText(name, "Name must not be empty");
        this.name = name;
    }

    public String toString() {
        return this.name;
    }
}

這個(gè)childValue 方法的描述很有趣

為這個(gè)可繼承的線程局部計(jì)算子線程的初始值變量作為父變量在子變量出現(xiàn)時(shí)的值的函數(shù)創(chuàng)建線程。

此方法從父類(lèi)內(nèi)部調(diào)用 子線程啟動(dòng)之前的線程。

就是子線程可以基礎(chǔ)父線程的 ThreadLocal 中的變量 看到這終于明白了 就是這個(gè)的問(wèn)題了

來(lái)仔細(xì)聊聊這個(gè)InheritableThreadLocal

首先我們知道ThreadLocal解決的是變量在不同線程間的隔離性,也就是不同線程擁有自己的值。類(lèi)ThreadLocal的主要作用是將數(shù)據(jù)放入當(dāng)前線程對(duì)象中的Map中,類(lèi)ThreadLocal自己不管理、不存儲(chǔ)任何數(shù)據(jù),它只是數(shù)據(jù)和Map之間的橋梁,Map中的key存儲(chǔ)的是ThreadLocal對(duì)象,value就是存儲(chǔ)的值。每個(gè)Thread中的Map值只對(duì)當(dāng)前線程可見(jiàn),其他線程不可以訪問(wèn)當(dāng)前線程對(duì)象中Map的值。

當(dāng)前線程銷(xiāo)毀,Map隨之銷(xiāo)毀,Map中的數(shù)據(jù)如果沒(méi)有被引用、沒(méi)有被使用,則隨時(shí)GC收回。由于Map中的key不可以重復(fù),所以一個(gè)ThreadLocal對(duì)象對(duì)應(yīng)一個(gè)value。

Thread類(lèi)中有一個(gè)init方法,每次創(chuàng)建線程的時(shí)候會(huì)執(zhí)行這個(gè)init方法,并且inheriThreadLocals默認(rèn)傳的參數(shù)是true,所以當(dāng)前線程對(duì)象每次都會(huì)從父線程繼承值,子線程將父線程中的table對(duì)象以復(fù)制的方式賦值給子線程的table數(shù)組,這個(gè)過(guò)程是在創(chuàng)建Thread類(lèi)對(duì)象時(shí)發(fā)生的,也就說(shuō)明當(dāng)子線程對(duì)象創(chuàng)建完畢后,子線程中的數(shù)據(jù)就是主線程中舊的數(shù)據(jù),主線程使用新的數(shù)據(jù)時(shí),子線程還是使用舊的數(shù)據(jù),因?yàn)橹髯泳€程使用兩個(gè)Entry[]對(duì)象數(shù)組各自存儲(chǔ)自己的值。

這個(gè)復(fù)制其實(shí)一個(gè)淺拷貝,如果存的值是可變對(duì)象的時(shí)候,只是復(fù)制了對(duì)象的引用而已,如果父線程修改對(duì)象的屬性值,子線程也是可以感知到的。

在我這個(gè)問(wèn)題是 就是 http-nio-82-exec-9 創(chuàng)建了線程http-nio-82-exec-10 導(dǎo)致了這個(gè)問(wèn)題

解決方法

重寫(xiě)childValue 或者 直接使用 ThreadLocal

    /**
     * 為什么要用鏈表存儲(chǔ)(準(zhǔn)確的是棧)
     * <pre>
     * 為了支持嵌套切換,如ABC三個(gè)service都是不同的數(shù)據(jù)源
     * 其中A的某個(gè)業(yè)務(wù)要調(diào)B的方法,B的方法需要調(diào)用C的方法。一級(jí)一級(jí)調(diào)用切換,形成了鏈。
     * 傳統(tǒng)的只設(shè)置當(dāng)前線程的方式不能滿足此業(yè)務(wù)需求,必須模擬棧,后進(jìn)先出。
     * </pre>
     */
    private static final ThreadLocal<Deque<String>> LOOKUP_KEY_HOLDER = new NamedInheritableThreadLocal<Deque<String>>("dynamic-datasource") {
        @Override
        protected Deque<String> childValue(Deque<String> parentValue) {
            return new ArrayDeque<>();
        }

        @Override
        protected ArrayDeque<String> initialValue() {
            return new ArrayDeque<>();
        }
    };

最后去看官方文檔

人家修復(fù)了 嗚嗚嗚嗚嗚嗚嗚

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中println輸出漢字亂碼問(wèn)題一招解決方案

    Java中println輸出漢字亂碼問(wèn)題一招解決方案

    這篇文章主要介紹了Java中println輸出漢字亂碼問(wèn)題一招解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • mybatis和mybatis-plus設(shè)置值為null不起作用問(wèn)題及解決

    mybatis和mybatis-plus設(shè)置值為null不起作用問(wèn)題及解決

    Mybatis-Plus的FieldStrategy主要用于控制新增、更新和查詢時(shí)對(duì)空值的處理策略,通過(guò)配置不同的策略類(lèi)型,可以靈活地處理實(shí)體對(duì)象的空值問(wèn)題
    2025-02-02
  • mybatis-plus?查詢傳入?yún)?shù)Map,返回List<Map>方式

    mybatis-plus?查詢傳入?yún)?shù)Map,返回List<Map>方式

    這篇文章主要介紹了mybatis-plus?查詢傳入?yún)?shù)Map,返回List<Map>方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java中List集合的常用方法詳解

    Java中List集合的常用方法詳解

    本篇文章給大家?guī)?lái)的內(nèi)容是關(guān)于Java中List集合的常用方法詳解,有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。下面我們就來(lái)學(xué)習(xí)一下吧
    2021-11-11
  • jdk8?FunctionalInterface注解源碼解讀

    jdk8?FunctionalInterface注解源碼解讀

    這篇文章主要介紹了jdk8?FunctionalInterface注解源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Spring boot開(kāi)發(fā)web應(yīng)用JPA過(guò)程解析

    Spring boot開(kāi)發(fā)web應(yīng)用JPA過(guò)程解析

    這篇文章主要介紹了Spring boot開(kāi)發(fā)web應(yīng)用JPA過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Spring的Aware接口你知道多少

    Spring的Aware接口你知道多少

    這篇文章主要為大家詳細(xì)介紹了Spring的Aware接口,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • Spring Boot集成MyBatis實(shí)現(xiàn)通用Mapper的配置及使用

    Spring Boot集成MyBatis實(shí)現(xiàn)通用Mapper的配置及使用

    關(guān)于MyBatis,大部分人都很熟悉。MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射。這篇文章主要介紹了Spring Boot集成MyBatis實(shí)現(xiàn)通用Mapper,需要的朋友可以參考下
    2018-08-08
  • Lambda表達(dá)式下訪問(wèn)外部變量問(wèn)題

    Lambda表達(dá)式下訪問(wèn)外部變量問(wèn)題

    這篇文章主要介紹了Lambda表達(dá)式下訪問(wèn)外部變量問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 解析Mybatis連續(xù)傳遞多個(gè)參數(shù)的方法

    解析Mybatis連續(xù)傳遞多個(gè)參數(shù)的方法

    MyBatis是一個(gè)支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架,這篇文章主要介紹了Mybatis連續(xù)傳遞多個(gè)參數(shù)的方法,需要的朋友可以參考下
    2016-08-08

最新評(píng)論