【JavaWeb】spring全家桶回顾——NoSql实践

浏览博客时,若发现作者有描述错误或不清的地方,请私信或者留言讨论,共同进步

使用 docker

  接下来我们会多次使用到不同的中间件,所以推荐使用 docker 来安装中间件来方便我们进行学习和测试,使用 Mac 的同学可以直接去 docker 官方直接下载 docker-desktop, 而 windows 的同学则推荐通过虚拟机安装 Linux 系统来使用 docker

# 静候安装
yum install -y docker

# 安装后选择适合的国内镜像加速下载
# 镜像
https://registry.docker-cn.com
http://hub-mirror.c.163.com
https://3laho3y3.mirror.aliyuncs.com
http://f1361db2.m.daocloud.io
https://mirror.ccs.tencentyun.com
# 改写配置文件并且重启
sudo nano /etc/docker/daemon.json
{
	// 注意 CTRL+O 是保存改写记录  ctrl+X是退出编辑模式
    "registry-mirrors": ["http://hub-mirror.c.163.com"]
}
# 重启
systemctl restart docker

# 查看是否配置成功
docker info

简单的了解 MongoDB

  当我们准备学习入门一项新技术的时候,推荐先去了解一下这项技术的大致板块,比如这里就可以先去了解一下 MongoDB 是什么?它可以做什么?它经常被用在什么地方?有什么案例推荐?就跟我们上学时做英语阅读理解一下,首先要快速浏览整篇文章,了解大致语义,然后再仔细的去研究就能大大的提高答题的正确率。
  MongoDB 是文档型数据库,一般存储的数据类型都是 json 格式的数据,像是这样的:

{
	name:"小林",    // field:value
	age:23,
	group:["sports"] // 字段的值也可以是其他文档、数组和文档数组。
}

  json 格式类型数据即是对象,对应许多编程语言中的内置数据类型,这样使得 mongodb 拥有强大的查询能力可以直接面向对象查询,并且它覆盖了 sql 的基本所有能力,像是 CRUD、聚合、事务等等,还提供了高性能的持久化能力,为什么说它具备高性能的持久化呢?它的官网给出的解释是:对嵌入式数据模型的支持减少了数据库系统上的I / O操作,这该如何去理解?

  直白的理解就是连表查询的事情少了(因为都存到一个json串里,大部分不需要做多对多或一对多关联),并且支持索引更快的查询,可以包含来自嵌入式文档和数组的键。另外它也支持高可用可拓展,像 mysql 一样支持多种存储引擎。
  MongoDB 比较常见的应用领域如下:

  • 物流场景:使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
  • 社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能
  • 视频直播,使用 MongoDB 存储用户信息、礼物信息

  如果你还想更多的了解 MongoDB 的相关信息,简易从官网入手:MongoDB官网

安装 MongoDB

  了解完 MongoDB 的一些相关信息后,我们首先要安装它:

# 打开虚拟机,进入终端
docker pull mongo

# 启动
docker run --name mongo -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=admin -d mongo

# 登入到 mongodb 容器中
docker exec -it mongo bash

# 登录
mongo -u admin -p admin

在 Spring 中操作 MongoDB

  spring 的目标就是在不失各个底层数据库特性的基础上来操纵数据。在 Spring Data 中Repository主要用作标记接口,spring 会为你动态代理生成对应的数据操作类。对于如何去使用 spring-data-mongodb 你完全可以将他像 JPA 那样使用,比如了解到它需要用到的注解 @Document、@Id 是做什么的,如何去定义接口内的 CRUD 方法等等。
  若你需要详细的了解 spring-data-mongoDB,建议先到官网了解:官方地址

学习前准备

# 查看当前数据库
show dbs;

# 切换数据库 mongoDB会自动帮你创建数据库
use springbucks;

# 创建操作角色
db.createUser(
	{
		user: "springbucks",
		pwd: "springbucks",
		roles: [
			{ role: "readWrite", db: "springbucks" }
		]
	}
)

  我们先简单学一下直接使用 MongoTemplate 是如何去进行 CRUD 的,准备一个 spring 初始化项目, 此次就只需要勾选 lombok 以及 spring-data-mongodb,此外还需要你加一个 joda-money 用来做额外的操作
  那么首先就是需要你做一下配置文件:

# 格式:用户名:密码@ip地址:端口/dbName
spring.data.mongodb.uri=mongodb://springbucks:springbucks@192.168.2.100:27017/springbucks

  代码实现

// 准备一个操作的实体类对象
@Document
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Coffee {
    @Id
    private String id;
    private String name;
    private Money price;
    private Date createTime;
    private Date updateTime;
}

// 准备一个转换器 不需要去关注实现细节 你只要知道这类似 json 处理且返回了 Money 对象就好
public class MoneyReadConverter implements Converter<Document, Money> {
    @Override
    public Money convert(Document source) {
        Document money = (Document) source.get("money");
        double amount = Double.parseDouble(money.getString("amount"));
        String currency = ((Document) money.get("currency")).getString("code");
        return Money.of(CurrencyUnit.of(currency), amount);
    }
}

// CRUD
@Slf4j
@SpringBootApplication
public class DemoApplication implements ApplicationRunner {
    @Autowired
    private MongoTemplate mongoTemplate;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions(Arrays.asList(new MoneyReadConverter()));
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Coffee espresso = Coffee.builder()
                .name("espresso")
                .price(Money.of(CurrencyUnit.of("CNY"), 20.0))
                .createTime(new Date())
                .updateTime(new Date()).build();
        Coffee saved = mongoTemplate.save(espresso);
        log.info("Coffee {}", saved);

        List<Coffee> list = mongoTemplate.find(
                Query.query(Criteria.where("name").is("espresso")), Coffee.class);
        log.info("Find {} Coffee", list.size());
        list.forEach(c -> log.info("Coffee {}", c));

        Thread.sleep(1000); // 为了看更新时间
        UpdateResult result = mongoTemplate.updateFirst(query(where("name").is("espresso")),
                new Update().set("price", Money.ofMajor(CurrencyUnit.of("CNY"), 30))
                        .currentDate("updateTime"),
                Coffee.class);
        log.info("Update Result: {}", result.getModifiedCount());
        Coffee updateOne = mongoTemplate.findById(saved.getId(), Coffee.class);
        log.info("Update Result: {}", updateOne);

        mongoTemplate.remove(updateOne);
    }
}

  了解完 mongoTemplate 的简单 CRUD 之后,就可以学习一下像是 JPA 那种实现方式的代码,仍然需要一个 Coffee 对象来作为数据操作对象,代码如下:

// 配置文件、操作对象类、转换器都一致
// repository
public interface CoffeeRepository extends MongoRepository<Coffee, String> {
    List<Coffee> findByName(String name);
}

@Slf4j
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private CoffeeRepository coffeeRepository;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions(Arrays.asList(new MoneyReadConverter()));
    }

    @Override
    public void run(String... args) throws Exception {
        Coffee espresso = Coffee.builder()
                .name("espresso")
                .price(Money.of(CurrencyUnit.of("CNY"), 20.0))
                .createTime(new Date())
                .updateTime(new Date()).build();
        Coffee latte = Coffee.builder()
                .name("latte")
                .price(Money.of(CurrencyUnit.of("CNY"), 30.0))
                .createTime(new Date())
                .updateTime(new Date()).build();

        List<Coffee> insert = coffeeRepository.insert(Arrays.asList(espresso, latte));
        coffeeRepository.findAll(Sort.by("name"))
                .forEach(c -> log.info("Saved Coffee {}", c));

        Thread.sleep(1000);
        latte.setPrice(Money.of(CurrencyUnit.of("CNY"), 35.0));
        latte.setUpdateTime(new Date());
        coffeeRepository.save(latte);
        coffeeRepository.findByName("latte")
                .forEach(c -> log.info("Coffee {}", c));

        coffeeRepository.deleteAll();
    }
}

Redis 的哨兵和集群模式

   redis 是一款键值对类型的非关系型数据库,应用场景非常广泛,基本可以说是 web 开发人员的必知必会的中间件之一,推荐刚入门的新人同学可以先浏览一下 redis-菜鸟教程 熟悉一下命令即可,以我个人经验来讲,redis的使用场景有但不限于:排行榜、签到以及签到红包、各类抽奖、秒杀活动及秒杀奖品、分布式锁等大部分键值对可以覆盖的场景。
  另外对于 redis 的使用,常见的是有用到 jedis、redistemplate、 redission以及lua脚本,建议到 github 上看一下各位大佬的简单演示,这里堆出代码来就显得有些繁长。

