初识Redis

文章目录


第1关:Redis中的数据结构

编程要求

根据提示,打开命令行,启动 Redis 客户端并创建一些值:

使用默认配置后台启动 Redis 服务器

启动 Redis 客户端 redis-cli

设置字符串

键为 hello

值为 redis

设置列表,键为 educoder-list

从列表左侧推入元素 hello

从列表右侧推入元素 educoder

从列表右侧推入元素 bye

从列表右侧弹出一个元素

设置集合,键为 educoder-set

添加元素 c

添加元素 python

添加元素 redis

删除元素 c

设置哈希,键为 educoder-hash

添加键:python,值为:language

添加键:ruby,值为:language

添加键: redis,值为:database

删除键 ruby

设置有序列表,键为 educoder-zset

添加成员 jack,分值为 200

添加成员 rose,分值为 400

添加成员 lee,分值为 100

测试说明

我会对你编写的代码进行测试:

测试输入:无;

预期输出:

redis

{'python': 'language', 'redis': 'database'}

['hello', 'educoder']

set(['python', 'redis'])

[('lee', 100.0), ('jack', 200.0), ('rose', 400.0)]

这是整体的第一关代码,在这篇文章是分开的代码点击此处跳转至该文章

代码示例如下(第一关的代码是按行粘贴,在命令行输入的):

c 复制代码
redis-cli
set hello redis
lpush educoder-list hello
rpush educoder-list educoder
rpush educoder-list bye
rpop educoder-list
sadd educoder-set c
sadd educoder-set python redis
del educoder-set c
hset educoder-hash python language
hset educoder-hash ruby language
hset educoder-hash redis database
hdel educoder-hash ruby
zadd educoder-zset 200 jack
zadd educoder-zset 400 rose
zadd educoder-zset 100 lee
sadd educoder-set python redis

第2关:使用 Python 与 Redis 交互

编程要求

根据提示,在右侧Begin-End区域补充代码,实现使用 Python 编写程序与 Redis 交互:

使用方法2创建客户端r1连接到 Redis

设置下表中的两个字符串键:

键 值

test1 hello

test2 Redis

测试说明

我会对你编写的代码进行测试:

获取test1和test2键的值。

测试输入:无

测试输出:

hello

Redis

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import redis

def write_redis():
    #********* Begin *********#
    pool = redis.ConnectionPool(host='127.0.0.1', port=6379, decode_responses=True)
    r = redis.Redis(connection_pool=pool)
    r.set("test1", "hello")
    r.set("test2", "Redis")
    #********* End *********#

第3关:使用Python+Redis实现文章投票网站后端功能编程要求

根据提示,在右侧Begin-End区域补充代码,完成简化版文章投票网站的后端处理逻辑:

在 article_vote() 函数中:

该方法作用是:对文章投票

参数说明:

r:Redis 客户端

user_id:投票用户

article_id:被投票文章

已提供一周前 Unix 时间戳,存放在变量 cutoff

当满足以下条件时,为文章投一票:

该文章发布不超过一周

该用户没有为该文章投过票

在 post_article() 函数中:

该方法作用是:创建文章

参数说明:

r:Redis 客户端

user:发布用户

title:文章标题

link:文章链接

已提供:

article_id,新文章 ID

voted,新文章已投票用户名单存储键名

article,新文章详细信息存储键名

now,文章创建时间

按照 ID 递增的顺序依次创建文章

保证发布文章的用户不能给自己的文章投票

文章在发布一周后删除已投票用户名单

存储文章详细信息到 Redis 中,包括字段:

文章标题

文章链接

发布用户

存储文章的发布时间和初始投票数

初始投票数为 1

在 get_articles() 函数中:

该方法作用是:对文章进行排序

参数说明:

r:Redis 客户端

start:从排序为 start 的文章开始获取

end:到排序为 end 的文章结束获取

order:排序方式,分为两种:

time:按时间排序

score:按投票数排序

已提供文章信息空列表,articles

实现按时间/投票数排序

将排序后的文章及其全部信息组成一个列表:

按照不同排序规则取出排序在参数提供的区间范围内的文章

及每篇文章的全部信息,包括文章 ID

测试说明

我会对你编写的代码进行测试:

