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"
参考:http://blog.csdn.net/qingfeilee/article/details/7052736
org.hibernate.NonUniqueResultException: query did not return a unique result: 2
在项目中出现了org.hiber
由Oracle通信技术部门主导的演示项目并没有在本月较早前法国南斯举行的行业集团TM论坛大会中获得嘉奖。但是,Oracle通信官员解雇致力于打造一个支持零干预分配和编制功能的网络即服务(NaaS)平台,帮助企业以更灵活和更适合云的方式实现通信服务提供商(CSP)的连接产品。这个Oracle主导的项目属于TM Forum Live!活动上展示的Catalyst计划的19个项目之一。Catalyst计
Spring MVC提供了非常方便的文件上传功能。
1,配置Spring支持文件上传:
DispatcherServlet本身并不知道如何处理multipart的表单数据,需要一个multipart解析器把POST请求的multipart数据中抽取出来,这样DispatcherServlet就能将其传递给我们的控制器了。为了在Spring中注册multipart解析器,需要声明一个实现了Mul
the CollabNet user information center http://help.collab.net/
How do I create a new Wiki page?
A CollabNet TeamForge project can have any number of Wiki pages. All Wiki pages are linked, and
package beautyOfCoding;
import java.util.Arrays;
import java.util.Random;
public class MaxSubArraySum2 {
/**
* 编程之美 子数组之和的最大值(二维)
*/
private static final int ROW = 5;
private stat
示例程序,swap_1和swap_2都是错误的,推理从1开始推到2,2没完成,推到3就完成了
# include <stdio.h>
void swap_1(int, int);
void swap_2(int *, int *);
void swap_3(int *, int *);
int main(void)
{
int a = 3;
int b =
同步工具类包括信号量(Semaphore)、栅栏(barrier)、闭锁(CountDownLatch)
闭锁(CountDownLatch)
public class RunMain {
public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
fin
不止一次,看到很多讲技术的文章里面出现过这个词语。今天终于弄懂了——通过朋友给的浏览软件,上了wiki。
我再一次感到,没有辞典能像WiKi一样,给出这样体贴人心、一清二楚的解释了。为了表达我对WiKi的喜爱,只好在此一一中英对照,给大家上次课。
In computer science, bleeding edge is a term that