Spring Data 教程 - Redis

来源:https://www.cnblogs.com/Butterfly-Tri/archive/2020/06/18/13160779.html
-Advertisement-
Play Games

1. Redis簡介 Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網路、可基於記憶體亦可持久化的日誌型、Key-Value 資料庫,並提供多種語言的API。Redis 是一個高性能的key-value資料庫。 redis的 ...


1. Redis簡介

Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網路、可基於記憶體亦可持久化的日誌型、Key-Value 資料庫,並提供多種語言的API。Redis 是一個高性能的key-value資料庫。 redis的出現,在部分場合可以對關係資料庫起到很好的補充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。

Redis支持主從同步。數據可以從主伺服器向任意數量的從伺服器上同步,從伺服器可以是關聯其他從伺服器的主伺服器。這使得Redis可執行單層樹複製。存檔可以有意無意的對數據進行寫操作。由於完全實現了發佈/訂閱機制,使得從資料庫在任何地方同步樹時,可訂閱一個頻道並接收主伺服器完整的消息發佈記錄。同步對讀取操作的可擴展性和數據冗餘很有幫助。

redis的key都是字元串String類型,它的value是多樣化的,如下圖:

redis數據類型 ENCODING返回的編碼 底層對應的數據結構
string int long類型的整數
string embstr embstr編碼的簡單動態字元串
string raw 簡單動態字元串
list ziplist 壓縮列表
list linkedlist 雙向鏈表
hash ziplist 壓縮列表
hash ht 字典
set intset 整數集合
set ht 字典
zset ziplist 壓縮列表
zset skiplist 跳錶

2. Redis的五種數據類型

2.1 字元串對象(String)

字元串對象的模型:

redis底層提供了三種不同的數據結構實現字元串對象,根據不同的數據自動選擇合適的數據結構。這裡的字元串對象並不是指的純粹的字元串,數字也是可以的。

  • int:當數據是long類型的整數字元串時,底層使用long類型的整數實現。這個值會直接存儲在字元串對象的ptr屬性中,同時OBJECT ENCODING為int。

  • raw:當數據為長度大於44位元組的字元串時,底層使用簡單動態字元串實現,說到這裡就不得不提下redis的簡單隨機字元串(Simple Dynamic String,SDS),SDS有三個屬性,free,len和buf。free存的是還剩多少空間,len存的是目前字元串長度,不包含結尾的空字元。buf是一個list,存放真實字元串數據,包含free和空字元。針對SDS本文不做詳細介紹,歡迎點擊SDS瞭解。

  • embstr:當數據為長度小於44位元組的字元串時,底層使用embstr編碼的簡單動態字元串實現。相比於raw,embstr記憶體分配只需要一次就可完成,分配的是一塊連續的記憶體空間。

2.2 列表對象(List)

列表對象的模型:

redis中的列表對象經常被用作消息隊列使用,底層採用ziplist和linkedlist實現。大家使用的時候當作鏈表使用就可以了。

  • ziplist

    列表對象使用ziplist編碼需要滿足兩個要求,一是所有字元串長度都小於設定值值64位元組(可以在配置文件中修改list-max-ziplist-value欄位改變)。二是所存元素數量小於設定值512個(可以在配置文件中修改list-max-ziplist-entries欄位改變)。ziplist類似與python中的list,占用一段連續的記憶體地址,由此減小指針記憶體占用。

    zlbytes:占記憶體總數

    zltail:到尾部的偏移量

    zllen:內部節點數

    node:節點

    zlend:尾部標識

    previous_entry_length:前一節點的長度

    encoding:數據類型

    content:真實數據

    遍歷的時候會根據zlbytes和zltail直接找到尾部節點nodeN,然後根據每個節點的previous_entry_length反向遍歷。增加和刪除節點會導致其他節點連鎖更新,因為每個節點都存儲了前一節點的長度。

  • linkedlist

    linkedlist有三個屬性,head,tail和len。head指向鏈表的頭部,tail指向鏈表的尾部,len為鏈表的長度。

2.3 哈希類型對象(Hash)

哈希類型對象的模型:

redis的value類型hash類型,其實就是map類型,就是在值的位置放一個map類型的數據。大家想詳細瞭解一下,可以參考一下這篇文章:https://www.jianshu.com/p/658365f0abfc

2.4 集合對象(Set)