jedis 的哨兵模式是如何实现?

   redis 的哨兵主要是为了解决 redis 集群中主机宕机之后,无法自主替换 master 而出现的一种高可用模式,一般使用我们都会像使用数据库那样来配置一个连接池供我们使用,那么哨兵模式下的 jedis 我们就可以使用 JedisSentinelPool 作为我们的连接池对象。

// 那么看到我们的 JedisSentinelPool 对象的构造函数部分,可以看到最终使用的构造函数是该构造函数
public JedisSentinelPool(String masterName, Set<String> sentinels,
    final GenericObjectPoolConfig poolConfig, final int connectionTimeout, final int soTimeout,
    final String password, final int database, final String clientName) {
  this.poolConfig = poolConfig;
  this.connectionTimeout = connectionTimeout;
  this.soTimeout = soTimeout;
  this.password = password;
  this.database = database;
  this.clientName = clientName;

  HostAndPort master = initSentinels(sentinels, masterName);
  initPool(master);
}

  在该构造函数方法内重要的方法是 initSentinels,我们点进去去查看对应的代码:

private HostAndPort initSentinels(Set<String> sentinels, final String masterName) {
	// 省略非关键代码
	// ....
	jedis = new Jedis(hap.getHost(), hap.getPort());
	// 通过名称获取主机地址 实际上就是执行 redis 命令:sentinel get-master-addr-by-name mymaster 
	// 返回的就是 host:port 两部分
	List<String> masterAddr = jedis.sentinelGetMasterAddrByName(masterName);

	// 随后做了一个很讨巧的判断 list.size 不是2就直接跳过
	 if (masterAddr == null || masterAddr.size() != 2) {
		log.warning("Can not get master addr,master name: " + masterName + ". Sentinel: " + hap
		     + ".");
		 continue;
    }
    // 构建对应的HostAndPortUtil来管理和redis server的host和port. 设置完成后就是自然而然的和redis server建立连接.
    master = toHostAndPort(masterAddr);
}

了解一下 redis 的集群模式

  集群的意义是解决高可用的问题,像是假设单机 redis 可支持1W+的并发量,那么我上3台理论上就可以达到3W的程度(但实际你就需要打个八折来计算最稳妥),Redis 集群除了提升读写能力之外,还提供在多个节点间自动拆分数据集的能力,也就是数据分片,并且当节点的自己遇到故障时也可以从其他节点获取到问题节点上的数据。

  • redis 集群的TCP 端口
    每个redis集群节点实际上都是开发两个 TCP 链接的,一个是用于客户端连接提供服务的 TCP 端口,就是我们熟知的6379,还有一个就是集群间通信的接口,一般是10000+6379(如16379),你可以在配置cluster-port覆盖它,这里是提醒你,如果你想集群运行成功,要小心不要误关了集群间通信的 TCP 端口

  • redis 集群数据分片
    redis 集群中有 16384 个哈希槽,基本是按照取模的方式匹配与分配

  • redis 集群的一致性
    redis 集群不保证强一致性,也就是异步复制的情况下(master通知写到slave1/2/3,master不会等待回复,此时2未写入且master失去连接,随后2升级为主机,这时候就是永久失去了),这种情况是需要你配置 redis 的一些配置项,比如写入的环列队列的长度等。

jedis的集群模式又是怎样的?

   这里又到了源码导读环节, jedis 的源码写的简便适合像我这种初级开发来阅读,我们可以借鉴学习它的一些客户端方面操作用于自己公司的一些相关项目开发上。
   jedis 客户端的源码解析基本上都可以从构造函数来入手,这里的代码流程执行大概如下:
  首先是从 JedisCluster 该类开始,可以发现它的构造函数基本都是调用父类 BinaryJedisCluster 的构造函数,那么我们先进入父类,看到:

public class BinaryJedisCluster implements BasicCommands, BinaryJedisClusterCommands,
    MultiKeyBinaryJedisClusterCommands, JedisClusterBinaryScriptingCommands, Closeable {
    // 省略非关键代码....
	public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int timeout, int maxAttempts,
	final GenericObjectPoolConfig poolConfig) {
		this.connectionHandler = new JedisSlotBasedConnectionHandler(jedisClusterNode, poolConfig,
		timeout);
		this.maxAttempts = maxAttempts;
	}
}

  这里 jedis new 出了一个 connectionHandler 实际上是我们整个 jedisCluster 中比较重要的一个事件,我们进入该类的父类可以看到它构建一个 JedisClusterInfoCache

public abstract class JedisClusterConnectionHandler implements Closeable {
	protected final JedisClusterInfoCache cache;
	// 省略非关键代码
public JedisClusterConnectionHandler(Set<HostAndPort> nodes,
	final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password, String clientName) {
		this.cache = new JedisClusterInfoCache(poolConfig, connectionTimeout, soTimeout, password, clientName);
		initializeSlotsCache(nodes, clientName);
	}
}

  JedisClusterInfoCache 这个缓存相当于我们连接池的一个基础配置,进去之后你可以看到它分别初始化了连接池配置、连接超时时间、密码、客户端名称等,并且该构造函数之后还执行了 initializeSlotsCache 方法,主要是去发现整个的集群节点还有它的 slots 信息的方法,其实就是通过 jedis 去取了它 cluserSlots 的一个信息,然后做了个分类,就是映射了对应关系

private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig,
                                    int connectionTimeout, String clientName) {
  for (HostAndPort hostAndPort : startNodes) {
    Jedis jedis = null;
    try {
    	// 连接准备
      jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), soTimeout);
      if (password != null) {
        jedis.auth(password);
      }
      if (clientName != null) {
        jedis.clientSetname(clientName);
      }
      // 分配 slot 注意该方法
      cache.discoverClusterNodesAndSlots(jedis);
      break;
    } catch (JedisConnectionException e) {
      // try next nodes
    } finally {
      if (jedis != null) {
        jedis.close();
      }
    }
  }
}

public void discoverClusterNodesAndSlots(Jedis jedis) {
  w.lock();

  try {
    reset();
    List<Object> slots = jedis.clusterSlots();

    for (Object slotInfoObj : slots) {
      List<Object> slotInfo = (List<Object>) slotInfoObj;

      if (slotInfo.size() <= MASTER_NODE_INDEX) {
        continue;
      }
	  // 获取分配的插槽阵列	 
      List<Integer> slotNums = getAssignedSlotArray(slotInfo);

      // hostInfos
      int size = slotInfo.size();
      for (int i = MASTER_NODE_INDEX; i < size; i++) {
        List<Object> hostInfos = (List<Object>) slotInfo.get(i);
        if (hostInfos.size() <= 0) {
          continue;
        }

        HostAndPort targetNode = generateHostAndPort(hostInfos);
        // 做设置
        setupNodeIfNotExist(targetNode);
        if (i == MASTER_NODE_INDEX) {
          // 分配
          assignSlotsToNode(slotNums, targetNode);
        }
      }
    }
  } finally {
    w.unlock();
  }
}

  这里 jedis 有两种取链接的方式,第一种通过我们 connectionHandler 连接的时候通过 pool 随机 去取, 然后做一下心跳,如果通过就可以直接返回,如果不通过就 close 掉。还有一种是通过特定的 slot 去取,只要我们知道 key 对应的 slot 是那个,就可以在缓存中找到对应的数据。

