redis学习

1.redis 总共有5 种数据类型

string, hash, list,set ,sorted set

2.数据类型操作命令

对应的每个数据类型的操作命令差不多,略有不同。详细见redis 实战

Stringhashlistsetsorted set
sethset lsetsaddzadd
setnxhsetnxrpushsrandmemberzincrby
setexhexistslinsertsismemberzrank
setrangehdellpushscardzcount
msethmsetllensmovezrevrank
msetnxhvalsltrimsunionstorezrevrange
gethgetlpopsunionzrem
getsethgetallrpoplpushsremzranggebyscore
getrangehmgetrpopspopzcard
mgethkeyslindexsdiffzscore
incrhincrbylremsdiffsctorezrange
incrbyhlenlrangesmembers 
decr    
append    
strlen    

3.适用场景

每个数据类型的适用场景,可能有不对的地方,

可能不全面或者有些问题,只是我目前认为的场景:
String--存储简单的数据,显示形式为key-value。
Hash --这个比较常用,可以用来存储对象,

在这方面比string 好用一些。
举个例子对比一下,比如存储用户信息

 stringhash
设置格式set key valueset hashname key value
单个属性值设置set user:1:name zhangsan
set user:1:age 20
set user:1:sorce 80
hset user:1 name zhangsan
hset user:1 age 20
hset user:1 score 80
多个属性值设置mset user:1:name zhangsan
user:1:age 20 user:1:score 80
hmset user:1 name zhangsan
age 20 score 80
获取值mget user:1:name user:1:age
user:1:score
hmget user:1 name age score

list 在redis 中可以用来做数据结构中的栈和队列,

从命令行就能看出push pop 等。
set 的应用场景在于数学中的集合相关操作,

如两个集合中的交集差集并集补集。比
如目前应用中qq 的的好友推荐功能。
sorted set 是在set 上的扩展,改进的地方是

set 的基础上增加了顺序,用户可以自定义排列
顺序,方便进行数据的过滤操作。

比如上面的成绩可以进行过滤分数在80 - 90 之间排序
输出,看看班级分数最高的是哪一个同学等等。


4.列出除了5 种数据类型外的几个常用命令

--->keys * 查看当前数据库中所有的key
--->exists user:1 查看user:1 键是否存在

1 表示存在0 表示不存在
--->del user:1 删除user:1 键
--->expire/ttl 设置某个键对应的过期时间,单位秒,

ttl 是查看数据是否过期
--->move 移动某个key 从当前数据库到其他数据库,

redis 默认提供16 个数据库,下
标从0 - 15

--->persist 取消过期,即让expire 失效
--->randomkey 随机返回某个key
--->rename 对key 进行重命名
--->type mylist1 返回mylist1 对应的数据类型

(string or list or hash or set or sorted set)
服务器端相关命令
--->ping 能连接服务起端,返回PANG
--->echo 原样输出字符
--->select 用于切换数据库0 -15 ,比如select 6
--->quit 退出客户端
--->dbsize 当前数据库中key 的数量
--->info 一些信息,集群的时候会有个role 参数,对应值为master 和slave
--->flushdb 清空当前数据库
--->flushall 删除所有数据库中的key 和value

5.安全方面设置
在redis.conf 中添加requirepass 123456 

代表这设置密码为123456.建议密码设置的
复杂些。这里只是简单举例
客户端连接时必须添加登陆命令,否则能连接服务器端,

不能执行任何查询,删除,
更新,插入命令。唯一能执行的命令为auth 123456,

然后验证后方可进行操作


6.主从复制
在从服务器中配置文件中添加命令slaveof 服务器ip 地址6379
注意,如果服务器中设置了验证密码,

必须加入masterauth 123456,否则不能完成主
从复制,(找了好长时间才发现这个问题)
7.事务控制
redis 的事务控制比较简单,目前不支持的情况:
执行插入
执行删除
出错
然后回滚不能完全回滚,第一次执行插入的操作已经入库
语法:
multi

各种操作命令
exec
如果中途想取消事务操作,命令为discard