集合對象類型的模型:

Set類型的value保證每個值都不重覆。

redis中的集合對象底層有兩種實現方式,分別有整數集合和hashtable。當所有元素都是整數且元素數小於512(可在配置文件中set-max-intset-entries欄位配置)時採用整數集合實現,其餘情況都採用hashtable實現。hashtable請移駕上文鏈接查閱,接下來介紹整數集合intset。intset有三個屬性,encoding:記錄數字的類型,有int16,int32和int64等,length:記錄集合的長度,content:存儲具體數據。具體結構如下圖:

2.5 有序集合對象

有序集合對象(zset)和集合對象(set)沒有很大區別,僅僅是多了一個分數(score)用來排序。

redis中的有序集合底層採用ziplist和skiplist跳錶實現,當所有字元串長度都小於設定值值64位元組(可以在配置文件中修改list-max-ziplist-value欄位改變),並且所存元素數量小於設定值512個(可以在配置文件中修改list-max-ziplist-entries欄位改變)使用ziplist實現,其他情況均使用skiplist實現,跳躍表的實現原理這裡偷個懶,給大家推薦一篇寫的非常好的博客,點擊查看跳躍表原理

3. Redis的安裝

可以去官網或者中文網下載Redis。redis的windows版本現在已經不更新了,所以我們安裝redis的6.0.3版本,這個版本支持的東西很多,在此次教程中,我們只對redis的五種數據類型做解釋和學習。

官網:https://redis.io/

中文網:https://www.redis.net.cn/

本教程安裝的redis版本為6.0.3版本,redis使用C語言編寫的,CentOS7的gcc自帶版本為4.8.5,而redis6.0+需要的gcc版本為5.3及以上,所以需要升級gcc版本。

下載Linux版本的tar.gz包,解壓以後進入解壓產生的包:

cd redis-6.0.3

發現沒有bin目錄,這裡需要通過make進行安裝。

# 先檢查gcc的環境 
gcc -v 
# 查看gcc版本 
yum -y install centos-release-scl 
# 升級到9.1版本 
yum -y install devtoolset-9-gcc devtoolset-9-gcc- c++ devtoolset-9-binutils 

scl enable devtoolset-9 bash 
#以上為臨時啟用,如果要長期使用gcc 9.1的話: 
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile 
# 進入redis解壓文件 
make 
# 6.0的坑,gcc版本 9.0 以上
# 等待完畢

執行完make操作之後,就可以在redis目錄看到src目錄了。進入src目錄後就可以看到redis-serverredis-cli

這裡建議將Redis的配置文件複製,保留一份原生的配置文件。

redis的配置大家可以在網上搜一下常用的配置,在這裡給大家推薦一個常用的配置,比較詳細:

https://blog.csdn.net/ymrfzr/article/details/51362125

到這裡redis就可以啟動並且正常訪問了。

註意:一定要將redis的IP地址綁定註釋掉,允許所有的IP地址訪問,不然我們從Windows訪問就訪問不了。

註釋掉下麵的這一行:

同時關閉Redis的服務保護模式,將protected-mode設置為no。如下:

4. Spring Boot 整合 Redis

  • 4.1 搭建工程,引入依賴

    搭建工程的操作我這裡就不在寫出來了。直接上pom.xml

    <!--springboot父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <dependencies>
        <!--springboot-web組件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
        <!--redis整合springboot組件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.3.0.RELEASE</version>
        </dependency>
        <!--lombok組件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>
    
  • 4.2 redis的配置

    項目的配置文件,application.yml

    butterflytri:
      host: 127.0.0.1
    server:
      port: 8080 # 應用埠
      servlet:
        context-path: /butterflytri # 應用映射
    spring:
      application:
        name: redis # 應用名稱
      redis:
        host: ${butterflytri.host} # redis地址
        port: 6379 # redis埠,預設是6379
        timeout: 10000 # 連接超時時間(ms)
        database: 0 # redis預設情況下有16個分片,這裡配置具體使用的分片,預設是0
        jedis: # 使用連接redis的工具-jedis
          pool:
            max-active: 8 # 連接池最大連接數(使用負值表示沒有限制) 預設 8
            max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制) 預設 -1
            max-idle: 8 # 連接池中的最大空閑連接 預設 8
            min-idle: 0 # 連接池中的最小空閑連接 預設 0
    

    另外還有額外的配置類RedisConfig.java

    package com.butterflytri.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    /**
     * @author: WJF
     * @date: 2020/5/24
     * @description: RedisConfig
     */
    
    @Configuration
    public class RedisConfig {
    
        /**
         * redis鍵值對的值的序列化方式:通用方式
         * @return RedisSerializer
         */
        private RedisSerializer redisValueSerializer() {
            return new GenericJackson2JsonRedisSerializer();
        }
    
        /**
         * redis鍵值對的健的序列化方式:所有的健都是字元串
         * @return RedisSerializer
         */
        private RedisSerializer redisKeySerializer() {
            return new StringRedisSerializer();
        }
    
        @Bean("redisTemplate")
        public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            redisTemplate.setKeySerializer(redisKeySerializer());
            redisTemplate.setValueSerializer(redisValueSerializer());
            return redisTemplate;
        }
    
    }
    
  • 4.3 redisTemplate的使用

    value類型的值的CRUD:

    ValueServiceImpl.java

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.ValueService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    /**
     * @author: WJF
     * @date: 2020/5/27
     * @description: ValueServiceImpl
     */
    @Service
    public class ValueServiceImpl implements ValueService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addValue(String key, Object value) {
            redisTemplate.opsForValue().set(key,value);
        }
    
        @Override
        public Object get(String key) {
            return redisTemplate.opsForValue().get(key);
        }
    
        @Override
        public Object update(String key, Object newValue) {
            return redisTemplate.opsForValue().getAndSet(key,newValue);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    }	
    

    List類型的值的CRUD:

    這裡我加了枚舉類型用來控制增加的位置,因為List類型對應的是鏈表。

    ListServiceImpl.java

    package com.butterflytri.service.impl;
    
    import com.butterflytri.enums.OpsType;
    import com.butterflytri.service.ListService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: ListServiceImpl
     */
    @Service
    public class ListServiceImpl implements ListService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addList(String key, List<Object> list, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPushAll(key, list);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPushAll(key, list);
                    break;
                default:
                    throw new RuntimeException("type不能為null");
            }
        }
    
        @Override
        public void add(String redisKey, Object value, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPush(redisKey, value);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPush(redisKey, value);
                    break;
                default:
                    throw new RuntimeException("type不能為null");
            }
        }
    
        @Override
        public List<Object> get(String key) {
            return redisTemplate.opsForList().range(key, 0, -1);
        }
    
        @Override
        public Object update(String key, Object value, Integer index) {
            Object obj = redisTemplate.opsForList().index(key, index);
            redisTemplate.opsForList().set(key,index,value);
            return obj;
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    
        @Override
        public void deleteValue(String redisKey, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPop(redisKey);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPop(redisKey);
                    break;
                default:
                    throw new RuntimeException("type不能為null");
            }
        }
    }
    

    Hash類型的值的CRUD:

    hash類型是我們使用最常用的類型。

    HashServiceImpl.java:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.HashService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Map;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: HashServiceImpl
     */
    @Service
    public class HashServiceImpl implements HashService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addHashAll(String key, Map<String, Object> value) {
            redisTemplate.opsForHash().putAll(key, value);
        }
    
        @Override
        public void addHash(String redisKey, String key, Object value) {
            redisTemplate.opsForHash().put(redisKey, key, value);
        }
    
        @Override
        public Object get(String redisKey, String key) {
            return redisTemplate.opsForHash().get(redisKey, key);
        }
    
        @Override
        public Object update(String redisKey, String key, Object value) {
            Object obj = this.get(redisKey, key);
            this.delete(redisKey,key);
            redisTemplate.opsForHash().put(redisKey, key, value);
            return obj;
        }
    
        @Override
        public void delete(String redisKey, String key) {
            redisTemplate.opsForHash().delete(redisKey, key);
        }
    
        @Override
        public void deleteAll(String redisKey) {
            redisTemplate.delete(redisKey);
        }
    }
    

    Set的值的CRUD:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.SetService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Set;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: SetServiceImpl
     */
    @Service
    public class SetServiceImpl implements SetService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
    
        @Override
        public void addAll(String key, Set<Object> set) {
            redisTemplate.opsForSet().add(key,set);
        }
    
        @Override
        public void add(String key, Object value) {
            redisTemplate.opsForSet().add(key,value);
        }
    
        @Override
        public Set<Object> findAll(String key) {
            return redisTemplate.opsForSet().members(key);
        }
    
        @Override
        public void deleteValue(String key, Object value) {
            redisTemplate.opsForSet().remove(key,value);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    }
    

    ZSet類型的值的CRUD:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.SortedSetService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.LinkedHashSet;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: SortedSetServiceImpl
     */
    @Service
    public class SortedSetServiceImpl implements SortedSetService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void add(String key, String value, Double score) {
            redisTemplate.opsForZSet().add(key, value, score);
        }
    
        @Override
        public LinkedHashSet<Object> findAll(String key) {
            return (LinkedHashSet<Object>) redisTemplate.opsForZSet().range(key,0,-1);
        }
    
        @Override
        public Long count(String key, Double scoreFrom, Double scoreTo) {
            return redisTemplate.opsForZSet().count(key,scoreFrom,scoreTo);
        }
    
        @Override
        public LinkedHashSet<Object> findByScore(String key, Double scoreFrom, Double scoreTo) {
            return (LinkedHashSet<Object>) redisTemplate.opsForZSet().rangeByScore(key,scoreFrom,scoreTo);
        }
    
        @Override
        public Long rank(String key, Object value) {
            return redisTemplate.opsForZSet().rank(key,value);
        }
    
        @Override
        public void remove(String key, String value) {
            redisTemplate.opsForZSet().remove(key,value);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    
    }
    

    redis的Java客戶端有很多,在這裡我們使用的是jedis,還有一個很好的Java語言的客戶端叫lettuce,大家可以去瞭解一下,Spring從不重覆造輪子,只會簡化輪子的使用,redisTemplate就是一個超級簡單的使用實現。到這裡redis整合Spring Boot 就結束了。