public class JedisSlotBasedConnectionHandler extends JedisClusterConnectionHandler {
	// 省略非关键代码
	  @Override
  public Jedis getConnection() {
    // In antirez's redis-rb-cluster implementation,
    // getRandomConnection always return valid connection (able to
    // ping-pong)
    // or exception if all connections are invalid

    List<JedisPool> pools = cache.getShuffledNodesPool();

    for (JedisPool pool : pools) {
      Jedis jedis = null;
      try {
        jedis = pool.getResource();

        if (jedis == null) {
          continue;
        }

        String result = jedis.ping();

        if (result.equalsIgnoreCase("pong")) return jedis;

        jedis.close();
      } catch (JedisException ex) {
        if (jedis != null) {
          jedis.close();
        }
      }
    }
    throw new JedisNoReachableClusterNodeException("No reachable node in cluster");
  }
}

 @Override
  public Jedis getConnectionFromSlot(int slot) {
    JedisPool connectionPool = cache.getSlotPool(slot);
    if (connectionPool != null) {
      // It can't guaranteed to get valid connection because of node
      // assignment
      return connectionPool.getResource();
    } else {
      renewSlotCache(); //It's abnormal situation for cluster mode,that we have just nothing for slot,try to rediscover state
      connectionPool = cache.getSlotPool(slot);
      if (connectionPool != null) {
        return connectionPool.getResource();
      } else {
        //no choice,fallback to new connection to random node
        return getConnection();
      }
    }
  }

  需要注意的是 jedis 的集群模式是不支持读写分离操作的,比如写在master、读在slave这种操作,具体可以看 github 上官方给出的解释:官方解释