测试输入:无;

预期输出:

We posted a new article with id: 1

Its HASH looks like:

{'poster': 'username', 'link': 'http://www.google.com', 'title': 'A title'}

We voted for the article, it now has votes: 2

The currently highest-scoring articles are:

[{'id': '1'}]

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import time

ONE_WEEK_IN_SECONDS = 7 * 24 * 60 * 60

def article_vote(r, user_id, article_id):
    cutoff = time.time() - ONE_WEEK_IN_SECONDS

    # 请在下面完成要求的功能
    #********* Begin *********#
    if r.zscore('time', article_id) < cutoff:
        return
    if r.sadd('voted:' + article_id, user_id):
        r.zincrby('score', article_id, 1)

    #********* End *********#

def post_article(r, user, title, link):
    article_id = str(r.incr('article'))

    voted = 'voted:' + article_id
    r.sadd(voted, user)
    r.expire(voted, ONE_WEEK_IN_SECONDS)
    now = time.time()
    article = 'article:' + article_id
    # 请在下面完成要求的功能
    #********* Begin *********#
    r.hmset(article, {
        'title': title,
        'link': link,
        'poster': user,
    })
    r.zadd('score', article_id, 1)
    r.zadd('time', article_id, now)
  
    #********* End *********#

    return article_id

def get_articles(r, start, end, order='score'):
    ids = r.zrevrange(order, start, end)
    articles = []

    # 请在下面完成要求的功能
    #********* Begin *********#
    for id in ids:
        article_data = r.hgetall(id)
        article_data['id'] = id
        articles.append(article_data)


    #********* End *********#

    return articles

第4关:字符串、列表与集合

编程要求

根据提示,在右侧Begin-End区域补充代码,完成任务分配的后端处理逻辑:

在 task_empty() 方法中:

从 Redis 中获取列表 task_list 的长度,判断是否为 0

若为 0,则返回 True

若不为 0,则返回 False

在 get_task() 方法中:

从列表 task_list 的最右侧弹出一个元素,赋值给 task

将 task 的值设置到 Redis 的字符串键 current_task 中

在 get_unallocated_staff() 方法中:

从集合 unallocated_staff 中随机返回一个元素,赋值给 staff

将上面的 staff 从集合 unallocated_staff 移动到集合 allocated_staff 中

返回(return)staff 的值

在 allocate_task(staff) 方法中:

将参数 staff 的值追加到 Redis 字符串键 current_task 的尾部,中间以 : 间隔

将追加后的字符串键 current_task 从左侧推入列表 task_queue

将字符串键 current_task 的值设置为 "None"

测试说明

我会对你编写的代码进行测试:

测试输入:

task_1 task_2 task_3 task_4 task_5

staff_1 staff_2 staff_3 staff_4 staff_5

预期输出:

Init task list: ['task_1', 'task_2', 'task_3', 'task_4', 'task_5']

Init staff list: set(['staff_4', 'staff_5', 'staff_1', 'staff_2', 'staff_3'])

Cur task list is empty: False

Get new task: task_5

Current staff is allocated: True

Current staff is unallocated: False

Current task is: None

Allocated all tasks

Task queue length: 5

Task list is empty: True

Allocated_staff: set(['staff_4', 'staff_5', 'staff_1', 'staff_2', 'staff_3'])

Unallocated_staff: set([])

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import redis

conn = redis.Redis()

def task_empty():
    # 请在下面完成判断任务列表是否为空
    #********* Begin *********#
    return int(conn.llen("task_list")) == 0
    #********* End *********#

def get_task():
    # 请在下面完成获取一个任务
    #********* Begin *********#
    task = conn.rpop("task_list")
    conn.set("current_task",task)

    #********* End *********#

def get_unallocated_staff():
    # 请在下面完成获取一个未分配的员工
    #********* Begin *********#
    staff=conn.srandmember("unallocated_staff")
    conn.smove("unallocated_staff","allocated_staff",staff)
    return staff
    #********* End *********#

def allocate_task(staff):
    # 请在下面完成分配任务
    #********* Begin *********#
    conn.append("current_task",':'+str(staff))
    conn.lpush("task_queue",conn.get("current_task"))
    conn.set("current_task","None")

    #********* End *********#

