简介

Redis 是用C语言开发完全开源免费的,遵守BSD协议的,一个高性能的,key-value型的,NOSQL数据库。

特点

  • 可以将内存中的数据持久化到硬盘中,重启的时候可以从硬盘中再次加载
  • 拥有丰富的数据类型,String、Hash、List、Set、ZSet(SortedSet)是常用的数据类型
  • 极高的读写性能
  • 拥有高可用架构,支持集群部署

安装

  1. Github下载地址:https://github.com/tporadowski/redis/releases
  2. 中文官网下载地址:http://www.redis.cn/
  3. github上面下载下来的压缩包默认是包含了Redis服务端程序和一个客户端访问程序的,redis-server.exe为Redis的服务端,redis-cli.exe为Redis的客户端。在redis-cli中可以用redis特有的语法或者说命令来和服务端交互,实现数据的CURD等操作,实际开发过程中,则是使用具体的工具类或者框架来和redis的服务端交互,例如java使用Jedis来和Redis交互。

  4. 首先启动server,再启动cli,这时候cli端会自动连接上服务端,尝试在cli中执行一些命令,config get *(查看Redis详细配置信息的命令)



    可以看到配置信息已经在cli中打印出来了,dbfilename配置为数据库文件的名称,默认是dump.rdb,requirepass配置为数据库的访问密码,可以看到当前为空,即无需密码就可以访问

数据类型

官方文档:https://www.redis.net.cn/tutorial/3508.html

  1. String

String是Redis中最基本的数据类型

string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象

string类型是Redis最基本的数据类型,一个键最大能存储512MB。

单值单Value

  • SET key1 beijing : 添加一条数据,SET为关键字,key1 是键 ,beijing 是值
  • keys * :查询所有的键 , redis关键字不区分大小写
  • GET key1 :根据键查找值
  • string 的其他命令
    • del :根据键删除
    • append :追加
    • strlen :根据键查询值的长度
    • incr :Increment,值在当前基础上加1,仅对数字有效,可用于高并发下的秒杀活动
    • decr :DeleteCreate,值在当前基础上减1,仅对数字有效
    • setex : SetWithExpire,添加一条数据,并指定多久过期
    • setnx : SetIfNotExist,添加一条数据,若指定的键已经存在就添加失败,若不存在添加成功
    • mset :MoreSet,批量添加,类似的还有mget(批量根据建获取值),msetnx(批量添加,若指定的某个键已经存在,全部添加失败,否则全部添加成功)
  1. Hash

hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Redis 中每个 hash 可以存储 2 的 32 次方减 1 个键值对(40多亿)

KV模式不变,但V是一个键值对。有点像java中的Map

  • hset user id 11 : 添加一条记录,hset为关键字, user 为键,id 11 为值,此时的值就是一个键值对结构了
  • hget user id:根据键和【值中的键】查询一条记录
  • hmset customer id 11 name xiaoming age 20:批量添加数据,此时的键为customer,值是id 11 name xiaoming age 20,但同时整个值呈现的是KV的结构
  • hmget customer id name age:批量根据键+值中的键查询值中的值
  • hgetall customer:根据键获取值
  • hash的其他命令:
    • hlen:根据键查询值的数量
    • hexists key :在键里面的某个值得键是否存在
    • hkeys/hvals:根据键获取值中所有的键/所有的值
    • hincrby/hincrbyfloat:定量增加整数,定量增加小数
    • hsetnx:添加时候,判断是否已经存在
  1. List

Redis列表是简单的字符串列表,按照插入顺序排序。可以从头部(左边)或者尾部(右边)进行插入。一个列表最多可以包含 2 的 32 次方 - 1 个元素 (4294967295, 每个列表可容纳超过40亿个元素)。

