最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Sharding Jdbc批量操作引發(fā)fullGC解決

 更新時間:2022年11月09日 09:41:06   作者:女友在高考  
這篇文章主要為大家介紹了Sharding Jdbc批量操作引發(fā)fullGC解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

周五晚上告警群突然收到了一條告警消息,點開一看,應(yīng)用 fullGC 了。

于是趕緊聯(lián)系運維下載堆內(nèi)存快照,進(jìn)行分析。

內(nèi)存分析

使用 MemoryAnalyzer 打開堆文件

mat 下載地址:http://m.fzitv.net/zt/matlab.html

下載下來后需要調(diào)大一下 MemoryAnalyzer.ini 配置文件里的-Xmx2048m

打開堆文件后如圖:

發(fā)現(xiàn)有 809MB 的一個占用,應(yīng)該問題就出在這塊了。然后點擊 Dominator Tree,看看有什么大的對象占用。

我們找大的對象,一級級往下點看看具體是誰在占用內(nèi)存。點到下面發(fā)現(xiàn)是 sharding jdbc 里面的類,然后再繼續(xù)往下發(fā)現(xiàn)了一個 localCache。

原來是一個本地緩存占了這么大的空間

為什么有這個 LocalCache 呢?

帶著這個疑惑我們?nèi)ゴa里看看它是怎么使用的,根據(jù)堆內(nèi)存分析上的提示,我直接打開了 SQLStatementParserEngine 類。

public final class SQLStatementParserEngine {
    private final SQLStatementParserExecutor sqlStatementParserExecutor;
    private final LoadingCache<String, SQLStatement> sqlStatementCache;
    public SQLStatementParserEngine(String databaseType, SQLParserRule sqlParserRule) {
        this.sqlStatementParserExecutor = new SQLStatementParserExecutor(databaseType, sqlParserRule);
        this.sqlStatementCache = SQLStatementCacheBuilder.build(sqlParserRule, databaseType);
    }
    public SQLStatement parse(String sql, boolean useCache) {
        return useCache ? (SQLStatement)this.sqlStatementCache.getUnchecked(sql) : this.sqlStatementParserExecutor.parse(sql);
    }
}

他這個里面有個 LoadingCache 類型的 sqlStatementCache 對象,這個就是我們要找的緩存對象。

從 parse 方法可以看出,它這里是想用本地緩存做一個優(yōu)化,優(yōu)化通過 sql 解析 SQLStatement 的速度。

在普通的場景使用應(yīng)該是沒問題的,但是如果是進(jìn)行批量操作場景的話就會有問題。

就像下面這個語句:

@Mapper
public interface OrderMapper {
    Integer batchInsertOrder(List<Order> orders);
}
<insert id="batchInsertOrder" parameterType="com.mmc.sharding.bean.Order" >
        insert into t_order (id,code,amt,user_id,create_time)
        values
        <foreach collection="list" item="item" separator=",">
            (#{item.id},#{item.code},#{item.amt},#{item.userId},#{item.createTime})
        </foreach>
</insert>

1)我傳入的 orders 的個數(shù)不一樣,會拼出很多不同的 sql,生成不同的 SQLStatement,都會被放入到緩存中

2)因為批量操作的拼接,sql 本身長度也很大。如果我傳入的 orders 的 size 是 1000,那么這個 sql 就很長,也比普通的 sql 更占用內(nèi)存。

綜上,就會導(dǎo)致大量的內(nèi)存消耗,如果是請求速度很快的話,就就有可能導(dǎo)致頻繁的 FullGC。

解決方案

因為是參數(shù)個數(shù)不同而導(dǎo)致的拼成 Sql 的不一致,所以我們解決參數(shù)個數(shù)就行了。