第5关:哈希与有序集合

编程要求

根据提示,在右侧Begin-End区域补充代码,完成带优先级的队列系统的后端处理逻辑:

在 set_task_info(task_id) 方法中:

使用参数 task_id 作为域,初始状态 "init" 作为值构成域-值对,存放在 task_status 哈希键中。

在 add_task_to_queue(task_id, priority) 方法中:

参数说明:

task_id 为任务 ID

priority 为任务优先级。

将分值(优先级)为 priority 的成员 task_id 存入有序集合 task_queue 中。

注意将参数 priority 转换为整型

调用 set_task_info() 方法,传入参数 task_id

在 get_task() 方法中:

新建变量 task_list_by_priority,值为:

使用 ZREVRANGE 命令按照分值(优先级)从大到小顺序返回有序集合 task_queue 的全部成员。

新建变量 current_task,值为:

task_list_by_priority 中的第一个元素(下标为 0)

将成员 current_task 从有序集合 task_queue 中移除

修改哈希 task_status 中的 current_task 域的值为 "processing"

返回(return)current_task 的值

测试说明

我会对你编写的代码进行测试:

测试输入:

1 2 3 4 5 6 7 8 9 10

2 4 9 1 0 5 8 6 7 3

预期输出:

Add new task: 1, priority: 2, status: init

Add new task: 2, priority: 4, status: init

Add new task: 3, priority: 9, status: init

Add new task: 4, priority: 1, status: init

Add new task: 5, priority: 0, status: init

Add new task: 6, priority: 5, status: init

Add new task: 7, priority: 8, status: init

Add new task: 8, priority: 6, status: init

Add new task: 9, priority: 7, status: init

Add new task: 10, priority: 3, status: init

Before: task list is: ['3', '7', '9', '8', '6', '2', '10', '1', '4', '5']

Get new task: 3

After: task list is: ['7', '9', '8', '6', '2', '10', '1', '4', '5']

Current task status: processing

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import redis

conn = redis.Redis()

# 初始化任务信息到 Redis 中
def set_task_info(task_id):
    # 请在下面完成要求的功能
    #********* Begin *********#
    conn.hset("task_status",task_id,"init")
    #********* End *********#

# 将任务添加至任务队列
def add_task_to_queue(task_id, priority):
    # 请在下面完成要求的功能
    #********* Begin *********#
    conn.zadd("task_queue",task_id,int(priority))
    set_task_info(task_id)
    #********* End *********#

# 从任务队列中取出优先级最高的任务
def get_task():
    # 请在下面完成要求的功能
    #********* Begin *********#
    task_list_by_priority=conn.zrevrange('task_queue',0,-1)
    current_task=task_list_by_priority[0]
    conn.zrem('task_queue',current_task)
    conn.hset("task_status",current_task,"processing")
    return current_task
    #********* End *********#

第6关:Redis基本事务与其他命令

编程要求

根据提示,在右侧Begin-End区域补充代码,完成网络约车的后端处理逻辑:

在 request_cab(user_id, priority) 方法中:

判断是否存在哈希键 request:info:用户ID 的 time 域:

提示:可使用 HEXISTS 命令

若存在,则直接 return

若不存在,做如下操作

使用事务提交下列命令:

将参数 user_id 从最左侧推入列表 cab:queue

使用 HMSET 命令设置哈希键 request:info:用户ID:

域 time,值为 time.time()

域 priority,值为参数 priority

将上述哈希键的过期时间设置为 10分钟

在 allocate() 方法中:

使用 SORT 命令对列表 cab:queue 排序,并将结果赋值给 cab_queue:

使用 BY 参数

参考键为哈希键 request:info:*,其中 * 为占位符

使用上述参考键中的 priority 域

使用 DESC 参数做倒序排序

取出 cab_queue 的第一个元素(下标为 0)赋值给 current_respond

从列表 cab:queue 中移除变量 current_respond 中包含的元素

返回(return)current_respond

测试说明

我会对你编写的代码进行测试:

测试输入:

1 2 3 4 5 6 7 8 9

9 8 7 6 5 4 3 2 1

预期输出:

Receive new request: 1, priority: 9, is_expired? True