单值多value

  • lpush list01 1 2 3 4 5:LeftPush,创建一个键为list01的列表,并有序的从左边添加 1 2 3 4 5 这几个元素
  • lrange list01 0 -1:从左边查询键为list01的列表
  • rpush list02 1 2 3 4 5:RightPush,创建一个键为list02的列表,并有序的从右边添加 1 2 3 4 5 这几个元素
  • lpop list01:从list01列表的左边弹出一个元素
  • lindex list01 3:按照下标访问列表元素
  • list的其他命令:
    • llen:求长度
    • lrem key :删除N个value
    • ltrlm key 开始index 结束index :截取指定范围的值后再赋值给key
  1. Set

Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的时间复杂度都是O(1)。集合中最大的成员数为 2 的 32 次方 - 1 (4294967295, 每个集合可存储40多亿个成员)。

单值多value

  • sadd set01 1 1 2 2 3 3:创建一个键为set01的集合,重复的值会被覆盖。
  • smembers set01:根据键查询值
  • sismember set01 3:判断set01集合中是否存在值为3的元素
  • Set的其他命令:
    • scard:获取集合里面元素的个数
    • srem key value :根据键删除值中的某个元素
    • srandmember key 3 :随机获取集合中的3个元素,可用于高并发场景下的抽奖
    • spop key :随机出栈

C#客户端