我們可以將傳入的參數(shù)按我們指定的集合大小來拆分,即不管傳入多大的集合,都拆為{300, 200, 100, 50, 25, 10, 5, 2, 1}這里面的個數(shù)的集合大小。如傳入 220 大小的集合,就拆為[{200},{10},{10}],這樣分三次去執(zhí)行 sql,那么生成的 SQL 緩存數(shù)也就只有我們指定的固定數(shù)字的個數(shù)那么多了,基本不超過 10 個。

接下來我們實驗一下,改造前和改造后的 gc 情況。

測試代碼如下:

 @RequestMapping("/batchInsert")
    public String batchInsert(){
        for (int j = 0; j < 1000; j++) {
            List<Order> orderList = new ArrayList<>();
            int i1 = new Random().nextInt(1000) + 500;
            for (int i = 0; i < i1; i++) {
                Order order=new Order();
                order.setCode("abc"+i);
                order.setAmt(new BigDecimal(i));
                order.setUserId(i);
                order.setCreateTime(new Date());
                orderList.add(order);
            }
            orderMapper.batchInsertOrder(orderList);
            System.out.println(j);
        }
        return "success";
    }

GC 情況如圖所示:

cache 里面存有元素:

修改代碼后:

@RequestMapping("/batchInsert")
    public String batchInsert(){
        for (int j = 0; j < 1; j++) {
            List<Order> orderList = new ArrayList<>();
            int i1 = new Random().nextInt(1000) + 500;
            for (int i = 0; i < i1; i++) {
                Order order=new Order();
                order.setCode("abc"+i);
                order.setAmt(new BigDecimal(i));
                order.setUserId(i);
                order.setCreateTime(new Date());
                orderList.add(order);
            }
            List<List<Order>> shard = ShardingUtils.shard(orderList);
            shard.stream().forEach(
                    orders->{
                        orderMapper.batchInsertOrder(orders);
                    }
            );
            System.out.println(j);
        }
        return "success";
    }

GC 情況如下:

cache 里面存有元素:

可以看出 GC 次數(shù)有減少,本地緩存的條數(shù)由 600 多減到了 11 個,如果導(dǎo)出堆內(nèi)存還能看出至少降低了幾百 M 的本地內(nèi)存占用。

另外,這個 cache 是有大小限制的,如果因為一個 sql 占了 600 多個位置,那么其他的 sql 的緩存就會被清理,導(dǎo)致其他 SQL 性能會受到影響,甚至如果機(jī)器本身內(nèi)存不高,還會因為這個 cache 過大而導(dǎo)致頻繁的 Full GC

大家以后在使用 Sharding JDBC 進(jìn)行批量操作的時候就需要多注意了

另附上拆分為固定大小的數(shù)組的工具方法如下:

public class ShardingUtils {
    private static Integer[] nums = new Integer[]{800,500,300, 200, 100, 50, 25, 10, 5, 2, 1};
    public static <T> List<List<T>> shard(final List<T> originData) {
        return shard(originData, new ArrayList<>());
    }
    private static <T> List<List<T>> shard(final List<T> originData, List<List<T>> result) {
        if (originData.isEmpty()) {
            return result;
        }
        for (int i = 0; i < nums.length; i++) {
            if (originData.size() >= nums[i]) {
                List<T> ts = originData.subList(0, nums[i]);
                result.add(ts);
                List<T> ts2 = originData.subList(nums[i], originData.size());
                if (ts2.isEmpty()) {
                    return result;
                } else {
                    return shard(ts2, result);
                }
            }
        }
        return result;
    }
}