Receive new request: 2, priority: 8, is_expired? True

Receive new request: 3, priority: 7, is_expired? True

Receive new request: 4, priority: 6, is_expired? True

Receive new request: 5, priority: 5, is_expired? True

Receive new request: 6, priority: 4, is_expired? True

Receive new request: 7, priority: 3, is_expired? True

Receive new request: 8, priority: 2, is_expired? True

Receive new request: 9, priority: 1, is_expired? True

Before: request queue: ['1', '2', '3', '4', '5', '6', '7', '8', '9']

Allocate new request: 1

After: request queue: ['2', '3', '4', '5', '6', '7', '8', '9']

Repeat request in few seconds:

Before: request queue length: 8

After: request queue length: 8

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import time
import redis

conn = redis.Redis()

# 用户端发起派车请求
def request_cab(user_id, priority):
    # 请在下面完成要求的功能
    #********* Begin *********#
    if conn.hexists('request:info:' + str(user_id), 'time'):
        return
    pipe = conn.pipeline()
    pipe.lpush('cab:queue', user_id)
    pipe.hmset('request:info:'+str(user_id), {'time': time.time(), 'priority':priority})
    pipe.expire('request:info:'+ str(user_id), 10 * 60)
    pipe.execute()
    #********* End *********#

# 平台选择优先级最高的派车请求并派车
def allocate():
    # 请在下面完成要求的功能
    #********* Begin *********#
    cab_queue=conn.sort('cab:queue',by='request:info:*->priority',desc=True)
    current_respond=cab_queue[0]
    conn.lrem('cab:queue', current_respond, 1)
    return current_respond
    #********* End *********#

# 用户端取消派车请求
def cancel_cab(user_id):
    conn.expire('request:info:' + str(user_id), 0)
    conn.lrem('cab:queue', user_id)

第7关:使用Redis管理登录令牌

编程要求

根据提示,在右侧Begin-End区域补充代码,完成令牌管理的后端处理逻辑:

在 check_token(token) 方法中:

使用 hget() 方法从哈希 login 中取出参数 token 域的值

返回(return)上述值

在 update_token(token, user_id) 方法中:

参数说明:

token 为令牌

user_id 为该令牌对应的用户 ID

获得当前时间并赋值给 timestamp

使用事务提交下列命令:

将域 token 与值 user_id 对存入哈希键 login 中

将成员 token 存入有序集合 recent:token 中,分值为 timestamp

在 clean_tokens() 方法中:

使用当前时间减去 86400 得到一周前时间戳,并赋值给 one_week_ago_timestamp

使用 zrangebyscore 方法获取有序集合 recent:token 中

分值大于等于 0

小于等于 one_week_ago_timestamp 的所有成员

并赋值给变量 expired_tokens

使用 zremrangebyscore 方法移除有序集合 recent:token 中

分值大于等于 0

小于等于 one_week_ago_timestamp 的所有成员

移除哈希 login 中所有与变量 expired_tokens 中相同的域

使用指针形式传入参数 *expired_tokens

测试说明

我会对你编写的代码进行测试:

测试输入:1,2,3,4,5

预期输出:

loged user: []

[ADD!]User 1 add token

Login with 1's token, match user: 1, have_timestamp: True

loged user: ['1']

[ADD!]User 2 add token

Login with 2's token, match user: 2, have_timestamp: True

loged user: ['1', '2']

[ADD!]User 3 add token

Login with 3's token, match user: 3, have_timestamp: True

loged user: ['1', '2', '3']

[ADD!]User 4 add token

Login with 4's token, match user: 4, have_timestamp: True

loged user: ['1', '2', '3', '4']

[ADD!]User 5 add token

Login with 5's token, match user: 5, have_timestamp: True

Login with expired token

User not_exist_user add token

Clean Tokens

Login with expired token, match user: None

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import time
import redis

conn = redis.Redis()

# 核对令牌,并返回该令牌对应的用户 ID
def check_token(token):
    # 请在下面完成要求的功能
    #********* Begin *********#
    return conn.hget('login', token)
    #********* End *********#

