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

分布式使用Redis實現(xiàn)數(shù)據(jù)庫對象自增主鍵ID

 更新時間:2024年12月27日 11:37:26   作者:灰小猿  
本文介紹在分布式項目中使用Redis生成對象的自增主鍵ID,通過Redis的INCR等命令實現(xiàn)計數(shù)器功能,具有一定的參考價值,感興趣的可以了解一下

在分布式項目中,數(shù)據(jù)表的主鍵ID一般可能存在于UUID或自增ID這兩種形式,UUID好理解而且實現(xiàn)起來也最容易,但是缺點就是數(shù)據(jù)表中的主鍵ID是32位的字符串,在大數(shù)據(jù)查詢等情況下性能會相對比較差,所以在需求允許的情況下,我們通常會優(yōu)先考慮使用自增ID來代替UUID使用。

在分布式項目中如果你的數(shù)據(jù)表的主鍵ID是自增ID,那么常見的生成對象主鍵ID的方式有:

  • 雪花算法

    • 優(yōu)點:實現(xiàn)簡單

    • 缺點:生成ID較長、生成ID不連續(xù),會造成ID浪費(fèi)

  • 采用框架自帶的ID生成器,如MybatisPlus的@AutoID

    • 優(yōu)點:依賴框架,實現(xiàn)簡單

    • 缺點:無法在插入對象前獲取到對象的主鍵ID

  • 采用Redis緩存生成主鍵ID等

    • 優(yōu)點:生成的ID連續(xù),數(shù)據(jù)在表中的可讀性好

    • 缺點:借助Redis緩存,實現(xiàn)相比前兩種較復(fù)雜

通過雪花算法生成對象主鍵ID的方式我們在之前的文章中已經(jīng)介紹過了,這篇文章我們主要介紹如何通過Redis來實現(xiàn)生成對象自增ID的方法。

1、緩存實現(xiàn)原理

通過Redis實現(xiàn)對象自增ID的方式,主要是通過Redis的INCR 和 INCRBY 命令來對鍵值進(jìn)行遞增操作,從而實現(xiàn)計數(shù)器的功能,主要原因是Redis 是單線程模型,所有命令都是原子操作,不會發(fā)生競態(tài)條件,

在使用時要留意以下特點與注意事項

  • 原子性INCR、INCRBY 和 INCRBYFLOAT 命令都是原子性的,這意味著如果多個客戶端同時執(zhí)行這些命令,Redis 會保證每個命令的執(zhí)行不會發(fā)生競態(tài)條件。

  • 數(shù)據(jù)類型要求:這些命令要求操作的值是整數(shù)(INCR 和 INCRBY)或浮點數(shù)(INCRBYFLOAT)。如果鍵對應(yīng)的值不是數(shù)值類型,Redis 會返回錯誤。

  • 性能:Redis 是單線程的,所有命令都是原子操作,因此在高并發(fā)環(huán)境下執(zhí)行這些命令時,性能表現(xiàn)非常好。

  • 鍵不存在的情況:如果執(zhí)行 INCR 或 INCRBY 時,鍵不存在,Redis 會自動創(chuàng)建這個鍵并初始化其值為 0,然后進(jìn)行遞增。

2、Redis工具類實現(xiàn)ID自動生成

了解到通過Redis實現(xiàn)的原理之后,就是如何設(shè)計緩存以保證每張表的數(shù)據(jù)之間不會相互影響,

以user表為例,對應(yīng)的model為UserModel,那么我們就可以將model名稱作為key,當(dāng)前已有的最大的ID作為value來進(jìn)行存儲,因為每一張表對應(yīng)的model名稱都是不一樣的,所以這里一定不會出現(xiàn)key重復(fù)的情況,

下面是一些在Redis中生成和獲取對象自增ID的工具方法,方便新建對象時直接調(diào)用

@Component("redisUtils")
@RequiredArgsConstructor
@Slf4j
public class RedisUtils implements InitializingBean {
    private final StringRedisTemplate stringRedisTemplate;
    private static RedisUtils redisUtils;

    @Override
    public void afterPropertiesSet() {
        redisUtils = this;
    }

    /**
     * 獲取自增ID
     */
    public static <T> Integer getIncr(Class<T> tClass) {
        try {
            String key = tClass.getName();
            Long increment = redisUtils.stringRedisTemplate.opsForValue().increment(key, 1);
            return Math.toIntExact(increment);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RedisSystemException(e.getMessage(), e);
        }
    }