原文地址:https://blog.csdn.net/qq_43654226/article/details/124237447

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读752次。关系型数据库关系型数据库是一个结构化的数据库,创建在关系模型(二维表模型)基础上,一般面向于记录SQL语句(标准数据查询语言)就是一种基于关系型数据库的语言,用于执行对关系型数据库中数据的检索和操作主流的关系数据库包括Oracle、Mysql、SQL Server、Microsoft Access、DB2等非关系型数据库NoSQL(nOSQL=Not Only SQL),意思是“不仅仅是SQL”,是非关系型数据库的总称。除了主流的关系型数据库外的数据库,都认为是非关系型主流的NoSQ.._redis是非关系型数据库吗
文章浏览阅读687次,点赞2次,收藏5次。商城系统中,抢购和秒杀是很常见的营销场景,在一定时间内有大量的用户访问商场下单,主要需要解决的问题有两个:1. 高并发对数据库产生的压力;2. 竞争状态下如何解决商品库存超卖;高并发对数据库产生的压力对于第一个问题,使用缓存来处理,避免直接操作数据库,例如使用 Redis。竞争状态下如何解决商品库存超卖对于第二个问题,需要重点说明。常规写法:查询出对应商品的库存,判断库存数量否大于 0,然后执行生成订单等操作,但是在判断库存是否大于 0 处,如果在高并发下就会有问题,导致库存_php库存结余并发
文章浏览阅读1.4k次。MongoTemplate开发spring-data-mongodb提供了MongoTemplate和MongoRepository两种方式访问MongoDB,MongoRepository的方式访问较为简单,MongoTemplate方式较为灵活,这两种方式在Java对于MongoDB的运用中相辅相成。_springboot插入指定的mongodb数据库
文章浏览阅读887次,点赞10次,收藏19次。1.背景介绍1. 背景介绍NoSQL数据库是一种非关系型数据库,它的特点是可以存储非结构化的数据,并且可以处理大量的数据。HBase是一个分布式、可扩展的列式存储系统,它是基于Google的Bigtable设计的。HBase是一个开源的NoSQL数据库,它的核心功能是提供高性能的随机读写访问。在本文中,我们将对比HBase与其他NoSQL数据库,例如Redis、MongoDB、Cass...
文章浏览阅读819次。MongoDB连接失败记录_edentialmechanisn-scram-sha-1
文章浏览阅读470次。mongodb抽取数据到ES,使用ELK内部插件无法获取数据,只能试试monstache抽取mongodb数据,但是monstache需要mongodb replica set 模式才能采集数据。############monstache-compose文件。#replicas set 启动服务。# 默认备份节点不能读写,可以设置。# mydb指的是需要同步的数据库。#登录主mongodb初始化rs。#primary 创建用户。# ip地址注意要修改。# ip地址注意要修改。_monstache csdn
文章浏览阅读913次,点赞4次,收藏5次。storage:fork: trueadmin登录切换数据库注意: use 代表创建并使用,当库中没有数据时默认不显示这个库删除数据库查看表清单> show tables # 或者 > show collections表创建db.createCollection('集合名称', [options])table1字段类型描述capped布尔(可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。_mongodb5
文章浏览阅读862次。Centos7.9设置MongoDB开机自启(超全教程,一条龙)_mongodb centos开机启动脚本
文章浏览阅读1.3k次,点赞6次,收藏21次。NoSQL数据库使用场景以及架构介绍
文章浏览阅读856次,点赞21次,收藏20次。1.背景介绍1. 背景介绍NoSQL数据库是一种非关系型数据库,它的设计目标是为了解决传统关系型数据库(如MySQL、Oracle等)在处理大量不结构化数据方面的不足。NoSQL数据库可以处理大量数据,具有高性能、高可扩展性和高可用性。但是,与关系型数据库不同,NoSQL数据库没有固定的模式,数据结构也不一定是表格。在NoSQL数据库中,数据存储和查询都是基于键值对、列族、图形等不同的...
文章浏览阅读416次。NoSQL定义:非关系型、分布式、开放源码和具有横向扩展能力的下一代数据库。由c++编写的开源、高性能、无模式的基于分布式文件存储的文档型数据库特点:高性能、高可用性、高扩展性、丰富的查询支持、可替换已完场文档某个指定的数据字段应用场景:社交场景:使用mongodb存储用户信息游戏场景:用户信息,装备积分物流场景:订单信息,订单状态场景操作特点:数据量大;读写操作频繁;价值较低的数据,对事物性要求不高开源、c语言编写、默认端口号6379、key-value形式存在,存储非结构化数据。_nosql
文章浏览阅读1.5k次,点赞3次,收藏2次。Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: Failed to create socket. at redis.clients.jedis.DefaultJedisSocketFactory.createSocket(DefaultJedisSocketFactory.java:110) at redis.clients.jedis.Connection.connect(Conne_redis.clients.jedis.exceptions.jedisconnectionexception: failed to create so
文章浏览阅读6.5k次,点赞3次,收藏12次。readAnyDatabase(在所有数据库上都有读取数据的权限)、readWriteAnyDatabase(在所有数据库上都有读写数据的权限)、userAdminAnyDatabase(在所有数据库上都有管理user的权限)、dbAdminAnyDatabase(管理所有数据库的权限);:clusterAdmin(管理机器的最高权限)、clusterManager(管理和监控集群的权限)、clusterMonitor(监控集群的权限)、hostManager( 管理Server);_mongodb创建用户密码并授权
文章浏览阅读593次。Redis是一个基于内存的键值型NoSQL数据库,在实际生产中有着非常广泛的用处_搭建本地redis
文章浏览阅读919次。Key 的最佳实践[业务名]:[数据名]:[id]足够简短:不超过 44 字节不包含特殊字符Value 的最佳实践:合理的拆分数据,拒绝 BigKey选择合适数据结构Hash 结构的 entry 数量不要超过 1000(默认是 500,如果达到上限则底层会使用哈希表而不是 ZipList,内存占用较多)设置合理的超时时间批量处理的方案:原生的 M 操作Pipeline 批处理注意事项:批处理时不建议一次携带太多命令。Pipeline 的多个命令之间不具备原子性。_redis高级实战
文章浏览阅读1.2k次。MongoDB 递归查询_mongodb数据库 递归
文章浏览阅读1.2k次。通过实际代码例子介绍:如何通过MongoTemplate和MongoRepository操作数据库数据_springboot操作mongodb
文章浏览阅读687次,点赞7次,收藏2次。首先欢迎大家阅读此文档,本文档主要分为三个模块分别是:Redis的介绍及安装、RedisDesktopManager可视化工具的安装、主从(哨兵)模式的配置。_redis 主从配置工具
文章浏览阅读764次。天下武功,无坚不摧,唯快不破!我的名字叫 Redis,全称是 Remote Dictionary Server。有人说,组 CP,除了要了解她外,还要给机会让她了解你。那么,作为开发工程师的你,是否愿意认真阅读此心法抓住机会来了解我,运用到你的系统中提升性能。我遵守 BSD 协议,由意大利人 Salvatore Sanfilippo 使用 C 语言编写的一个基于内存实现的键值型非关系(NoSQL)..._redis 7.2 源码
文章浏览阅读2k次。MongoDB 的增删改查【1】_mongodb $inc