整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          redis系列:通過隊列案例學習list命令

          這一篇文章將講述Redis中的list類型命令,同樣也是通過demo來講述,其他部分這里就不在贅述了。

          項目Github地址:https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-list

          案例

          demo功能是隊列,整個demo的大致頁面如下。左邊是存儲到Redis中的數據,右邊是從Redis中彈出的數據。

          準備工作

          首先定義一個存儲list的key

          private static final String LIST_KEY = "list:1";
          

          隊列的key就用list:1

          redis操作對象

          private RedisTemplate redisTemplate;
          //string 命令操作對象
          private ValueOperations valueOperations;
          //list 命令操作對象
          private ListOperations listOperations;
          

          list在Redis中的結構可以看下圖(圖片來源于Redis in Action)。

          插入數據

          頭部插入

          命令介紹

          命令用例描述LPUSHLPUSH key value [value ...]將所有指定的值插入到存于 key 的列表的頭部。 如果 key 不存在,那么在進行 push 操作前會創建一個空列表。LPUSHXLPUSHX key value只有當 key 已經存在并且存著一個 list 的時候,在這個 key 下面的 list 的頭部插入 value。

          接下來看看demo中頭部插入的功能,點擊下圖中頭部插入按鈕,然后在彈出框中填入數字0,點擊提交后整個頭部插入流程結束。可以看到左邊的隊列數據出現了一條{"data":"0"} 數據,在數據{"data":"1"} 上面。

          來看看后臺的方法

          @RequestMapping(value = "/leftPop",method = RequestMethod.GET)
          public Object leftPop(){
           return listOperations.leftPop(LIST_KEY);
          }
          

          如果需要在Redis中操作,可以敲下面的命令

          lpush list:1 "{\"data\":\"0\"}" 
          

          尾部插入

          命令介紹

          命令用例描述RPUSHRPUSH key value [value ...]向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么會創建一個空的列表然后再進行 push 操作。RPUSHXRPUSHX key value將值 value 插入到列表 key 的表尾, 當且僅當 key 存在并且是一個列表。

          接下來看看demo中尾部插入的功能,點擊下圖中尾部插入按鈕,然后在彈出框中填入數字11,點擊提交后整個新增流程結束。可以看到左邊的隊列數據出現了一條{"data":"11"} 數據,在數據{"data":"10"}下面。

          來看看后臺的方法

          @RequestMapping(value = "/rightPop",method = RequestMethod.GET)
          public Object rightPop(){
           return listOperations.rightPop(LIST_KEY);
          }
          

          如果需要在Redis中操作,可以敲下面的命令

          rpush list:1 "{\"data\":\"11\"}" 
          

          列表查詢

          命令介紹

          同樣先看看相關的獲取值命令

          命令用例描述LRANGELRANGE key start stop返回存儲在 key 的列表里指定范圍內的元素。LINDEXLINDEX key index返回列表里的元素的索引 index 存儲在 key 里面。LLENLLEN key返回存儲在 key 里的list的長度。

          后臺查詢方法,將新增的內容查詢出來

          @RequestMapping(value = "/getList",method = RequestMethod.GET)
          public List getList(){
           List list = listOperations.range(LIST_KEY, 0, -1);
           //可以用size獲取成員長度
           //listOperations.size(LIST_KEY);
           return list;
          }
          

          數據彈出

          頭部彈出

          命令用例描述LPOPLPOP key移除并且返回 key 對應的 list 的第一個元素。BLPOPBLPOP key [key ...] timeout它是命令 LPOP 的阻塞版本,這是因為當給定列表內沒有任何元素可供彈出的時候, 連接將被 BLPOP 命令阻塞。

          接下來看看頭部彈出的功能,點擊下圖中頭部彈出按鈕,可以看到左邊的隊列頂部數據減少了,在右邊彈出的數據出現了左邊隊列數據消失的數據。

          來看看后臺的方法

          @RequestMapping(value = "/leftPop",method = RequestMethod.GET)
          public Object leftPop(){
           return listOperations.leftPop(LIST_KEY);
          }
          

          如果需要在Redis中操作,可以敲下面的命令

          lpop list:1 
          

          尾部彈出

          命令用例描述RPOPRPOP key移除并返回存于 key 的 list 的最后一個元素。BRPOPBRPOP key [key ...] timeout它是 RPOP 的阻塞版本,因為這個命令會在給定list無法彈出任何元素的時候阻塞連接。

          接下來看看尾部彈出的功能,點擊下圖中尾部彈出按鈕,可以看到左邊的隊列尾部數據減少了,在右邊彈出的數據出現了左邊隊列數據消失的數據。

          來看看后臺的方法

          @RequestMapping(value = "/rightPop",method = RequestMethod.GET)
          public Object rightPop(){
           return listOperations.rightPop(LIST_KEY);
          }
          

          如果需要在Redis中操作,可以敲下面的命令

          rpop list:1 
          

          其他命令

          命令用例描述LINSERTLINSERT key BEFORE\AFTER pivot value把 value 插入存于 key 的列表中在基準值 pivot 的前面或后面。LREMLREM key count value從存于 key 的列表里移除前 count 次出現的值為 value 的元素。LSETLSET key index value設置 index 位置的list元素的值為 value。LTRIMLTRIM key start stop修剪(trim)一個已存在的 list,這樣 list 就會只包含指定范圍的指定元素。RPOPLPUSHRPOPLPUSH source destination原子性地返回并移除存儲在 source 的列表的最后一個元素(列表尾部元素), 并把該元素放入存儲在 destination 的列表的第一個元素位置(列表頭部)。BRPOPLPUSHBRPOPLPUSH source destination timeoutBRPOPLPUSH 是 RPOPLPUSH 的阻塞版本。

          RPOPLPUSH和BRPOPLPUSH

          這兩個命令作用其實是相同的,只不過BRPOPLPUSH是阻塞的,當沒有數據時,會一直阻塞,直到有數據。

          在Redis官方文檔中,用RPOPLPUSH命令舉了兩個例子,一個是Reliable queue(安全的隊列 ),另一個是Circular list(循環列表)。

          Reliable queue(安全的隊列 )

          Redis通常都被用做一個處理各種后臺工作或消息任務的消息服務器。 一個簡單的隊列模式就是:生產者把消息放入一個列表中,等待消息的消費者用 RPOP 命令(用輪詢方式), 或者用 BRPOP 命令(如果客戶端使用阻塞操作會更好)來得到這個消息。

          然而,因為消息有可能會丟失,所以這種隊列并是不安全的。例如,當接收到消息后,出現了網絡問題或者消費者端崩潰了, 那么這個消息就丟失了。

          RPOPLPUSH (或者其阻塞版本的 BRPOPLPUSH) 提供了一種方法來避免這個問題:消費者端取到消息的同時把該消息放入一個正在處理中的列表。 當消息被處理了之后,該命令會使用 LREM 命令來移除正在處理中列表中的對應消息。

          另外,可以添加一個客戶端來監控這個正在處理中列表,如果有某些消息已經在這個列表中存在很長時間了(即超過一定的處理時限), 那么這個客戶端會把這些超時消息重新加入到隊列中。

          翻譯來自 http://www.redis.cn/commands/rpoplpush.html

          Circular list(循環列表)

          RPOPLPUSH 命令的 source 和 destination 是相同的話, 那么客戶端在訪問一個擁有n個元素的列表時,可以在 O(N) 時間里一個接一個獲取列表元素, 而不用像 LRANGE那樣需要把整個列表從服務器端傳送到客戶端。

          上面這種模式即使在以下兩種情況下照樣能很好地工作: 有多個客戶端同時對同一個列表進行旋轉(rotating):它們會取得不同的元素,直到列表里所有元素都被訪問過,又從頭開始這個操作。 有其他客戶端在往列表末端加入新的元素。

          這個模式讓我們可以很容易地實現這樣一個系統:有 N 個客戶端,需要連續不斷地對一批元素進行處理,而且處理的過程必須盡可能地快。 一個典型的例子就是服務器上的監控程序:它們需要在盡可能短的時間內,并行地檢查一批網站,確保它們的可訪問性。

          值得注意的是,使用這個模式的客戶端是易于擴展(scalable)且安全的(reliable),因為即使客戶端把接收到的消息丟失了, 這個消息依然存在于隊列中,等下次迭代到它的時候,由其他客戶端進行處理。

          翻譯來自 http://www.redis.cn/commands/rpoplpush.html

          案例-約瑟夫問題

          約瑟夫問題(有時也稱為約瑟夫斯置換),是一個出現在計算機科學和數學中的問題。在計算機編程的算法中,類似問題又稱為約瑟夫環。

          人們站在一個等待被處決的圈子里。 計數從圓圈中的指定點開始,并沿指定方向圍繞圓圈進行。 在跳過指定數量的人之后,執行下一個人。 對剩下的人重復該過程,從下一個人開始,朝同一方向跳過相同數量的人,直到只剩下一個人,并被釋放。

          問題即,給定人數、起點、方向和要跳過的數字,選擇初始圓圈中的位置以避免被處決。

          來自維基百科 https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98

          思路

          定義一個list key為josephus,利用

          RPOPLPUSH josephus josephus
          

          命令來構造循環鏈表,每當數到3時,使用rpop

          rpop josephus
          

          命令彈出

          代碼實現

          public class JosephusProblem extends RedisBaseConnection {
           @Test
           public void test() {
           //構造數據
           for (int i = 1; i <= 41; i++) {
           listOperations.leftPush("josephus", String.valueOf(i));
           }
           int index = 1;
           while (listOperations.size("josephus") > 0) {
           //當數到3時,彈出
           if (index == 3) {
           System.out.println(listOperations.range("josephus", 0, -1));
           System.out.println("當前被殺的人是:" + listOperations.rightPop("josephus"));
           index = 0;
           } else {
           listOperations.rightPopAndLeftPush("josephus", "josephus");
           }
           index++;
           }
           }
          }
          

          整個代碼步驟如下

          1. 先是模擬有41個人(向redis中key為josephus的list添加41個數據)
          2. 定義索引index
          3. 循環判斷key為josephus的數據長度是否大于0
          4. 當索引index為3時,調用Redis的rpop命令彈出對應的數據。索引index不為3時,調用RPOPLPUSH命令,將對應的數據放到隊列頭部
          5. 索引index加1

          運行結果有點長,這里只截圖最后一部分的結果,如下

          約瑟夫問題代碼請點擊JosephusProblem.java


          建議學習的人最好每個命令都去敲下,加深印象。下面詩句送給你們。

          紙上得來終覺淺,絕知此事要躬行。————出自《冬夜讀書示子聿》

          作者:勿妄

          .1、 循環表達式語法

          thymeleaf使用th:each屬性可以對數組,集合進行循環,此屬性用在容器元素上,循環生成子元素。

          語法

          th:each="循環出的元素 , 循環狀態 : 集合或數組"

          6.2、數組的循環

          示例

          在TestServlet中定義一個數組

          String [] arr = {"HTML","CSS","JavaScript"};
          request.setAttribute("arr",arr);

          在index.html中循環顯示數組中的元素

          <div th:text="'數組元素數量:' + ${arr.length}"> </div><!--獲取數組元素的數量-->
          <ul th:each="s : ${arr}">
          	<li th:text="${s}"></li>
          </ul>

          運行test.do,頁面顯示效果如下

          6.3、循環狀態的使用

          在th:each中循環狀態不是必須的,它是一個對象,具有以下屬性

          屬性名

          說明

          index

          整型屬性,當前迭代索引,從0開始

          count

          整型屬性,當前的迭代計數,從1開始

          size

          整型屬性,迭代變量中元素的總量

          current

          對象屬性,每次迭代的 iter 變量,即當前遍歷到的元素

          even/odd

          布爾屬性,當前的迭代是偶數還是奇數

          first

          布爾屬性,當前的迭代是否是第?個迭代

          last

          布爾屬性,當前的迭代是否是最后?個迭代。

          修改上一個示例,顯示每次循環的各狀態的值

          <table border="1">	
          	<tr>			
                 <th>當前迭代索引</th>	
                 <th>當前迭代計數</th>	
          	<th>元素的總量</th>	
          	<th>當前遍歷到的元素</th>		
          	<th>當前遍歷的偶數</th>			
                  <th>是否是第一條</th>			
                  <th>是否是最后一條</th>	
          	</tr>		
          <tbody th:each="s,status : ${arr}">		
          	<tr><td th:text="${status.index}"></td>			
          	    <td th:text="${status.count}"></td>			
          	    <td th:text="${status.size}"></td>	
          	    <td th:text="${status.current}"></td>				
                      <td  th:text="${status.even}"></td>		
                      <td th:text="${status.first}"></td>			
          	    <td th:text="${status.last}"></td>	
          	</tr>	
          </tbody>
          	</table>

          運行test.do,頁面顯示效果如下

          6.4、list的循環

          示例

          在TestServelt中添加一個List集合

          List list = new ArrayList<>();
           list.add("HTML"); 
          list.add("CSS");
          list.add("JavaScript");
          request.setAttribute("list", list);

          在index.html中循環顯示列表中的數據

          <div th:text="'list中元素數量:' + ${list.size}"> </div>
          <ul th:each="s : ${list}">
          	<li th:text="${s}"></li>
          </ul>

          運行test.do,頁面顯示效果如下

          6.5、map集合的訪問

          1) 直接訪問

          map集合可以通過key獲取值,也可以獲取集合中元素的數據

          示例

          在TestServelt中添加map集合

          Map<String,String> map = new HashMap<>();
          map.put("HTML", "超文本標記語言");
          map.put("CSS", "層疊樣式表");
          request.setAttribute("map", map);

          在頁面中輸出map的信息

          <ul>		
          
          <li >集合:[[${map}]]</li>		
          <li>指定key的值:[[${map.HTML}]]</li>		
          <li>集合中元素的數量:[[${map.size}]]</li>		
          	</ul>

          運行test.do,頁面顯示效果如下

          2)循環訪問

          Map循環的每個元素的類型是Entry,可以通過此Entry對象的key屬性獲取鍵,value屬性獲取值

          修改index.html,循環顯示map集合中的內容

          <ul th:each="entry : ${map}">		
          <li >			
          <strong th:text="${entry.key}"></strong> 
          :
          <em th:text="${entry.value}"></em>		
          </li>	</ul>

          運行test.do,頁面顯示效果如下

          6.6 th:block標簽

          在使用th:if時,如果是一當條件成立需要加載一組標簽,在循環時,循環的元素外沒有容器時,可以使用th:block標簽做為外容器,th:block僅是一個屬性容器,允許開發人員指定他們想要的任何屬性

          示例

          <th:block th:each="s : ${list}">     
            <div th:text="${s}"></div></th:block>



          文章來源于嗶站《六、循環表達式 - 嗶哩嗶哩》

          更多學習視頻和專欄文章請到嗶站個人空間: 布道師學院的個人空間-布道師學院個人主頁-嗶哩嗶哩視頻

          更多資源和項目下載請到:”開源吧(找實戰項目和畢設項目的好網站)“ :開源吧

          表 & Key

          首先,讓我們看下在 Javascript 中如何轉化列表。

          如下代碼,我們使用 map() 函數讓數組中的每一項變雙倍,然后我們得到了一個新的列表 doubled 并打印出來:

          const numbers = [1, 2, 3, 4, 5];
          const doubled = numbers.map((number) => number * 2);
          console.log(doubled);
          

          代碼打印出 [2, 4, 6, 8, 10]。

          在 React 中,把數組轉化為元素列表的過程是相似的。

          渲染多個組件

          你可以通過使用 {} 在 JSX 內構建一個元素集合。

          下面,我們使用 Javascript 中的 map() 方法來遍歷 numbers 數組。將數組中的每個元素變成

        1. 標簽,最后我們將得到的數組賦值給 listItems:
        2. const numbers = [1, 2, 3, 4, 5];
          const listItems = numbers.map((number) =>
            <li>{number}</li>
          );
          

          我們把整個 listItems 插入到

          • 元素中,然后渲染進 DOM:
          ReactDOM.render(
            <ul>{listItems}</ul>,
            document.getElementById('root')
          );
          

          這段代碼生成了一個 1 到 5 的項目符號列表。

          基礎列表組件

          通常你需要在一個組件中渲染列表。

          我們可以把前面的例子重構成一個組件,這個組件接收 numbers 數組作為參數并輸出一個元素列表。

          function NumberList(props) {
            const numbers = props.numbers;
            const listItems = numbers.map((number) =>
              <li>{number}</li>
            );
            return (
              <ul>{listItems}</ul>
            );
          }
          
          const numbers = [1, 2, 3, 4, 5];
          ReactDOM.render(
            <NumberList numbers={numbers} />,
            document.getElementById('root')
          );
          

          當我們運行這段代碼,將會看到一個警告 a key should be provided for list items,意思是當你創建一個元素時,必須包括一個特殊的 key 屬性。我們將在下一節討論這是為什么。

          讓我們來給每個列表元素分配一個 key 屬性來解決上面的那個警告:

          function NumberList(props) {
            const numbers = props.numbers;
            const listItems = numbers.map((number) =>
              <li key={number.toString()}>
                {number}
              </li>
            );
            return (
              <ul>{listItems}</ul>
            );
          }
          
          const numbers = [1, 2, 3, 4, 5];
          ReactDOM.render(
            <NumberList numbers={numbers} />,
            document.getElementById('root')
          );
          

          key

          key 幫助 React 識別哪些元素改變了,比如被添加或刪除。因此你應當給數組中的每一個元素賦予一個確定的標識。

          const numbers = [1, 2, 3, 4, 5];
          const listItems = numbers.map((number) =>
            <li key={number.toString()}>
              {number}
            </li>
          );
          

          一個元素的 key 最好是這個元素在列表中擁有的一個獨一無二的字符串。通常,我們使用數據中的 id 來作為元素的 key:

          const todoItems = todos.map((todo) =>
            <li key={todo.id}>
              {todo.text}
            </li>
          );
          

          當元素沒有確定 id 的時候,萬不得已你可以使用元素索引 index 作為 key:

          const todoItems = todos.map((todo, index) =>
            // Only do this if items have no stable IDs
            <li key={index}>
              {todo.text}
            </li>
          );
          

          如果列表項目的順序可能會變化,我們不建議使用索引來用作 key 值,因為這樣做會導致性能變差,還可能引起組件狀態的問題。可以看看 Robin Pokorny 的深度解析使用索引作為 key 的負面影響這一篇文章。如果你選擇不指定顯式的 key 值,那么 React 將默認使用索引用作為列表項目的 key 值。

          要是你有興趣了解更多的話,這里有一篇文章深入解析為什么 key 是必須的可以參考。

          用 key 提取組件

          元素的 key 只有放在就近的數組上下文中才有意義。

          比方說,如果你提取出一個 ListItem 組件,你應該把 key 保留在數組中的這個 元素上,而不是放在 ListItem 組件中的

        3. 元素上。
        4. 例子:不正確的使用 key 的方式

          function ListItem(props) {
            const value = props.value;
            return (
              // 錯誤!你不需要在這里指定 key:
              <li key={value.toString()}>
                {value}
              </li>
            );
          }
          
          function NumberList(props) {
            const numbers = props.numbers;
            const listItems = numbers.map((number) =>
              // 錯誤!元素的 key 應該在這里指定:
              <ListItem value={number} />
            );
            return (
              <ul>
                {listItems}
              </ul>
            );
          }
          
          const numbers = [1, 2, 3, 4, 5];
          ReactDOM.render(
            <NumberList numbers={numbers} />,
            document.getElementById('root')
          );
          

          例子:正確的使用 key 的方式

          function ListItem(props) {
            // 正確!這里不需要指定 key:
            return <li>{props.value}</li>;
          }
          
          function NumberList(props) {
            const numbers = props.numbers;
            const listItems = numbers.map((number) =>
              // 正確!key 應該在數組的上下文中被指定
              <ListItem key={number.toString()}
                        value={number} />
            );
            return (
              <ul>
                {listItems}
              </ul>
            );
          }
          
          const numbers = [1, 2, 3, 4, 5];
          ReactDOM.render(
            <NumberList numbers={numbers} />,
            document.getElementById('root')
          );
          

          一個好的經驗法則是:在 map() 方法中的元素需要設置 key 屬性。

          key 只是在兄弟節點之間必須唯一

          數組元素中使用的 key 在其兄弟節點之間應該是獨一無二的。然而,它們不需要是全局唯一的。當我們生成兩個不同的數組時,我們可以使用相同的 key 值:

          function Blog(props) {
            const sidebar = (
              <ul>
                {props.posts.map((post) =>
                  <li key={post.id}>
                    {post.title}
                  </li>
                )}
              </ul>
            );
            const content = props.posts.map((post) =>
              <div key={post.id}>
                <h3>{post.title}</h3>
                <p>{post.content}</p>
              </div>
            );
            return (
              <div>
                {sidebar}
                <hr />
                {content}
              </div>
            );
          }
          
          const posts = [
            {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
            {id: 2, title: 'Installation', content: 'You can install React from npm.'}
          ];
          ReactDOM.render(
            <Blog posts={posts} />,
            document.getElementById('root')
          );
          
          

          key 會傳遞信息給 React ,但不會傳遞給你的組件。如果你的組件中需要使用 key 屬性的值,請用其他屬性名顯式傳遞這個值:

          const content = posts.map((post) =>
            <Post
              key={post.id}
              id={post.id}
              title={post.title} />
          );
          

          上面例子中,Post 組件可以讀出 props.id,但是不能讀出 props.key。

          在 JSX 中嵌入 map()

          在上面的例子中,我們聲明了一個單獨的 listItems 變量并將其包含在 JSX 中:

          function NumberList(props) {
            const numbers = props.numbers;
            const listItems = numbers.map((number) =>
              <ListItem key={number.toString()}
                        value={number} />
            );
            return (
              <ul>
                {listItems}
              </ul>
            );
          }
          

          JSX 允許在大括號中嵌入任何表達式,所以我們可以內聯 map() 返回的結果:

          function NumberList(props) {
            const numbers = props.numbers;
            return (
              <ul>
                {numbers.map((number) =>
                  <ListItem key={number.toString()}
                            value={number} />
                )}
              </ul>
            );
          }
          
          

          這么做有時可以使你的代碼更清晰,但有時這種風格也會被濫用。就像在 JavaScript 中一樣,何時需要為了可讀性提取出一個變量,這完全取決于你。但請記住,如果一個 map() 嵌套了太多層級,那可能就是你提取組件的一個好時機。


          主站蜘蛛池模板: 精品国产一区二区三区| 无码一区二区三区视频| 激情久久av一区av二区av三区| 不卡无码人妻一区三区音频| 日本激情一区二区三区| 国产成人AV一区二区三区无码| 国产一区二区三区免费看| 亚洲AV无码国产一区二区三区| 日本道免费精品一区二区| 国产亚洲综合精品一区二区三区 | 在线播放一区二区| 国产精品主播一区二区| 免费观看日本污污ww网站一区| 在线观看国产一区二三区| 久久久久人妻精品一区蜜桃| 黑人大战亚洲人精品一区| 亚洲乱码国产一区网址| 国产亚洲综合精品一区二区三区| 国产精品一区二区不卡| 2021国产精品视频一区| 亚洲国产成人久久综合一区 | 91午夜精品亚洲一区二区三区 | 国产成人高清亚洲一区91| 成人无号精品一区二区三区| 亚洲色一区二区三区四区| 欧美日韩精品一区二区在线观看 | 亚洲综合无码一区二区痴汉| 在线视频一区二区三区| 亚洲一区二区三区在线| 国产一区二区三区乱码网站| 国产精品综合AV一区二区国产馆| 日韩免费一区二区三区在线播放| 精品国产一区AV天美传媒| 精品一区二区三区四区在线播放| 2022年亚洲午夜一区二区福利| 亚洲宅男精品一区在线观看| 国产午夜精品一区二区三区极品 | 91麻豆精品国产自产在线观看一区 | 国产人妖视频一区二区| 中文字幕在线一区二区在线 | 日本精品一区二区三本中文|