    /**
     * 獲取自增ID,指定遞增長度,用于批量創(chuàng)建對象時,只請求一次Redis
     * 如批量創(chuàng)建五個對象,delta等于5
     */
    public static <T> Integer getIncr(Class<T> tClass, int delta) {
        try {
            String key = tClass.getName();
            Long increment = redisUtils.stringRedisTemplate.opsForValue().increment(key, delta);
            return Math.toIntExact(increment);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RedisSystemException(e.getMessage(), e);
        }
    }

    /**
     * 緩存預(yù)熱,用于項目啟動時初始化Redis中各個表的最大ID
     */
    public static <T> long incrPreheat(Class<T> tClass, Long maxValue) {
        if (maxValue == null) {
            maxValue = 0L;
        }
        if (maxValue < 0) {
            //異常拋出,預(yù)熱的初始值不能小于0
        }
        Integer incr = getIncr(tClass);
        if (maxValue <= incr) {
            return incr;
        }
        return getIncr(tClass, (int) (maxValue - incr));
    }
}

解釋:InitializingBean是Spring提供的拓展性接口,InitializingBean接口為bean提供了屬性初始化后的處理方法,它只有一個afterPropertiesSet方法,凡是繼承該接口的類,在bean的屬性初始化后都會執(zhí)行該方法。

3、緩存預(yù)熱

緩存預(yù)熱是指在項目啟動時,將每一張表當(dāng)前最大的主鍵ID預(yù)先加載到Redis中,這樣在后面使用的時候,就可以直接從Redis中獲取下一次ID即可,不需要再去訪問數(shù)據(jù)庫查詢最大ID,緩存預(yù)熱一般會建立在Redis專門的初始化類中,以便在啟動項目時可以運(yùn)行該類,具體如下:

/**
 * 緩存預(yù)熱
 *
 * @author hxy
 */
@Component
@DependsOn("redisUtils")
@RequiredArgsConstructor
public class RedisInit {

    private final UserMapper userMapper;

    /**
     * 獲取每一張表中當(dāng)前的最大ID,然后預(yù)熱到redis中
     */
    @PostConstruct
    public void init() {
        RedisUtils.incrPreheat(UserModel.class, userMapper.maxId());
    }
}

解釋:@DependsOn注解可以定義在類和方法上,意思是我這個組件要依賴于另一個組件,也就是說被依賴的組件會比該組件先注冊到IOC容器中。

解釋:@PostConstruct注解

在Java中,@PostConstruct注解,通常用于標(biāo)記一個方法,它表示該方法在類實例化之后(通過構(gòu)造函數(shù)創(chuàng)建對象之后)立即執(zhí)行。

加上@PostConstruct注解的方法會在對象的所有依賴項都已經(jīng)注入完成之后執(zhí)行。通過使用@PostConstruct注解,我們可以確保在對象完全創(chuàng)建和初始化之后才執(zhí)行這些操作。這個注解通常用在依賴注入(Dependency Injection)的框架中,例如Spring。

@PostConstruct 注解可以用在任何類的方法上,但它最常用于標(biāo)記在 Spring Framework 中的 Bean 類中的初始化方法。

4、model層封裝調(diào)用

在實例化一個model對象的時候,要將model的主鍵ID進(jìn)行賦值,這個時候就要從Redis中獲取到當(dāng)前對象應(yīng)該對應(yīng)的主鍵ID,我們可以在model類中構(gòu)建一個newInstance方法或有參構(gòu)造,來專門的生成需要賦值主鍵ID的對象,在方法中調(diào)用redis工具類的getIncr方法,獲取到最新最小未使用的主鍵ID并賦值給新建的model即可。

@Getter
@Setter
public class UserModel {

    private Integer id;

    private String name;

    private Integer age;

    private String tel;

    public UserModel() {
    }

    /**
     * 提供一個能夠生成自增ID的有參構(gòu)造,需要生成自增ID時調(diào)用
     */
    public UserModel(boolean autoId) {
        if (autoId) {
            this.id = RedisUtils.getIncr(UserModel.class);
        }
    }
}

如果你是需要批量創(chuàng)建對象并且給對象賦值主鍵ID的情況,可以按照如下方式使用,這樣可以只調(diào)用一次Redis,避免重復(fù)調(diào)用Redis影響性能。

@Service
@RequiredArgsConstructor
public class UserServiceImpl {

    private final UserMapper userMapper;

    public void batchAddUser(){
        int addNumber = 10;
        //提前生成自定跨度的ID,比如之前最大ID是6,獲取后得到的incr是16
        Integer incr = RedisUtils.getIncr(UserModel.class, addNumber);
        List<UserModel> userModels = new ArrayList<>();
        for (int i = 0; i < addNumber; i++) {
            UserModel userModel = new UserModel();
            //每一個主鍵ID依次遞減使用
            userModel.setId(incr--);
            userModels.add(userModel);
        }
        userMapper.insertBatch(userModels);
    }
}