StackExchange.Redis:StackOverflow开源的一个Redis(C#)客户端

Microsoft.Extensions.Caching.Redis:微软官方基于StackExchange.Redis 封装后的Redis客户端

下面用代码演示基于Microsoft.Extensions.Caching.Redis和Redis-Server进行交互

  • 新建控制台应用程序,项目属性如下所示

  • 项目目录结构和nuget依赖

  • RedisUtil为redis交互工具类,封装了Redis常用数据类型的存储和读取操作。具体代码如下

using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace RedisDemo.Utils
{
class RedisUtil
{ public static readonly Lazy<RedisUtil> lazy = new Lazy<RedisUtil>(() => new RedisUtil()); public static RedisUtil redis { get { return lazy.Value; } } private RedisUtil() { } private static IDatabase db = null; static RedisUtil()
{
ConnectionMultiplexer conn = ConnectionMultiplexer.Connect("127.0.0.1:6379");
db = conn.GetDatabase();
} /// <summary>
/// String类型set
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool StringSet(string key, string value)
{
return db.StringSet(key, value);
} /// <summary>
/// String类型set
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="timeSpan">过期时间</param>
/// <returns></returns>
public static bool StringSet(string key, string value, TimeSpan timeSpan)
{
return db.StringSet(key, value, timeSpan);
} /// <summary>
/// String类型get
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static string StringGet(string key)
{
return db.StringGet(key);
} /// <summary>
/// Hash类型set
/// </summary>
/// <typeparam name="V"></typeparam>
/// <param name="key"></param>
/// <param name="dic"></param>
public static void HashSet<V>(string key, Dictionary<string, V> dic)
{
if (dic == null || dic.Count <= 0) { return; }
HashEntry[] entries = new HashEntry[dic.Count];
List<string> keys = new List<string>(dic.Keys);
for (int i = 0; i < dic.Count; i++)
{
string value = JsonConvert.SerializeObject(dic[keys[i]]);
entries[i] = new HashEntry(keys[i], value);
}
db.HashSet(key, entries);
} /// <summary>
/// Hash类型set
/// </summary>
/// <typeparam name="V"></typeparam>
/// <param name="key"></param>
/// <param name="field"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool HashSet<V>(string key, string field, V value)
{
return db.HashSet(key, field, JsonConvert.SerializeObject(value));
} /// <summary>
/// Hash类型get
/// </summary>
/// <typeparam name="V"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public static Dictionary<string, V> HashGet<V>(string key)
{
HashEntry[] entries = db.HashGetAll(key);
if (entries != null && entries.Length > 0)
{
Dictionary<string, V> dics = new Dictionary<string, V>();
foreach (var item in entries)
{
dics.Add(item.Name, JsonConvert.DeserializeObject<V>(item.Value));
}
return dics;
}
return null;
} /// <summary>
/// Hash类型get
/// </summary>
/// <param name="key"></param>
/// <param name="field"></param>
/// <returns></returns>
public static string HashGet(string key, string field)
{
return db.HashGet(key, field);
} /// <summary>
/// List添加的时候只能一个一个的添加
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="values"></param>
/// <returns></returns>
public static bool ListSet<T>(string key, List<T> values)
{
if (values == null | values.Count <= 0) { return false; }
for (int i = 0; i < values.Count; i++)
{
db.ListLeftPush(key, JsonConvert.SerializeObject(values[i]));
}
return true;
} public static List<T> ListGet<T>(string key)
{
List<T> list = new List<T>();
RedisValue[] values = db.ListRange(key, 0, -1);
foreach (var item in values)
{
list.Add((T)JsonConvert.DeserializeObject(item));
}
return list;
} public static bool SetSet<T>(string key, List<T> values)
{
if (values == null | values.Count <= 0) { return false; }
for (int i = 0; i < values.Count; i++)
{
db.SetAdd(key, JsonConvert.SerializeObject(values[i]));
}
return true;
} public static List<T> SetGet<T>(string key)
{
List<T> list = new List<T>();
RedisValue[] values = db.SetMembers(key);
foreach (var item in values)
{
list.Add((T)JsonConvert.DeserializeObject(item));
}
return list;
} }
}
  • Main 方法中编写测试代码
using Newtonsoft.Json;
using RedisDemo.Models;
using RedisDemo.Utils;
using System;
using System.Collections.Generic; namespace RedisDemo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//string
bool isok = RedisUtil.StringSet("age", "20", new TimeSpan(1, 0, 0));
Console.WriteLine(isok);
string result = RedisUtil.StringGet("age");
Console.WriteLine(result); //Hash
//基本数据类型
//Dictionary<string, string> dic01 = new Dictionary<string, string>();
//dic01.Add("dic-key01", "dic-v1");
//dic01.Add("dic-key02", "dic-v2");
//RedisUtil.HashSet("dic01", dic01);
//Dictionary<string, string> result = RedisUtil.HashGet<string>("dic01");
//Console.WriteLine(JsonConvert.SerializeObject(result)); //dic的value为一个实体类
//Dictionary<string, Sku> dic02 = new Dictionary<string, Sku>();
//dic02.Add("dic-key01", new Sku() { id = 1, name = "复印纸", price = 10.00M });
//dic02.Add("dic-key02", new Sku() { id = 2, name = "A5复印纸", price = 100.00M });
//RedisUtil.HashSet("dic02", dic02);
//Dictionary<string, Sku> result = RedisUtil.HashGet<Sku>("dic02");
//Console.WriteLine(JsonConvert.SerializeObject(result)); //dic的value为一个嵌套实体类
//Dictionary<string, Spu> dic03 = new Dictionary<string, Spu>();
//dic03.Add("k1", new Spu() { id = 1, name = "复印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3复印纸", price = 1.00M } } });
//dic03.Add("k2", new Spu() { id = 2, name = "打印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3打印纸", price = 91.00M } } });
//RedisUtil.HashSet("dic03", dic03);
//Dictionary<string, Spu> result = RedisUtil.HashGet<Spu>("dic03");
//Console.WriteLine(JsonConvert.SerializeObject(result)); //List
//List<int> lists = new List<int>() { 1, 2, 3, 4, 5 };
//bool isok = RedisUtil.ListSet("list02", lists);
//List<long> result = RedisUtil.ListGet<long>("list02");
//Console.WriteLine(JsonConvert.SerializeObject(result)); //Set
//List<int> lists = new List<int>() { 1, 2, 3, 4, 5,5 };
//bool isok = RedisUtil.SetSet("set01", lists);
//List<long> result = RedisUtil.SetGet<long>("set01");
//Console.WriteLine(JsonConvert.SerializeObject(result)); }
}
}
  • String类型存储和读取

bool isok = RedisUtil.StringSet("age", "20", new TimeSpan(1, 0, 0));
Console.WriteLine(isok);
string result = RedisUtil.StringGet("age");
Console.WriteLine(result);

TimeSpan为设置的过期时间,三个参数分别表示时,分,秒

输出结果过为

Hello World!
True
20
  • Hash存储一个基本数据类型的字典集合
 Dictionary<string, string> dic01 = new Dictionary<string, string>();