8.发布订阅消息
session1:subscribe tv1
session2:subscribe tv1 tv2
publish tv1 “hello,i am comming”
解释:客户端1 订阅tv1 频道,客户端2 订阅tv1 tv2 频道
服务器端给tv1 频道发布消息则,

订阅tv1 频道的客户端都能收到对应的
message 信息

9.pipeline 批量发送请求,能提高点效率
10.虚拟内存技术
配置文件中添加参数vm-enabled yes ,

类似于window 系统中的虚拟内存,主要是提供一个中转的空间,

方便内存空间不足时候进行临时存放与夜文件等的交换。但是有人不
建议使用,因为生产环境的服务器内存本身已经够用,

多一些配置,基本上起不到太大的作
用,还增加了额外的复杂度。
11.集群
目前还没有完美的技术方案,

官方说在redis 3.0 中会实现集群功能,目前3.0 还在
测试阶段,生产环境不建议使用。
另外有网友使用keepalived 实现主从监视,

这个后面再研究下。

12.关于持久化技术
redis 有两种持久化命令
Snapshotting 快照模式,这个是默认的,

文件是二进制的,用户无法查看,另外里面
存放的是操作的数据,这种方式容易丢失最后一次数据,

所以建议采用另外的方式
aof --- append only file 是文件存储,

主要是存储的操作过程,而不单单是存储的数据。
缺点是随着操作的增加文件也会越来越大。

可以使用压缩命令,对一些命令执行压缩。
bgrewriteof,即可在后台开一个字线程执行压缩操作,

效果还是挺理想的。

13.Java 中的几个小例子

Redis-string
public class User_String {
public static Jedis jj = null;
public static void main(String[] args) {
init();
insertUser();
}
public static void insertUser(){
jj.set("user:1:uid", "1");
jj.set("user:1:username", "张三丰");
jj.set("user:1:age", "128");
jj.set("user:1:score", "2500");
/**数据库中的结构显示
* keys *
1) "user:1:username"
2) "user:1:score"
3) "user:1:uid"
4) "user:1:age"
*/
}
public static void init(){
jj = new Jedis("192.168.182.129", 6379);
jj.auth("123456");
}
}