至此,通過Redis來獲取對象自增ID的方法已經(jīng)完成,如果在使用過程中有其他場景需求,可以對redisUtils中的方法進(jìn)行拓展即可。

到此這篇關(guān)于分布式使用Redis實現(xiàn)數(shù)據(jù)庫對象自增主鍵ID的文章就介紹到這了,更多相關(guān)Redis對象自增主鍵ID內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis事務(wù)處理的使用操作方法

    Redis事務(wù)處理的使用操作方法

    Redis保證一個事務(wù)中的所有命令要么都執(zhí)行,要么都不執(zhí)行(原子性),如果客戶端發(fā)送了EXEC命令,所有的命令就都會被執(zhí)行,即使此后客戶端斷線也沒關(guān)系,因為Redis中已經(jīng)記錄了所有要執(zhí)行的命令,下面通過本文給大家介紹Redis事務(wù)處理的使用操作,感興趣的朋友一起看看吧
    2021-10-10
  • Redis SETEX命令實現(xiàn)鍵值對管理

    Redis SETEX命令實現(xiàn)鍵值對管理

    本文主要介紹了Redis SETEX命令實現(xiàn)鍵值對管理,SETEX命令用于設(shè)置具有過期時間的鍵值對,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • Redis之ZipList壓縮列表的使用

    Redis之ZipList壓縮列表的使用

    這篇文章主要介紹了Redis之ZipList壓縮列表的使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • Redis Desktop Manager(Redis可視化工具)安裝及使用圖文教程

    Redis Desktop Manager(Redis可視化工具)安裝及使用圖文教程

    這篇文章主要介紹了Redis Desktop Manager(Redis可視化工具)安裝及使用圖文教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • Redis生成分布式系統(tǒng)全局唯一ID的實現(xiàn)

    Redis生成分布式系統(tǒng)全局唯一ID的實現(xiàn)

    在互聯(lián)網(wǎng)系統(tǒng)中,并發(fā)越大的系統(tǒng),數(shù)據(jù)就越大,數(shù)據(jù)越大就越需要分布式,本文主要介紹了Redis生成分布式系統(tǒng)全局唯一ID的實現(xiàn),感興趣的可以了解一下
    2021-10-10
  • Redis?Lua同步鎖實現(xiàn)源碼解析

    Redis?Lua同步鎖實現(xiàn)源碼解析

    這篇文章主要為大家介紹了Redis?Lua同步鎖實現(xiàn)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Redis設(shè)置Hash數(shù)據(jù)類型的過期時間

    Redis設(shè)置Hash數(shù)據(jù)類型的過期時間

    在Redis中,我們可以使用Hash數(shù)據(jù)結(jié)構(gòu)來存儲一組鍵值對,而有時候,我們可能需要設(shè)置這些鍵值對的過期時間,本文主要介紹了Redis設(shè)置Hash數(shù)據(jù)類型的過期時間,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • SpringBoot3+Redis實現(xiàn)分布式鎖的配置方法

    SpringBoot3+Redis實現(xiàn)分布式鎖的配置方法

    這篇文章主要介紹了SpringBoot3+Redis實現(xiàn)分布式鎖,本文通過實例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • redis數(shù)據(jù)結(jié)構(gòu)之intset的實例詳解

    redis數(shù)據(jù)結(jié)構(gòu)之intset的實例詳解

    這篇文章主要介紹了redis數(shù)據(jù)結(jié)構(gòu)之intset的實例詳解的相關(guān)資料, intset也即整數(shù)集合,當(dāng)集合保存的值數(shù)量不多時,redis使用intset作為其底層數(shù)據(jù)保存結(jié)構(gòu),希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Redis數(shù)據(jù)遷移RedisShake的實現(xiàn)方法

    Redis數(shù)據(jù)遷移RedisShake的實現(xiàn)方法

    本文主要介紹了Redis數(shù)據(jù)遷移RedisShake的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評論

错那县| 石阡县| 措美县| 洛扎县| 连江县| 呼图壁县| 吐鲁番市| 汝南县| 监利县| 城口县| 桦甸市| 辽宁省| 南召县| 抚州市| 松潘县| 大足县| 巫溪县| 巨野县| 延津县| 茂名市| 林周县| 方城县| 牡丹江市| 吉林市| 微博| 孝义市| 汉阴县| 河源市| 兴隆县| 蓝田县| 陆良县| 陵川县| 武宣县| 德州市| 丰宁| 临泽县| 宁波市| 泾川县| 紫金县| 竹北市| 河南省|