5. 項目地址

本項目傳送門:

此教程會一直更新下去,覺得博主寫的可以的話,關註一下,也可以更方便下次來學習。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。 原文出處:https://dzone.com/articles/why-masses-are-not-using-latest-css-features-in-20 儘管CSS每年都會發佈全新的特性,但實際上 ...
  • 6.1 webpack概念的引入 在網頁中會引用哪些常見的靜態資源? JS .js、 .jsx 、.coffee、 .ts(TypeScript 類 C# 語言) CSS .css、 .less、 .sass 、.scss Images .jpg 、.png、 .gif 、.bmp 、.svg 字體 ...
  • 常用設計模式思維導圖,大部分設計模式在spring和jdk源碼中都有體現。 在學習spring源碼前,有必要花一定時間瞭解設計模式。 ...
  • 訪問者模式是一種較為複雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素具有不同的類型,且不同的訪問者可以對其進行不同的訪問操作 模式動機 對於系統中某些對象,它們存儲在同一個集合中,且具有不同的類型。對於該集合中的對象,可以接受一類稱為訪問者的對象來訪問,不同的訪問者其 ...
  • 1.模型管理 :web線上流程設計器、預覽流程xml、導出xml、部署流程 2.流程管理 :導入導出流程資源文件、查看流程圖、根據流程實例反射出流程模型、激活掛起 3.運行中流程:查看流程信息、當前任務節點、當前流程圖、作廢暫停流程、指派待辦人 4.歷史的流程:查看流程信息、流程用時、流程狀態、查看 ...
  • #一、解釋器模式介紹 ##1、定義與類型 定義:給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。 為瞭解釋一種語言,而為語言創建的解釋器 類型:行為型 #2、適用場景 某個特定類型問題發生頻率足夠高 ##3、優點 語法由很多類表示,容易改變及擴展此“語 ...
  • 首先是個人的一些閱讀源碼的小技巧,不一定適用每個人,可以直接跳過。 閱讀源碼的一些個人技巧 博客+總結 個人覺得大多數情況下跟著一篇優秀的博客配合著看就足夠了,之後再自己寫博客總結一遍加深印象,畫一下流程圖基本都能理順。(圖為學AQS時本人畫的獲取獨占鎖流程圖) 類關係 配合idea看類之間的關係( ...
  • 一、網格包佈局舉例 1.這裡構造一個3*3的佈局。 package com.bjpowernode.java_learning; ​ import java.awt.Frame; import java.awt.*; ​ public class D123_1_GridLayout { public ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...