# 更新令牌,同时存储令牌的创建时间
def update_token(token, user_id):
    # 请在下面完成要求的功能
    #********* Begin *********#
    timestamp = time.time()
    pipe = conn.pipeline()
    pipe.hset('login', token, user_id)
    pipe.zadd('recent:token', token, timestamp)
    pipe.execute()

    #********* End *********#

# 清理过期令牌
def clean_tokens():
    # 请在下面完成要求的功能
    #********* Begin *********#
    one_week_ago_timestamp = time.time() - 86400
    expired_tokens = conn.zrangebyscore('recent:token', 0, one_week_ago_timestamp)
    conn.hdel('login', *expired_tokens)

    #********* End *********#

第8关:使用Redis实现购物车

编程要求

根据提示,在右侧Begin-End区域补充代码,实现购物车的后端处理逻辑:

在 add_item(name, price) 方法中:

使用 item_id 键自增作为商品 ID

商品信息键名为 item::info,其中 为商品ID

为商品信息哈希键设置:

域为 "name",值为参数 name

域为 "price",值为参数 price

为商品信息哈希键设置过期时间:30 天后

返回(return)商品 ID

在 add_to_cart(user_id, item, count) 方法中:

如果参数 count 大于 0:

为哈希键 cart:,其中 为参数 user_id 设置:

域为参数 item

值为参数 count

否则:

移除哈希键 cart:,其中 为参数 user_id 中:

参数为 item 的域

在 get_cart_info(user_id) 方法中:

获取 user_id 对应用户的购物车信息并返回(return)

测试说明

我会对你编写的代码进行测试:

测试输入:

pen

2.5

car

20000

shirt

99

user:1

3

2

user:2

1

8

预期输出:

Add item 1! Infos: {'price': '2.5', 'name': 'pen'}, have_ttl? True

Add item 2! Infos: {'price': '20000.0', 'name': 'car'}, have_ttl? True

Add item 3! Infos: {'price': '99.0', 'name': 'shirt'}, have_ttl? True

Add item 3 to cart user:1, count: 2, info: {'3': '2'}

Add item 1 to cart user:2, count: 8, info: {'1': '8'}

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import redis

conn = redis.Redis()

# 添加商品
def add_item(name, price):
    # 请在下面完成要求的功能
    #********* Begin *********#
    item_id = conn.incr('item_id')
    item_info_key = 'item:' + str(item_id)+ ":info"
    conn.hmset(item_info_key,{"name":name,"price":price})
    conn.expire(item_info_key,30 * 24 * 60 * 60)

    return item_id
    #********* End *********#

# 加入购物车
def add_to_cart(user_id, item, count):
    # 请在下面完成要求的功能
    #********* Begin *********#
    if count > 0:
        conn.hset("cart:"+user_id,item,count)
    else:
        conn.hrem('cart:'+user_id,item)
    #********* End *********#


# 获取购物车详情
def get_cart_info(user_id):
    # 请在下面完成要求的功能
    #********* Begin *********#
    return conn.hgetall("cart:"+user_id)
    #********* End *********#

第9关:使用Redis做页面缓存

编程要求

根据提示,在右侧Begin-End区域补充代码,实现使用Redis缓存网页:

创建变量 page_key,值为:

对参数 request_url 哈希编码并转化成字符串

使用字符串 cache: 与上述字符串前后拼接

尝试从 Redis 中读取字符串键,键名为 page_key 的值

若读取成功,则返回该键中的值

若读取失败,则:

创建变量 content,值为:

使用字符串 content for 与参数 request_url 前后拼接

使用 SETEX 命令将变量 content 存至字符串键:

键名为 page_key 的值

生存时间为 600 秒

测试说明

我会对你编写的代码进行测试:

测试输入:无;

预期输出:

Cache: request http://example.educoder.net/?productId=X, content: content for http://example.educoder.net/?productId=X, have_ttl? True

Get response: 'content for http://example.educoder.net/?productId=X'

Cache the request again!

Get response: 'content for http://example.educoder.net/?productId=X'

Cache: request http://example.educoder.net/?productId=X, content: content for http://example.educoder.net

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import redis

conn = redis.Redis()