dic01.Add("dic-key01", "dic-v1");
dic01.Add("dic-key02", "dic-v2");
RedisUtil.HashSet("dic01", dic01);
Dictionary<string, string> result = RedisUtil.HashGet<string>("dic01");
Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
{"dic-key01":"dic-v1","dic-key02":"dic-v2"}
  • Hash存储一个value为实体类的字典
            Dictionary<string, Sku> dic02 = new Dictionary<string, Sku>();
dic02.Add("dic-key01", new Sku() { id = 1, name = "复印纸", price = 10.00M });
dic02.Add("dic-key02", new Sku() { id = 2, name = "A5复印纸", price = 100.00M });
RedisUtil.HashSet("dic02", dic02);
Dictionary<string, Sku> result = RedisUtil.HashGet<Sku>("dic02");
Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
{"dic-key01":{"id":1,"name":"复印纸","price":10.00},"dic-key02":{"id":2,"name":"A5复印纸","price":100.00}}
  • Hash存储一个value为嵌套的实体类的字典
            Dictionary<string, Spu> dic03 = new Dictionary<string, Spu>();
dic03.Add("k1", new Spu() { id = 1, name = "复印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3复印纸", price = 1.00M } } });
dic03.Add("k2", new Spu() { id = 2, name = "打印纸", skus = new List<Sku>() { new Sku() { id = 1, name = "A3打印纸", price = 91.00M } } });
RedisUtil.HashSet("dic03", dic03);
Dictionary<string, Spu> result = RedisUtil.HashGet<Spu>("dic03");
Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
{"k1":{"id":1,"name":"复印纸","skus":[{"id":1,"name":"A3复印纸","price":1.00}]},"k2":{"id":2,"name":"打印纸","skus":[{"id":1,"name":"A3打印纸","price":91.00}]}}
  • List存储一个int类型的List集合,这里存的时候实际是int32,但是取出来的时候是int64,所以使用了long来存方取出的数据
            List<int> lists = new List<int>() { 1, 2, 3, 4, 5 };
bool isok = RedisUtil.ListSet("list02", lists);
List<long> result = RedisUtil.ListGet<long>("list02");
Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
[5,4,3,2,1]
  • Set存储一个int集合,从输出结果可以看到,重复的那个5没有存进去,redis的set数据类型是无序不可重复的
            List<int> lists = new List<int>() { 1, 2, 3, 4, 5, 5 };
bool isok = RedisUtil.SetSet("set01", lists);
List<long> result = RedisUtil.SetGet<long>("set01");
Console.WriteLine(JsonConvert.SerializeObject(result));

输出结果为

Hello World!
[1,2,3,4,5]

spring-boot客户端

  • 关于java客户端就以spring-boot做为切入点简单演示
  • org.springframework.data.redis.core 只是封装了常用的接口,具体实现还是通过jedis或者lettuce去和redis-server交互
  • spring-boot 2.0之前默认的redis客户端是jedis;之后默认的是lettuce
  • 新建spring-boot的web应用,采用maven来管理依赖,项目文件结构如下:

  • 在pom.xml中增加如下dependency。

        <!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> <!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency> <!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
  • 修改application.properties。配置redis-server的访问地址
server.port=8081
spring.redis.host=127.0.0.1
spring.redis.port=6379
  • 新建一个RestController,并命名为TestRedisController
@RestController
@RequestMapping("/redis/")
public class TestRedisController {}
  • 注入RedisTemplate对象,此对象为springframework框架提供的一个对象,通过此对象实现spring-boot和redis-server的交互
    @Autowired
private RedisTemplate<String, String> redisTemplate;
  • 相关示例