Redis-hash
//新浪微博的存储数据类型
// hash key :user id
// fields: friends id
// value: add time
//如: jj.hset("user:0001", "0002,0003,0004", new Date());
public class Users_Hash {
public static Jedis jj = null;
public static String TEST_USER_ID = "user:99";
public static void main(String[] args) {
init();
addUsers();
addOneUser();//add
getUserById(TEST_USER_ID);//select
updateUserById(TEST_USER_ID);//update;
// deleteUserById(TEST_USER_ID);//delete
// existsUserById(TEST_USER_ID);
// clearAllDatas(); //慎用
// zipAof();
getAllUsers(); //selectAll
}
private static void getAllUsers() {
System.out.println("---------------------------------------------
---------------------");
Set<String> users = jj.keys("user:*");
Iterator<String> it = users.iterator();
while (it.hasNext()) {
String str = it.next();
getUserById(str);
}
}
private static void zipAof() {
jj.bgrewriteaof();//后台重启线程,对aof文件执行压缩
}
private static void clearAllDatas(){
jj.flushDB(); //删除本数据库的所有数据
// jj.flushAll(); //删除本服务器中所有服务器中的所有数据
}
//判断用戶是否存在
private static boolean existsUserById(String userId) {
return jj.exists(userId);
}
private static void deleteUserById(String userId) {
getUserById(userId);
jj.del(userId);
/* jj.hdel(TEST_USER_ID, "uid"); //每個字段都刪除才算對這個hash刪
除
jj.hdel(TEST_USER_ID, "username");
jj.hdel(TEST_USER_ID, "sex");
jj.hdel(TEST_USER_ID, "age");
jj.hdel(TEST_USER_ID, "score");*/
getUserById(userId);
}
private static void updateUserById(String userId){
Map<String,String> userInfos = jj.hgetAll(userId);
userInfos.put("username", "呂布");
jj.hmset(TEST_USER_ID, userInfos);
getUserById(TEST_USER_ID);
}
private static void getUserById(String userId) {
Map<String,String> maps = jj.hgetAll(userId);
shows(maps);
}
private static void shows(Map<String, String> maps) {
String result = " 编号: "+maps.get("uid")+" | 姓名:
"+maps.get("username")+"|年龄:"+maps.get("age")
+" | 性别: "+maps.get("sex")+" | 武力值:
"+maps.get("score");
System.out.println(result);
}
public static void addOneUser(){
Map<String,String> userInfos = new HashMap<String,String>();
userInfos.put("uid", "99");
userInfos.put("username", "宇文化及");
userInfos.put("age", "5000");
userInfos.put("sex","未知");
userInfos.put("score","1000");
jj.hmset(TEST_USER_ID, userInfos);
// jj.hsetnx(key, field, value);//支持排重验证
}
private static void addUsers() {
//存的hash数据类型
Map<String,String> userInfos = new HashMap<String,String>();
userInfos.put("uid", "1");
userInfos.put("username", "刘德华");
userInfos.put("age", "50");
userInfos.put("sex","男");
userInfos.put("score","90.5");
jj.hmset("user:1", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "2");
userInfos.put("username", "张学友");
userInfos.put("age", "52");
userInfos.put("sex","男");
userInfos.put("score","88.1");
jj.hmset("user:2", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "3");
userInfos.put("username", "黎明");
userInfos.put("age", "49");
userInfos.put("sex","男");
userInfos.put("score","68.3");
jj.hmset("user:3", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "4");
userInfos.put("username", "郭富城");
userInfos.put("age", "54");
userInfos.put("sex","男");
userInfos.put("score","82.7");
jj.hmset("user:4", userInfos);
}
public static void init(){
jj = new Jedis("192.168.182.129", 6379);
jj.auth("123456");
}
}

Redis-list
public class Users_List {
public static Jedis jj = null;
public static String TEST_USER_ID = "user:4";
public static void main(String[] args) {
init();
//一般在用戶添加刪除的時候对应维护这个list列表,记录库中存在的
用户数量
jj.flushDB();
addUsers();
List<String> ls = jj.lrange("userNumbers", 0, -1);
System.out.println(ls.size());
for(String s : ls){
System.out.println(s);
}
deleteUserById(TEST_USER_ID);//delete
List<String> ls_new = jj.lrange("userNumbers", 0, -1);
System.out.println(ls_new.size());
for(String s : ls_new){
System.out.println(s);
}
//例子2:记录最近发表的关于888的5000条评论
//直接用redis语句了,不写代码了
//1.lpush latest.comments:888 评论1
// lpush latest.comments:888 评论2
// lpush latest.comments:888 评论3
// lpush latest.comments:888 评论4
// lpush latest.comments:888 评论5
// ......... ..........
// lpush latest.comments:888 评论99999
// lpush latest.comments:888 评论100000
// lpush latest.comments:888 评论100001
// lpush latest.comments:888 评论100002
// lpush latest.comments:888 评论100003
//假设redis库里面关于888的评论有100003条,我们现在要获取前5000
条的id
// ltrim latest.comments:888 0 4999
// lrange latest.comments:888 0 -1
}

private static void deleteUserById(String userId) {
jj.del(userId);
jj.lrem("userNumbers", 1, "1-刘德华");
}
private static void addUsers() {
//存的hash数据类型
Map<String,String> userInfos = new HashMap<String,String>();
userInfos.put("uid", "1");
userInfos.put("username", "刘德华");
userInfos.put("age", "50");
userInfos.put("sex","男");
userInfos.put("score","90.5");
jj.hmset("user:1", userInfos);
jj.rpush("userNumbers", "1-刘德华");
userInfos = new HashMap<String,String>();
userInfos.put("uid", "2");
userInfos.put("username", "张学友");
userInfos.put("age", "52");
userInfos.put("sex","男");
userInfos.put("score","88.1");
jj.hmset("user:2", userInfos);
jj.rpush("userNumbers", "2-张学友");
userInfos = new HashMap<String,String>();
userInfos.put("uid", "3");
userInfos.put("username", "黎明");
userInfos.put("age", "49");
userInfos.put("sex","男");
userInfos.put("score","68.3");
jj.hmset("user:3", userInfos);
jj.rpush("userNumbers", "3-黎明");
userInfos = new HashMap<String,String>();
userInfos.put("uid", "4");
userInfos.put("username", "郭富城");
userInfos.put("age", "54");
userInfos.put("sex","男");
userInfos.put("score","82.7");
jj.hmset("user:4", userInfos);
jj.rpush("userNumbers", "4-郭富城");
}
public static void init(){
jj = new Jedis("192.168.182.129", 6379);
jj.auth("123456");
}
}

Redis-set
public class Users_Set {
public static Jedis jj = null;
public static void main(String[] args) {
init();
jj.flushDB();
addUsers();//添加8个测试用户
//设置好友关系
rosterRelations();
//好友相关操作
doRosterShow();
}

private static void doRosterShow() {
System.out.print(" 用户1 的好友个数:
"+jj.scard("user:1:roster"));
Set<String> user1Rosters = jj.smembers("user:1:roster");
System.out.println(" | 用户1好友详细信息:"+user1Rosters);
showIteratorInfos(user1Rosters);
System.out.print(" 用户2 的好友个数:
"+jj.scard("user:2:roster"));
Set<String> user2Rosters = jj.smembers("user:2:roster");
System.out.println(" | 用户2好友详细信息:"+user2Rosters);
showIteratorInfos(user2Rosters);
//差集,用户1的好友[user:4, user:3, user:2],用户2的好友[user:3,
user:5, user:8, user:7],结果为[user:4, user:2]
Set<String> user3Rosters =
jj.sdiff("user:1:roster","user:2:roster");
System.out.println("对用户2好友推荐,您可能认识:");
showIteratorInfos(user3Rosters);
//交集,用户1的好友[user:4, user:3, user:2],用户2的好友[user:3,
user:5, user:8, user:7],结果为[user:3]
Set<String> user4Rosters =
jj.sinter("user:1:roster","user:2:roster");
System.out.println("您和用户2的共同好友为:");
showIteratorInfos(user4Rosters);
//并集,用户1的好友[user:4, user:3, user:2],用户2的好友[user:3,
user:5, user:8, user:7],结果为[user:4, user:3, user:5, user:2, user:8,
user:7]
Set<String> user5Rosters =
jj.sunion("user:1:roster","user:2:roster");
System.out.println("您和用户2的所有好友列表为:");
showIteratorInfos(user5Rosters);
}
private static void showIteratorInfos(Set<String> user2Rosters) {
Iterator<String> it2 = user2Rosters.iterator();
while(it2.hasNext()){
String str = it2.next();
getUserById(str);
}
System.out.println("---------------------------------------------
-------------");
}
private static void getUserById(String userId) {
Map<String,String> maps = jj.hgetAll(userId);
shows(maps);
}
private static void shows(Map<String, String> maps) {
String result = " 编号: "+maps.get("uid")+" | 姓名:
"+maps.get("username")+"|年龄:"+maps.get("age")
+" | 性别: "+maps.get("sex")+" | 武力值:
"+maps.get("score");
System.out.println(result);
}
private static void rosterRelations() {
jj.sadd("user:1:roster", "user:2","user:3","user:4");//1的好友
为2 3 4
jj.sadd("user:2:roster", "user:1",
"user:3","user:5","user:7","user:8");//2的好友为1 3 5 7 8
}
private static void addUsers() {
//存的hash数据类型
Map<String,String> userInfos = new HashMap<String,String>();
userInfos.put("uid", "1");
userInfos.put("username", "刘德华");
userInfos.put("age", "50");
userInfos.put("sex","男");
userInfos.put("score","90.5");
jj.hmset("user:1", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "2");
userInfos.put("username", "张学友");
userInfos.put("age", "52");
userInfos.put("sex","男");
userInfos.put("score","88.1");
jj.hmset("user:2", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "3");
userInfos.put("username", "黎明");
userInfos.put("age", "49");
userInfos.put("sex","男");
userInfos.put("score","68.3");
jj.hmset("user:3", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "4");
userInfos.put("username", "郭富城");
userInfos.put("age", "54");
userInfos.put("sex","男");
userInfos.put("score","82.7");
jj.hmset("user:4", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "5");
userInfos.put("username", "小鱼儿");
userInfos.put("age", "66");
userInfos.put("sex","女");
userInfos.put("score","182.7");
jj.hmset("user:5", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "6");
userInfos.put("username", "花无缺");
userInfos.put("age", "44");
userInfos.put("sex","男");
userInfos.put("score","200.8");
jj.hmset("user:6", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "7");
userInfos.put("username", "吕布");
userInfos.put("age", "2899");
userInfos.put("sex","男");
userInfos.put("score","2999");
jj.hmset("user:7", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "8");
userInfos.put("username", "貂蝉");
userInfos.put("age", "24");
userInfos.put("sex","女");
userInfos.put("score","8.6");
jj.hmset("user:8", userInfos);
}
public static void init(){
jj = new Jedis("192.168.182.129", 6379);
jj.auth("123456");
}
}
Redis-sorted set
public class Users_ZSet {
public static Jedis jj = null;
public static void main(String[] args) {
init();
jj.flushDB();
addUsers();
userInClasses();
System.out.println(jj.zrank("class:1:height","user:1")); // 结
果为6,说明user:1在班级里面是第七的高个子
Set<String> ss = jj.zrange("class:1:height", 0, -1);
Iterator<String> it = ss.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("------------------------飞行员入学考试,身
高限制");
Set<String> ss1 = jj.zrangeByScore("class:1:height", 165, 175);
Iterator<String> it1 = ss1.iterator();
while(it1.hasNext()){
String s = it1.next();
System.out.println(s);
}
}
private static void userInClasses() {
jj.zadd("class:1:height", 178, "user:1");
jj.zadd("class:1:height", 167, "user:2");
jj.zadd("class:1:height", 183, "user:3");
jj.zadd("class:1:height", 142, "user:4");
jj.zadd("class:1:height", 155, "user:5");
jj.zadd("class:1:height", 163, "user:6");
jj.zadd("class:1:height", 158, "user:7");
jj.zadd("class:1:height", 171, "user:8");
}
private static void addUsers() {
//存的hash数据类型
Map<String,String> userInfos = new HashMap<String,String>();
userInfos.put("uid", "1");
userInfos.put("username", "刘德华");
userInfos.put("age", "50");
userInfos.put("sex","男");
userInfos.put("score","90.5");
jj.hmset("user:1", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "2");
userInfos.put("username", "张学友");
userInfos.put("age", "52");
userInfos.put("sex","男");
userInfos.put("score","88.1");
jj.hmset("user:2", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "3");
userInfos.put("username", "黎明");
userInfos.put("age", "49");
userInfos.put("sex","男");
userInfos.put("score","68.3");
jj.hmset("user:3", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "4");
userInfos.put("username", "郭富城");
userInfos.put("age", "54");
userInfos.put("sex","男");
userInfos.put("score","82.7");
jj.hmset("user:4", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "5");
userInfos.put("username", "小鱼儿");
userInfos.put("age", "66");
userInfos.put("sex","女");
userInfos.put("score","182.7");
jj.hmset("user:5", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "6");
userInfos.put("username", "花无缺");
userInfos.put("age", "44");
userInfos.put("sex","男");
userInfos.put("score","200.8");
jj.hmset("user:6", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "7");
userInfos.put("username", "吕布");
userInfos.put("age", "2899");
userInfos.put("sex","男");
userInfos.put("score","2999");
jj.hmset("user:7", userInfos);
userInfos = new HashMap<String,String>();
userInfos.put("uid", "8");
userInfos.put("username", "貂蝉");
userInfos.put("age", "24");
userInfos.put("sex","女");
userInfos.put("score","8.6");
jj.hmset("user:8", userInfos);
}
public static void init(){
jj = new Jedis("192.168.182.129", 6379);
jj.auth("123456");
}
}

Redis-mysql
public class Integration {
public static Jedis jj;
public static String driver;
public static String url;
public static String user;
public static String password;
public static void main(String[] args) {
long starttime = System.currentTimeMillis();
init();
// 查询用户张三的好友列表
// 用户张三的key为1
String userkey = "1";
// 查询redis
String vals = jj.hget("user:"+userkey, "rosterids");
List<Integer> ls = new ArrayList<Integer>();
if (null == vals) {
// redis没有对应的key,查询数据库
ls = getRosterIds(userkey);
jj.hset("user:"+userkey, "rosterids",
ls.toString().replace("[", "")
.replace("]", ""));
vals = jj.hget("user:"+userkey, "rosterids");
}
System.out.println("执行redis缓存");
if (ls.size() > 0)
getRosterInfos(ls.toString().replace("[", "").replace("]",
""));
else
getRosterInfos(vals);
long endtime = System.currentTimeMillis();
System.out.println(endtime-starttime+"ms");
}
public static void init() {
jj = new Jedis("127.0.0.1", 6379);
// 驱动程序名
driver = "com.mysql.jdbc.Driver";
// URL指向要访问的数据库名scutcs
url = "jdbc:mysql://14.38.223.29:3306/redis_db_test";
// MySQL配置时的用户名
user = "admin";
// MySQL配置时的密码
password = "12qwert8@#!";
}
public static List<Integer> getRosterIds(String userkey) {
System.out.println("执行数据库查询");
List<Integer> ls = new ArrayList<Integer>();
try {
// 加载驱动程序
Class.forName(driver);
// 连续数据库
Connection conn = DriverManager.getConnection(url, user,
password);
if (!conn.isClosed())
System.out.println("Succeeded connecting to the
Database!");
// statement用来执行SQL语句
Statement statement = conn.createStatement();
// 要执行的SQL语句
String sql = "select rosterId from t_rosters where userid =
"
+ userkey;
// 结果集
ResultSet rs = statement.executeQuery(sql);
while (rs.next()) {
// 输出结果
ls.add(rs.getInt("rosterid"));
}
rs.close();
conn.close();
} catch (ClassNotFoundException e) {
System.out.println("Sorry,can`t find the Driver!");
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return ls;
}
public static void getRosterInfos(String ids) {
try {
// 加载驱动程序
Class.forName(driver);
// 连续数据库
Connection conn = DriverManager.getConnection(url, user,
password);
if (!conn.isClosed())
System.out.println("Succeeded connecting to the
Database!");
// statement用来执行SQL语句
Statement statement = conn.createStatement();
// 要执行的SQL语句
String sql = "select * from t_userinfo where uid in (" + ids
+ ")";
// 结果集
ResultSet rs = statement.executeQuery(sql);
System.out.println("-------------------------------------------")
;
System.out.println("执行结果如下所示:");
System.out.println("-------------------------------------------")
;
System.out.println(" 学号" + "\t" + " 姓名" + "\t" + "年龄"
+ "\t" + "性别"
+ "\t" + "生日");
System.out.println("-------------------------------------------")
;
String name = null;
while (rs.next()) {
// 选择sname这列数据
name = rs.getString("username");
// 首先使用ISO-8859-1字符集将name解码为字节序列并将结果
存储新的字节数组中。
// 然后使用GB2312字符集解码指定的字节数组
name = new String(name.getBytes("utf-8"), "utf-8");
// 输出结果
System.out.println(rs.getString("uid") + "\t" + name +
"\t"
+ rs.getInt("age") + "\t" + rs.getInt("sex") + "\t"
+ rs.getDate("birth"));
}
rs.close();
conn.close();
} catch (ClassNotFoundException e) {
System.out.println("Sorry,can`t find the Driver!");
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值