127.0.0.1:6379> flushall //清空数据库
OK
127.0.0.1:6379> set name zzz //设置key为name,value为zzz
OK
127.0.0.1:6379> set age 3 //设置key为age,值为3
OK
127.0.0.1:6379> keys * //查看所有的 key
1) "name"
2) "age"
127.0.0.1:6379> exists name //检查是否存在 名为 name 的 key
(integer) 1 // 1 表示存在
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> move name 1 //移除 name
(integer) 1 // 1 表示移除成功
(1.16s)
127.0.0.1:6379> keys * //查看所有的 key
1) "age"
127.0.0.1:6379> expire name 10 //设置 name 的过期时间为 10 秒钟,单点登录可以使用 Redis 的过期功能
(integer) 1
127.0.0.1:6379> ttl name //查看过期时间,已经过期2秒钟
(integer) -2
127.0.0.1:6379> get name //此时 name 已不存在
(nil)
127.0.0.1:6379> type name //查看 key 中所存储的 value 的数据类型
string // string 类型
127.0.0.1:6379> type age //查看 key 中所存储的 value 的数据类型
string // string 类型
Redis 所有命令可以在:Commands | Redis 中去查看。
3.2 String 类型
由于在 Linux 环境中是使用终端命令来对 Redis 进行一些操作的,所以下面通过对一些 String 类型的命令的操作来进行讲解。
127.0.0.1:6379> set key1 v1 //设置 key-value
OK
127.0.0.1:6379> get key1 //通过 get-key 来获取 value
"v1"
127.0.0.1:6379> append key1 "hello" //追加字符串,如果 key 不存在,就相当于重新 set key
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> strlen key1 //获取字符串长度
(integer) 7
127.0.0.1:6379> append key1 "+apluemxa" //追加字符串
(integer) 16
127.0.0.1:6379> get key1
"v1hello+apluemxa"
下面再对 Redis 中一些现有的自增、自减、设置步长操作进行讲解:
127.0.0.1:6379> set views 0 //设置 key 为0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views //自增
(integer) 1
127.0.0.1:6379> incr views
(integer) 5
127.0.0.1:6379> get views
"5"
127.0.0.1:6379> incrby views 20 //设置步长,并指定增量
(integer) 23
127.0.0.1:6379> get views
"23"
127.0.0.1:6379> DECRBY views 8 //设置步长,并指定减量
(integer) 15
下面是对字符串范围 range 做一个讲解:
127.0.0.1:6379> set key1 "helle,world!" //设置 key 以及 value
OK
127.0.0.1:6379> get key1 //通过 key 获取 value
"helle,world!"
127.0.0.1:6379> GETRANGE key1 0 3 //截取字符串 [0,3](数组下标)
"hell"
127.0.0.1:6379> GETRANGE key1 0 -1 //表示截取所有的字符串,与 get key 作用一致
"helle,world!"
127.0.0.1:6379> GETRANGE key1 2 6 //截取字符串 [2,6](数组下标)
"lle,w"
127.0.0.1:6379> SETRANGE key1 2 xx //替换字符串为 xx,2为数组下标
(integer) 12
127.0.0.1:6379> get key1 //查看被替换后的字符串
"hexxe,world!"
set user:1{name:zhuzqc,age:123} //设置一个 user:1 对象,其 value 使用一个 json 字符串来保存
127.0.0.1:6379> mset user:1:name zhuzqc user:1:age 123 //同时为 user 对象设置 key为 name 和 age,并设置value
OK
127.0.0.1:6379> mget user:1:name user:1:age //通过 user 对象的 key,获取对应的 value
1) "zhuzqc"
2) "123"
127.0.0.1:6379> getset db redis //先 get 后 set,若没有值则返回 nil
(nil)
127.0.0.1:6379> get db //上述命令中已 set 了值
"redis"
127.0.0.1:6379> getset db mysql //同理先 get 到 db 的 value
"redis"
127.0.0.1:6379> get db //再重新 set db 的 value
"mysql"
3.3小结
本节讲解的是 Redis 中关于 String 类型数据类型的基本命令以及进阶用法,主要包括:
计数器(自增,设置步长)
如:某网站的浏览量统计
uid:1234:views:0 incr views //用户id、浏览量、浏览量自增
对象存储
如:过期时间、是否存在(分布式锁)
批量操作
如:同时创建多个 key-value、先设置 key 再设置 value
四、Redis 使用场景(拓展)
4.1Redis 基本事务操作
前提:Redis 单条命令保证原子性,但是 Redis 的事务不保证原子性。
比如在关系型数据库 MySQL 中,事务是具有原子性的,所有的命令都是一起成功或者失败。
Redis 事务的本质:
一组命令一起执行的集合(事务不保证原子性);
一个事务中的所有命令都会按照顺序执行;
其它3大特性:一次性、顺序性和排他性;
Redis 事务没有隔离级别的概念,所有命令只有发起执行时才会被执行(exec);
Redis 的执行过程:
开启事务(multi);
命令入队(按照顺序执行);
执行事务(exec)。
基本操作过程如下:
127.0.0.1:6379> multi #redis开启事务
OK
127.0.0.1:6379(TX)> FLUSHDB #命令开始入队
QUEUED
127.0.0.1:6379(TX)> keys *
QUEUED
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec #执行事务,上述命令开始按顺序执行并给出展示执行结果
1) OK
2) (empty array)
3) OK
4) OK
5) "v2"
编译型异常(代码有问题或者命令有错):事务中所有的命令都不会被执行;
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> getset k3 v33 #正确的 getset 语句
QUEUED
127.0.0.1:6379(TX)> getset k3 #错误的语句:编译时(未执行)发生错误
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> exec #事务中所有的命令都不会执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> INCR k1 #对字符串的 value 使用自增,语法不报错
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> exec #执行事务后,只有错的命令未被执行,其余命令都被执行了
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "v3"
4.2Redis 实现乐观锁
悲观锁
简单来说,就是什么时候都会出问题,无论做什么都会加锁!
乐观锁
很乐观,认为无论什么时候都不会出问题,所以不会上锁!
在数据进行更新的期间,会对数据进行判断,期间这个数据是否被修改(如 mysql 中的 version)。
步骤一:获取 version;
步骤二:更新的时候比较 version。
Redis 监视(watch)测试
正常步骤执行的过程:
127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set cost 0
OK
127.0.0.1:6379> watch money #监视 money 对象
OK
127.0.0.1:6379> multi #开启事务,数据正常变动
OK
127.0.0.1:6379(TX)> DECRBY money 28
QUEUED
127.0.0.1:6379(TX)> INCRBY cost 28
QUEUED
127.0.0.1:6379(TX)> EXEC #执行后得到正常的数据
1) (integer) 972
2) (integer) 28
多线程情况下对值进行更改:
127.0.0.1:6379> watch money #使用 watch 进行乐观锁操作
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 100 #另一个线程操作
QUEUED
127.0.0.1:6379(TX)> INCRBY money 100
QUEUED
127.0.0.1:6379(TX)> exec #执行失败
(nil)
######################################### 解决办法 ##########################################
127.0.0.1:6379> unwatch #先解锁
OK
127.0.0.1:6379> watch money #再次监视,获取最新的值
OK
127.0.0.1:6379> multi #启用事务
OK
127.0.0.1:6379(TX)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY cost 10
QUEUED
127.0.0.1:6379(TX)> exec #执行成功
1) (integer) 480
2) (integer) 48
# 主节点可以读也可以写
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"
# 从节点可以获取到主节点的数据
127.0.0.1:6380> keys *
1) "k1"
127.0.0.1:6380> get k1
"v1"
# 从节点只允许读,不允许写
127.0.0.1:6380> set k2 v2
(error) READONLY You can't write against a read only replica.
# 主节点宕机后,从节点仍然可以获取到主节点数据
127.0.0.1:6379> shutdown
127.0.0.1:6380> get key2
"shutdown"
我们都晓得java实现线程2种方式,一个是继承Thread,另一个是实现Runnable。
模拟窗口买票,第一例子继承thread,代码如下
package thread;
public class ThreadTest {
public static void main(String[] args) {
Thread1 t1 = new Thread1(
#include<iostream>
using namespace std;
//辅助函数,交换两数之值
template<class T>
void mySwap(T &x, T &y){
T temp = x;
x = y;
y = temp;
}
const int size = 10;
//一、用直接插入排
对日期类型的数据进行序列化和反序列化时,需要考虑如下问题:
1. 序列化时,Date对象序列化的字符串日期格式如何
2. 反序列化时,把日期字符串序列化为Date对象,也需要考虑日期格式问题
3. Date A -> str -> Date B,A和B对象是否equals
默认序列化和反序列化
import com
1. DStream的类说明文档:
/**
* A Discretized Stream (DStream), the basic abstraction in Spark Streaming, is a continuous
* sequence of RDDs (of the same type) representing a continuous st
ReplayingDecoder是FrameDecoder的子类,不熟悉FrameDecoder的,可以先看看
http://bylijinnan.iteye.com/blog/1982618
API说,ReplayingDecoder简化了操作,比如:
FrameDecoder在decode时,需要判断数据是否接收完全:
public class IntegerH
1.js中用正则表达式 过滤特殊字符, 校验所有输入域是否含有特殊符号function stripscript(s) { var pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]"
经常在写shell脚本时,会碰到要以另外一个用户来执行相关命令,其方法简单记下:
1、执行单个命令:su - user -c "command"
如:下面命令是以test用户在/data目录下创建test123目录
[root@slave19 /data]# su - test -c "mkdir /data/test123"