# 使用 Redis 做页面缓存
def cache_request(request_url):
    # 请在下面完成要求的功能
    #********* Begin *********#
    page_key = 'cache:' + str(hash(request_url))
    content = conn.get(page_key)
    if not content:
        content = "content for " + request_url
        conn.setex(page_key, content, 600)
    return content
    #********* End *********#

第10关:使用Redis做数据缓存

编程要求

根据提示,在右侧Begin-End区域补充代码,实现使用Redis实现数据缓存:

在 add_cache_list(data_id, delay) 方法中:

参数说明:

data_id 是需要缓存的数据的唯一标识

delay 是该数据的更新周期

将分值为 delay 的成员 data_id 存入有序集合 cache:delay 中

将分值为当前时间 time.time() 的成员 data_id 存入有序集合 cache:list 中

在 cache_data() 方法中:

获取到有序集合 cache:list 中根据分值排序的第一个元素并赋值给变量 next

获取当前时间 time.time() 并赋值给变量 now

若 next 不存在或 next 的第一个元素的分值大于 now:

等待 100 毫秒

从 next 中取出第一个元素的成员值并赋值给变量 data_id

根据 data_id 从有序集合 cache:delay 中取出它的更新周期并赋值给变量 delay

判断 delay 是否大于 0:

若小于等于 0:

从有序集合 cache:list 中移除 data_id 成员

从有序集合 cache:delay 中移除 data_id 成员

删除该数据对应的缓存键 cache:data:,其中 的值为data_id

若大于 0:

构建哈希 {'id': data_id, 'data': 'fake data'} 并赋值给变量 data,作为待缓存的伪造数据

将分值为当前时间+更新周期的成员 data_id 加入有序集合 cache:list 中

更新该成员的缓存键 cache:data:*,值为:data 编码成 JSON 格式 json(dumps(data))

测试说明

我会对你编写的代码进行测试:

测试输入:无;

预期输出:

Schedule caching of itemX every 5 seconds

Cache list looks like:

['itemX']

Cached data looks like:

'{"data": "fake data", "id": "itemX"}'

Force delete cache

The cache was cleared? True

代码示例如下:

c 复制代码
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import time
import json
import redis

conn = redis.Redis()

# 将数据加入缓存队列
def add_cache_list(data_id, delay):
    # 请在下面完成要求的功能
    #********* Begin *********#
    conn.zadd('cache:delay', data_id, delay)
    conn.zadd('cache:list', data_id, time.time())
    #********* End *********#

# 缓存数据
def cache_data():
    # 请在下面完成要求的功能
    #********* Begin *********#
    next = conn.zrange('cache:list', 0, 0, withscores=True)
    now = time.time()
    if not next or next[0][1] > now:
        time.sleep(0.1)
    data_id = next[0][0]
    delay = conn.zscore('cache:delay', data_id)
    if delay <= 0:
        conn.zrem('cache:delay', data_id)
        conn.zrem('cache:list', data_id)
        conn.delete('cache:data:' + data_id)
    else:
        data = {'id': data_id, 'data': 'fake data'}
        conn.zadd('cache:list', data_id, now + delay)
        conn.set('cache:data:' + data_id, json.dumps(data))



    #********* End *********#

相关推荐
PGCCC22 分钟前
【PGCCC】Postgresql 存储设计
数据库·postgresql
PcVue China2 小时前
PcVue + SQL Grid : 释放数据的无限潜力
大数据·服务器·数据库·sql·科技·安全·oracle
魔道不误砍柴功4 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
锐策4 小时前
〔 MySQL 〕数据库基础
数据库·mysql
远歌已逝5 小时前
管理Oracle实例(二)
数据库·oracle
日月星宿~5 小时前
【MySQL】summary
数据库·mysql
爱吃土豆的程序员5 小时前
在oracle官网下载资源显示400 Bad Request Request Header Or Cookie Too Large 解决办法
java·数据库·oracle·cookie
睿思达DBA_WGX6 小时前
Oracle 11g rac 集群节点的修复过程
数据库·oracle
尘浮生6 小时前
Java项目实战II基于微信小程序的移动学习平台的设计与实现(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·学习·微信小程序·小程序
Leo.yuan7 小时前
数据量大Excel卡顿严重?选对报表工具提高10倍效率
数据库·数据分析·数据可视化·powerbi