亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

正文

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

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

內存分析

使用 MemoryAnalyzer 打開堆文件

mat 下載地址:http://chabaoo.cn/zt/matlab.html

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

打開堆文件后如圖:

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

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

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

為什么有這個 LocalCache 呢?

帶著這個疑惑我們去代碼里看看它是怎么使用的,根據(jù)堆內存分析上的提示,我直接打開了 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 的速度。

在普通的場景使用應該是沒問題的,但是如果是進行批量操作場景的話就會有問題。

就像下面這個語句:

@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 更占用內存。

綜上,就會導致大量的內存消耗,如果是請求速度很快的話,就就有可能導致頻繁的 FullGC。

解決方案

因為是參數(shù)個數(shù)不同而導致的拼成 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 個,如果導出堆內存還能看出至少降低了幾百 M 的本地內存占用。

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

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

另附上拆分為固定大小的數(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解決的詳細內容,更多關于Sharding Jdbc引發(fā)fullGC的資料請關注腳本之家其它相關文章!

相關文章

  • Zuul 如何屏蔽服務和指定路徑

    Zuul 如何屏蔽服務和指定路徑

    這篇文章主要介紹了Zuul 如何屏蔽服務和指定路徑的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 一分鐘入門Java Spring Boot徹底解決SSM配置問題

    一分鐘入門Java Spring Boot徹底解決SSM配置問題

    Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發(fā)過程。該框架使用了特定的方式來進行配置,從而使開發(fā)人員不再需要定義樣板化的配置。通過這種方式,Spring Boot致力于在蓬勃發(fā)展的快速應用開發(fā)領域成為領導者
    2021-10-10
  • springboot jpa實現(xiàn)優(yōu)雅處理isDelete的默認值

    springboot jpa實現(xiàn)優(yōu)雅處理isDelete的默認值

    如果多個實體類都有 isDelete 字段,并且你希望在插入時為它們統(tǒng)一設置默認值時改怎么做呢,本文為大家整理了一些方法,希望對大家有所幫助
    2024-11-11
  • 一文秒懂springboot druid 配置

    一文秒懂springboot druid 配置

    Druid是阿里巴巴開發(fā)的一個連接池,他提供了一個高效、功能強大、可擴展性好的數(shù)據(jù)庫連接池,區(qū)別于hikari,今天通過本文給大家分享springboot druid 配置教程,需要的朋友參考下吧
    2021-08-08
  • Java負載均衡策略的實現(xiàn)詳解

    Java負載均衡策略的實現(xiàn)詳解

    這篇文章主要介紹了Java負載均衡策略的實現(xiàn),負載均衡在Java領域中有著廣泛深入的應用,不管是大名鼎鼎的nginx,還是微服務治理組件如dubbo,feign等,負載均衡的算法在其中都有著實際的使用,需要的朋友可以參考下
    2022-07-07
  • JAVA格式化時間日期的簡單實例

    JAVA格式化時間日期的簡單實例

    這篇文章主要介紹了JAVA格式化時間日期的簡單實例,有需要的朋友可以參考一下
    2013-11-11
  • 淺談Arrays.asList()方法的使用

    淺談Arrays.asList()方法的使用

    本文主要介紹了Arrays.asList()方法的使用。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • java的Console類的使用方法及實例

    java的Console類的使用方法及實例

    這篇文章主要介紹了java的Console類的使用方法及實例的相關資料,需要的朋友可以參考下
    2017-07-07
  • Java實戰(zhàn)之客戶信息管理系統(tǒng)

    Java實戰(zhàn)之客戶信息管理系統(tǒng)

    這篇文章主要介紹了Java實戰(zhàn)之客戶信息管理系統(tǒng),文中有非常詳細的代碼示例,對正在學習java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • Java發(fā)送帶html標簽內容的郵件實例代碼

    Java發(fā)送帶html標簽內容的郵件實例代碼

    下面小編就為大家?guī)硪黄狫ava發(fā)送帶html標簽內容的郵件實例代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11

最新評論