/**
* String类型set
*
* @param key
* @param value
* @return
*/
@GetMapping("string/set/{key}/{value}")
public boolean stringSet(@PathVariable("key") String key, @PathVariable("value") String value) {
redisTemplate.opsForValue().set(key, value);
return true;
} /**
* String类型get
*
* @param key
* @return
*/
@GetMapping("string/get/{key}")
public String stringGet(@PathVariable("key") String key) {
return redisTemplate.opsForValue().get(key);
} /**
* Hash类型ser
*
* @param key
* @return
*/
@GetMapping("hash/set/{key}")
public boolean hashSet(@PathVariable("key") Integer key) {
UserDto userDto = new UserDto().setId(key).setName("redis").setStature(0.55D);
Map<String, String> map = new Hashtable<>();
map.put(key.toString(), JSON.toJSONString(userDto));
redisTemplate.opsForHash().putAll(key.toString(), map);
return true;
} /**
* Hash类型ser
*
* @param key
* @param field
* @param value
* @return
*/
@GetMapping("hash/set/{key}/{field}/{value}")
public boolean hashSet(@PathVariable("key") String key, @PathVariable("field") String field, @PathVariable("value") String value) {
redisTemplate.opsForHash().put(key, field, value);
return true;
} /**
* Hash类型get
*
* @param key
* @return
*/
@GetMapping("hash/get/{key}")
public UserDto hashGet(@PathVariable("key") String key) {
String result = JSON.toJSONString(redisTemplate.opsForHash().get(key, key));
return JSON.parseObject(result, UserDto.class);
} /**
* Hash类型get
*
* @param key
* @param field
* @return
*/
@GetMapping("hash/get/{key}/{field}")
public String hashGet(@PathVariable("key") String key, @PathVariable("field") String field) {
return JSON.toJSONString(redisTemplate.opsForHash().get(key, field));
} /**
* List类型set - 一个一个的增加
*
* @param key
* @param value
* @return
*/
@GetMapping("list/set/{key}/{value}")
public boolean listSet(@PathVariable("key") String key, @PathVariable("value") String value) {
String[] array = value.split(",");
for (String item : array) {
redisTemplate.opsForList().leftPush(key, item);
}
return true;
} /**
* List类型get
*
* @param key
* @return
*/
@GetMapping("list/get/{key}")
public List<String> listGet(@PathVariable("key") String key) {
return redisTemplate.opsForList().range(key, 0, -1);
} /**
* Set类型set
*
* @param key
* @param value
* @return
*/
@GetMapping("set/set/{key}/{value}")
public boolean setSet(@PathVariable("key") String key, @PathVariable("value") String value) {
String[] array = value.split(",");
for (String item : array) {
redisTemplate.opsForSet().add(key, item);
}
return true;
} /**
* Set类型get
*
* @param key
* @return
*/
@GetMapping("set/get/{key}")
public Set<String> setGet(@PathVariable("key") String key) {
return redisTemplate.opsForSet().members(key);
}

常用命令

  • del key:删除某一个key,对应的value也就删除了
  • flushdb :清空当前数据库,删除所有数据
  • keys *:查询所有key

引用

代码

Redis极简教程的更多相关文章

  1. Asky极简教程:零基础1小时学编程,已更新前8节

    Asky极简架构 开源Asky极简架构.超轻量级.高并发.水平扩展.微服务架构 <Asky极简教程:零基础1小时学编程>开源教程 零基础入门,从零开始全程演示,如何开发一个大型互联网系统, ...

  2. Typora极简教程

    Typora极简教程 ” Markdown 是一种轻量级标记语言,创始人是约翰·格鲁伯(John Gruber).它允许人们 “使用易读易写的纯文本格式编写文档,然后转换成有效的 HTML 文档.” ...

  3. CentOS安装使用.netcore极简教程(免费提供学习服务器)

    本文目标是指引从未使用过Linux的.Neter,如何在CentOS7上安装.Net Core环境,以及部署.Net Core应用. 仅针对CentOS,其它Linux系统类似,命令环节稍加调整: 需 ...

  4. Python 极简教程(八)字符串 str

    由于字符串过于重要,请认真看完并保证所有代码都至少敲过一遍. 对于字符串,前面在数据类型中已经提到过.但是由于字符串类型太过于常用,Python 中提供了非常多的关于字符串的操作.而我们在实际编码过程 ...

  5. Nginx 极简教程(快速入门)

    作者:dunwu github.com/dunwu/nginx-tutorial 推荐阅读(点击即可跳转阅读) 1. SpringBoot内容聚合 2. 面试题内容聚合 3. 设计模式内容聚合 4.  ...

  6. 【转】Typora极简教程

    Typora极简教程 Typora download ” Markdown 是一种轻量级标记语言,创始人是约翰·格鲁伯(John Gruber).它允许人们 “使用易读易写的纯文本格式编写文档,然后转 ...

  7. nginx极简教程

    Nginx 极简教程 本项目是一个 Nginx 极简教程,目的在于帮助新手快速入门 Nginx. examples 目录中的示例模拟了工作中的一些常用实战场景,并且都可以通过脚本一键式启动,让您可以快 ...

  8. NodeJS 极简教程 <1> NodeJS 特点 & 使用场景

    NodeJS 极简教程 <1> NodeJS 特点 & 使用场景 田浩 因为看开了所以才去较劲儿.   1. NodeJS是什么 1.1 Node.js is a JavaScri ...

  9. 自制 os 极简教程1:写一个操作系统有多难

    为什么叫极简教程呢?听我慢慢说 不知道正在阅读本文的你,是否是因为想自己动手写一个操作系统.我觉得可能每个程序员都有个操作系统梦,或许是想亲自动手写出来一个,或许是想彻底吃透操作系统的知识.不论是为了 ...

  10. python极简教程04:进程和线程

    测试奇谭,BUG不见. 大家好,我是谭叔. 这一场,主讲python的进程和线程. 目的:掌握初学必须的进程和线程知识. 进程和线程的区别和联系 终于开始加深难度,来到进程和线程的知识点~ 单就这两个 ...

