Redisのインクリメント呼び出しが失敗する理由と推奨される使い方を大きな白い嘘で解説
プロジェクトでは基本的にredisに出会うことになりますが、spring-data-redis-2.*. *RELEASE.jarには、redisに保存されたデータを簡単に操作するためのHelperクラスが2つ用意されています。この2つのHelperクラスはRedisTemplateとStringRedisTemplateで、StringRedisTemplateはString型を保存するためのRedisTemplateの拡張サブクラスです。そのため、redisを利用する際には
1.String型を操作する場合は、StringRedisTemplateを優先してください。
2、型が複雑なオブジェクトの場合、RedisTemplateの考慮は限定的です。
コール数の記録、インターフェースのコールスレッショルドの記録など、カウントの場面でredisを使っている人が、RedisTemplateで以下のエラーERR value is not an integer or out of rangeが発生した場合、まず解決策は以下のようになります。
//Inject StringRedisTemplate directly into the class
@Autowired
private StringRedisTemplate stringRedisTemplate;
//count in the method body with
stringRedisTemplate.opsForValue().increment("check:incr:str");
つまり、RedisTemplateをStringRedisTemplateに置き換えてください。
上記の理由は、シリアライゼーションによるものです。redisではデータはバイナリ形式で保存されることが分かっているので、必然的にシリアライズと逆シリアライズを伴います。上記の2つのHelperクラスは、シリアライズと逆シリアライズを自動的に支援してくれますが、両者の主な違いは、シリアライズ機構にあります
1. StringRedisTemplateのシリアライズ機構は、StringRedisSerializerによって実装されています。
2. RedisTemplateのシリアライズ機構は、JdkSerializationRedisSerializerを通して実装されています。
インクリメント操作は、一番下がデータの読み込み、次に+1、そしてsetですが、この3ステップはredisプラス原子操作で保証されているので、StringRedisTemplateとRedisTemplateからsetメソッドを解析してみましょう。まず、StringRedisTemplateのソースコードを見てみると、以下のようになっています。
1. stringRedisTemplate.opsForValue().set("check:incr:str", "1")を実行。
2. 1.のsetメソッドを確認し、DefaultValueOperationsクラスのsetメソッドに移動する
@Override
public void set(K key, V value) {
byte[] rawValue = rawValue(value);
execute(new ValueDeserializingRedisCallback(key) {
@Override
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
connection.set(rawKey, rawValue);
return null;
}
}, true);
}
3. 値を処理するrawValueメソッドの2段階目を確認し、AbstractOperations.rawValueメソッドに移動します。
@SuppressWarnings("unchecked")
byte[] rawValue(Object value) {
if (valueSerializer() == null && value instanceof byte[]) {
return (byte[]) value;
}
return valueSerializer().serialize(value);
}
4. 3番目のステップでは、最終的にシリアライズクラスを呼び出して値のシリアライズを行っていることから、StringRedisTemplateのシリアライズクラスStringRedisSerializerが
ステップ3のserializeの最終行は、結局、以下のメソッドを呼び出していることがわかります。
@Override
public byte[] serialize(@Nullable String string) {
return (string == null ? null : string.getBytes(charset));
}
5. この時点で、value redisの最後の存在の底原理は、4番目のステップでreturnで返されたbyte[]であることがわかります。では、こう考えてみてください。
stringRedisTemplate.opsForValue().set("check:incr:str", "1"); あたかも "1".getBytes("UTF-8& quot;) のようなものである。
public static void main(String[] args) throws UnsupportedEncodingException {
byte[] str = "1".getBytes("UTF-8");
for(int i = 0 ; i< str.length; i++) {
System.out.println(str[i]);
}
}
結論
上のmainメソッドは49を出力していますが、setメソッドを理解した上で、incrementの呼び出しは49に直接1を足して50にし、データを取得する際に逆シリアライズして数字の2に対応することを示すのと同じだと推測することができます
[...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...]関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
redis分散ロックについて解説(redis分散ロックの最適化処理とRedissonの利用について)
-
redisでluaスクリプトを使用するためのチュートリアル
-
Redisにおけるビットマップの説明
-
SpringBootのRedis連携のアイデア解説
-
Redisによる分散シングルナンバーと分散ID(カスタムルール生成)
-
redisを使ってnearly peopleの機能を実装する
-
Redisの高同期スパイクを防ぐために、ソースコードソリューションを売られすぎ
-
マイクロサービス領域におけるredisの貢献度を説明する
-
シングルスレッドのredisがなぜ速いのかの紹介
-
RedisClusterが16,384個のスロットを持つ設計になっている理由