以上就是Sharding Jdbc批量操作引發(fā)fullGC解決的詳細(xì)內(nèi)容,更多關(guān)于Sharding Jdbc引發(fā)fullGC的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MyBatis查詢、新增、更新與刪除操作指南

    MyBatis查詢、新增、更新與刪除操作指南

    這篇文章主要給大家介紹了關(guān)于MyBatis查詢、新增、更新與刪除操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MyBatis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 解決HttpServletResponse和HttpServletRequest取值的2個坑

    解決HttpServletResponse和HttpServletRequest取值的2個坑

    這篇文章主要介紹了解決HttpServletResponse和HttpServletRequest取值的2個坑問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Spring?Get請求與post請求的實現(xiàn)

    Spring?Get請求與post請求的實現(xiàn)

    在Spring中,GET請求和POST請求是兩種常見的HTTP請求方法,用于與服務(wù)器進(jìn)行交互,本文詳細(xì)的介紹一下Spring?Get請求與post請求的實現(xiàn),感興趣的可以了解一下
    2023-10-10
  • HashMap在JDK7與JDK8中的實現(xiàn)過程解析

    HashMap在JDK7與JDK8中的實現(xiàn)過程解析

    這幾天學(xué)習(xí)了HashMap的底層實現(xiàn),但是發(fā)現(xiàn)好幾個版本的,代碼不一,很多文章都是舊版本JDK1.6.JDK1.7的?,F(xiàn)在我來分析下JDK7與JDK8中HashMap的實現(xiàn)過程
    2021-09-09
  • 使用kotlin集成springboot開發(fā)的超詳細(xì)教程

    使用kotlin集成springboot開發(fā)的超詳細(xì)教程

    目前大多數(shù)都在使用java集成 springboot進(jìn)行開發(fā),本文演示僅僅將 java換成 kotlin,其他不變的情況下進(jìn)行開發(fā),需要的朋友可以參考下
    2021-09-09
  • Java中的Native方法

    Java中的Native方法

    這篇文章主要介紹了Java中的Native方法,在本文中,我們將看到j(luò)ava中本機(jī)native方法的介紹。我們將看到它的基本語法及其工作原理。將有java代碼示例展示native本機(jī)方法的使用,下面來看看文章的具體介紹
    2021-12-12
  • Java中的RPC框架Dubbo原理和機(jī)制詳解

    Java中的RPC框架Dubbo原理和機(jī)制詳解

    這篇文章主要介紹了Java中的RPC框架Dubbo原理和機(jī)制詳解,Dubbo 是一款Java RPC框架,致力于提供高性能的 RPC 遠(yuǎn)程服務(wù)調(diào)用方案,作為主流的微服務(wù)框架之一,Dubbo 為開發(fā)人員帶來了非常多的便利,需要的朋友可以參考下
    2024-01-01
  • JSP request.setAttribute()詳解及實例

    JSP request.setAttribute()詳解及實例

    這篇文章主要介紹了 javascript request.setAttribute()詳解及實例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • IDEA整合SSM框架實現(xiàn)網(wǎng)頁上顯示數(shù)據(jù)

    IDEA整合SSM框架實現(xiàn)網(wǎng)頁上顯示數(shù)據(jù)

    最近做了個小項目,該項目包在intellij idea中實現(xiàn)了ssm框架的整合以及實現(xiàn)訪問,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • springboot集成nacos實現(xiàn)自動刷新的示例代碼

    springboot集成nacos實現(xiàn)自動刷新的示例代碼

    研究nacos時發(fā)現(xiàn),springboot版本可使用@NacosValue實現(xiàn)配置的自動刷新,本文主要介紹了springboot集成nacos實現(xiàn)自動刷新的示例代碼,感興趣的可以了解一下
    2023-11-11

最新評論

秭归县| 汉中市| 本溪市| 新宾| 陵川县| 定结县| 天镇县| 临沭县| 宜城市| 庐江县| 佛冈县| 搜索| 离岛区| 湛江市| 万山特区| 锡林浩特市| 淳安县| 阿城市| 晋中市| 武定县| 漳州市| 曲阳县| 九龙县| 江都市| 柯坪县| 澄江县| 嘉兴市| 布拖县| 南通市| 安多县| 建平县| 贵港市| 大冶市| 资溪县| 呼伦贝尔市| 定远县| 浪卡子县| 大丰市| 深圳市| 石景山区| 铅山县|