随机推荐

  1. openGauss内核分析:执行计划生成

    摘要:SQL语句解析完成后被解析成Query结构,在进行优化时是以Query为单位进行的,Query的优化分为基于规则的逻辑优化(查询重写)和基于代价的物理优化(计划生成),主入口函数为subquer ...

  2. “互联网+”大赛之智慧校园 赛题攻略:你的智慧校园,WeLink帮你来建

    摘要:本赛题的核心就是借助华为云WeLink的中台服务能力/开发工具等,结合学校的具体的高价值场景,开发出WeLink小程序,方便师生的学习与生活. 本文分享自华为云社区<"互联网+& ...

  3. vue2.x老项目typescript改造过程经验总结

    前言: 关于Vue2.x 的TS改造,其实没有啥好说的. 对于vue-cli项目来说,从新跑一遍 vue create xxx-project ,选择Manually select features ...

  4. Flutter加固原理及加密处理

    ​ 引言 为了保护Flutter应用免受潜在的漏洞和攻击威胁,加固是必不可少的措施之一.Flutter加固原理主要包括代码混淆.数据加密.安全存储.反调试与反分析.动态加载和安全通信等多个方面.通过综 ...

  5. App Store上架流程/苹果app发布流程

    第一步:拥有自己的苹果开发者账号: 开发账号分为两类:99美元(发布App Store用的,也就是上架苹果商店用这个):299美元(企业授信证书,不用上架appstore 亦可使用.弊端:证书容易被封 ...

  6. 如何在NET 6.0使用结构化的日志系统

              在我们的系统里面,有一项技术是必须使用的,那就是日志记录.我们在调试系统或者跟踪系统运行情况,都可以通过日志了解具体的情况.在项目开发中,我们有可能使用系统本身所带的日志系统,也有 ...

  7. JSP | JSP 动作详解

    原作者为 RioTian@cnblogs, 本作品采用 CC 4.0 BY 进行许可,转载请注明出处. 本篇学习自:C语言中文网,部分内容转载仅供学习使用. \[QAQ \] JSP 动作利用 XML ...

  8. AtCoder Regular Contest 119 (ABC题)

    比赛链接:Here A - 119 × 2^23 + 1 注意到 \(2^{60} > 10^{18}\)​ ,所以我们可以直接枚举 \(0\) ~ \(59\) int main() { ci ...

  9. [VS Code] 入门-自定键盘快捷键

    Keyboard Shortcuts 自訂鍵盤快捷鍵 開啟設定面板 :點擊左下角管理圖示〉選擇「鍵盤快速鍵」. 編輯器開啟後,滑鼠移至變更項目上,點擊出現的變更圖示(橘框處),輸入要變更的快捷鍵組合. ...

  10. Android 加载图片占用内存分析

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/aRDzmMlkqB14Ty67GJs9vg作者:Xu Jie 不同Android版本,对一张图 ...