分布式NoSQL列存储数据库Hbase Java API(三)

简介: 分布式NoSQL列存储数据库Hbase Java API(三)

分布式NoSQL列存储数据库Hbase(三)

知识点01:课程回顾

  1. Hbase使用场景
  • 集群管理:定时调度管理的脚本
  • 定时调度:Azkaban、Oozie、Linux Crontab
  • Hbase脚本
  • 将Hbase命令写入一个文件
  • hbase shell运行文件即可
  • 测试开发:Hbase命令
  • DDL
  • list_namespace/create_namespace
  • create/list/desc
  • DML
  • put:插入、更新
  • 插入:每次是为每行插入一列
  • 更新:通过插入数据来代替了更新,用于提高性能
  • 语法
put 表 rowkey    列族:列    值
  • delete:删除数据
  • delete:删除列
  • deleteall:删除行
  • truncate:清空表
  • get:获取某个rowkey的数据
  • 优点:查询数据最快的方式,根据rowkey进行查询
  • rowkey是Hbase中的唯一索引
  • 缺点
  • get最多返回一个rowkey的所有列
  • 语法
get 表名    rowkey    【列族:列】
  • scan:查询符合条件的数据
  • 优点:返回需要的多条Hbase的数据
  • 缺点:很多情况下是不走索引【不能根据rowkey进行检索】
  • 语法
scan 表名
scan 表名 + Filter
  • 生产开发:JavaAPI
  • Connection:连接对象
  • Configuration:配置管理对象
  • HbaseAdmin:Hbase管理员对象:用于实现DDL操作

知识点02:课程目标

  1. Hbase JavaAPI实现DML操作【重点内容】
  • put:数据的写入或者更新
  • get:查询数据
  • delete:删除数据
  • scan:扫描数据
  • Filter:过滤器
  1. Hbase存储设计【掌握原理】
  • 表、RegionServer关系?
  • 表的分布式如何实现的?
  • Region的划分规则?
  • 数据如何决定进入哪个分区哪?
  • 分区内部是如何存储数据的?

知识点03:Java API:DML:Table

  • 需求:通过JavaAPI实现对Hbase的DML操作
  • 分析
  • step1:构建连接对象
  • step2:构建Table对象
  • 所有的DML操作,必须构建一个表的对象
  • 实现
//todo:1-构建一个连接对象
Configuration conf = HBaseConfiguration.create();
//指定Hbase集群的服务端地址:给定ZK的地址
conf.set("hbase.zookeeper.quorum","node1:2181,node2:2181,node3:2181");
Connection conn = ConnectionFactory.createConnection(conf);
//todo:2-所有的DML必须构建一个Table表的对象
//构建一个表的对象
TableName tbname = TableName.valueOf("itcast:t1");
Table table = conn.getTable(tbname);
  • 总结
  • step1:先构建一个连接对象:Connection
  • step2:根据所做的操作决定构建哪种对象
  • DDL:HbaseAdmin
  • DML:Table

知识点04:Java API:DML:Put

  • 需求:JavaAPI实现往Hbase表中写入数据
put   表   rowkey    列族:列    值
  • 分析
  • step1:Hbase中实现put操作,需要构建Put对象
  • step2:为Put对象添加列族、列名、值
  • step3:对表执行put操作
  • 实现
/**
     * 用于实现使用Put插入数据到表中:put   表   rowkey    列族:列    值
     * @param table
     */
    private void putData(Table table) throws IOException {
        //step1:构建Put对象,必须指定插入的rowkey的数据
        Put put = new Put(Bytes.toBytes("20201001_888"));
        //step2:初始化put,添加列族、列、值
        put.addColumn(
                Bytes.toBytes("basic"),//指定列族
                Bytes.toBytes("name"),//指定列的名称
                Bytes.toBytes("laoba")//指定列的值
        );
        //step3:让表执行put操作
        table.put(put);     
    }
  • 总结[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a57OCTc7-1616631335573)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318084424081.png)]
  • Put对象:专门用于往Hbase写入数据的对象
  • 指定Rowkey,添加列族、列、值信息
  • table.put

知识点05:Java API:DML:Get

  • 需求:JavaAPI实现从Hbase表中读取某个Rowkey的数据
get 表名  rowkey  【列族,列】
  • 分析
  • step1:Hbase中实现get操作,需要构建Get对象
  • step2:为Get对象添加列族、列名
  • step3:对表执行get操作,获取返回值,打印输出
table.get(Get)
  • 实现
/**
     * 使用Get查询Hbase表中的数据:get 表名 rowkey  【列族,列】
     * @param table
     */
    private void getData(Table table) throws IOException {
        //step1:构建Get对象,必须指定Rowkey
        Get get = new Get(Bytes.toBytes("20201001_888"));
        //step2:可选的,配置Get需要的参数:列族、列
//        get.addColumn()//指定获取某一列的数据
//        get.addFamily()//指定获取某个列族的数据
        //step3:表执行get操作
        Result result = table.get(get);//Get操作的返回值为Result类型对象
        /**
         * 迭代输出Result对应的rowkey中的每一列的数据,一个Rowkey包含很多列,循环迭代输出每一列的数据
         *      Result:一个Result对象就是一个Rowkey的数据
         *      Cell:一个Cell代表一个rowkey中一列的数据
         *      一个Result对象中会包含多个Cell
         */
        for(Cell cell : result.rawCells()){
            //输出每一列Cell对象中的数据:20201001_888  column=basic:age, timestamp=1616029665232, value=20
            System.out.println(
                    Bytes.toString(CellUtil.cloneRow(cell)) //获取这一列的rowkey,转换为字符串类型
                    +"\t"+
                    Bytes.toString(CellUtil.cloneFamily(cell)) //获取这一列的列族,转换为字符串类型
                    +"\t"+
                    Bytes.toString(CellUtil.cloneQualifier(cell)) //获取这一列的名称,转换为字符串类型
                    +"\t"+
                    Bytes.toString(CellUtil.cloneValue(cell)) //获取这一列的值,转换为字符串类型
                    +"\t"+
                    cell.getTimestamp() //获取时间戳
            );
        }
    }
  • 总结
  • step1:先构建Get
  • step2:执行Get,得到返回值
  • Result:一个Result就是一个Rowkey的数据,包含一个Cell数组
  • Cell:一个Cell就是一列的数据

知识点06:Java API:DML:Delete

  • 需求:JavaAPI实现从Hbase表删除某个Rowkey的某列的数据
  • 分析
  • step1:Hbase中实现delete操作,需要构建Delete对象
  • step2:为Delete对象添加列族、列名
  • step3:对表执行delete操作
table.delete(Delete)
  • 实现
/**
     * 删除某个Rowkey的某一列的数据:delete  表名     rowkey      列族:列
     * @param table
     */
    private void deleteData(Table table) throws IOException {
        //step1:构建删除对象
        Delete delete = new Delete(Bytes.toBytes("20201001_888"));
        //step2:添加删除配置
//        delete.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name")); //只删除最新版本
        delete.addColumns(Bytes.toBytes("basic"),Bytes.toBytes("name")); //删除所有版本
        //step3:执行删除
        table.delete(delete);
    }
  • 总结
  • step1:构建Delete对象
  • step2:根据需求调用配置方法:添加列族、列
  • step3:表对象指定delete对象即可

知识点07:Java API:DML:Scan

  • 需求:JavaAPI实现从Hbase表中读取所有数据
scan 表
scan 表 + filter
  • 分析
  • step1:Hbase中实现scan操作,需要构建Scan对象
  • step2:对表执行scan操作
  • step3:获取返回值,取出每个Rowkey的数据,打印输出
  • 实现
/**
     * 通过Scan,进行Hbase表的数据查询:scan 表
     * @param table
     */
    private void scanData(Table table) throws IOException {
        //step1:构建Scan对象
        Scan scan = new Scan();
        //step2:执行scan:返回值是ResultScanner,包含了多个Rowkey的数据
        ResultScanner rsScan = table.getScanner(scan);
        /**
         *      ResultScanner:包含多个Rowkey的数据,包含了多个Result对象:Iterator<Result>
         *      Result:一个Rowkey的数据,包含了这个Rowkey多列的数据:Cell[]
         *      Cell :一列的数据
         */
        //step3:打印数据
        //先获取每个rowkey
        for(Result rs:rsScan){
            //直接输出当前rowkey的值
            System.out.println(Bytes.toString(rs.getRow()));
            //再获取每个rowkey中的每一列
            for(Cell cell : rs.rawCells()){
                //输出每一列Cell对象中的数据:20201001_888  column=basic:age, timestamp=1616029665232, value=20
                System.out.println(
                        Bytes.toString(CellUtil.cloneRow(cell)) //获取这一列的rowkey,转换为字符串类型
                                +"\t"+
                                Bytes.toString(CellUtil.cloneFamily(cell)) //获取这一列的列族,转换为字符串类型
                                +"\t"+
                                Bytes.toString(CellUtil.cloneQualifier(cell)) //获取这一列的名称,转换为字符串类型
                                +"\t"+
                                Bytes.toString(CellUtil.cloneValue(cell)) //获取这一列的值,转换为字符串类型
                                +"\t"+
                                cell.getTimestamp() //获取时间戳
                );
            }
            System.out.println("----------------------------------------------------------------------");
        }
    }
  • 总结
  • step1:先构建Scan对象
  • step2:执行Scan操作
  • step3:返回值
  • ResultScanner:包含多个Rowkey的数据的集合
  • Iter《Result》
  • Result:一个Rowkey的数据
  • Cell[]
  • Cell:一列的数据

知识点08:Java API:DML:Filter

  • 需求:JavaAPI实现从Hbase表中根据条件读取部分
  • 需求1:查询2021年1月和2月的数据
  • 需求2:查询2021年的所有数据
  • 需求3:查询所有age = 20的数据
  • 需求4:查询所有数据的name和age这两列
  • 需求5:查询所有年age = 20的人的name和age
  • 分析
  • Rowkey的设计:时间【年月日】+id
  • Rowkey整体有序
  • 前缀匹配
  • 需求1
  • StartRow = 》202101
  • 包含
  • StopRow = 》202103
  • 不包含
  • 需求2
  • 方案一:使用startrow = 2021,stoprow = 2022
  • 方案二:使用Filter:PrefixFilter,Rowkey的前缀过滤器[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MfZFeVn-1616631335575)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318103200422.png)]
  • 构建过滤器,指定Rowkey前缀
  • Scan加载过滤器,返回所有符合rowkey前缀的过滤器
  • 需求三:查询所有age = 20的数据
where age = 20
  • Filter:列值过滤器
  • SingleColumnValueFilter:对某一列的值进行过滤
  • 指定列值过滤器:哪个列族下的哪一列的值等于什么值
  • scan加载过滤器
  • 需求4:查询所有数据的name和age这两列
select name ,age from table
  • Filter:多列前缀过滤器
  • MutipleColumnPrefixFIlter:用于将每条数据中指定的列过滤出来
  • 指定需要过滤哪些列
  • scan加载过滤器即可
  • 需求5:查询所有年age = 20的人的name和age
select name,age from table where age = 20
  • 支持组合过滤器:FilterList
  • 列的过滤:MutipleColumnPrefixFIlter
  • 列值过滤:SingleColumnValueFilter
  • 构建两个过滤器,将两个过滤器组合放入过滤器集合
  • Scan加载过滤器集合
  • 实现
  • 批量写入数据到Hbase
/**
     * 批量写入数据到Hbase
     * @param table
     */
    private void putListData(Table table) throws IOException {
        //step1:构建Put对象,一个Put对象用于表示一个Rowkey写入的数据
        Put put1 = new Put(Bytes.toBytes("20210101_001"));
        Put put2 = new Put(Bytes.toBytes("20210201_002"));
        Put put3 = new Put(Bytes.toBytes("20210301_003"));
        //step2:为Put添加这个Rowkey的每一列
        put1.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name"),Bytes.toBytes("laoda"));
        put1.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("age"),Bytes.toBytes("18"));
        put1.addColumn(Bytes.toBytes("other"),Bytes.toBytes("phone"),Bytes.toBytes("110"));
        put1.addColumn(Bytes.toBytes("other"),Bytes.toBytes("addr"),Bytes.toBytes("shanghai"));
        put2.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name"),Bytes.toBytes("laoer"));
        put2.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("age"),Bytes.toBytes("20"));
        put2.addColumn(Bytes.toBytes("other"),Bytes.toBytes("phone"),Bytes.toBytes("120"));
        put3.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name"),Bytes.toBytes("laosan"));
        put3.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("age"),Bytes.toBytes("22"));
        put3.addColumn(Bytes.toBytes("other"),Bytes.toBytes("addr"),Bytes.toBytes("beijing"));
        //step3:将多个Put封装到List中
        List<Put> puts = new ArrayList<Put>();
        puts.add(put1);
        puts.add(put2);
        puts.add(put3);
        //step4:执行PutList
        table.put(puts);
    }
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ijNYbrbY-1616631335576)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318101928785.png)]
  • 需求一:实现范围过滤
//需求一:查询2021年1月和2月的数据
scan.withStartRow(Bytes.toBytes("202101"));
scan.withStopRow(Bytes.toBytes("202103"));
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kUtwEsEy-1616631335577)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318102604990.png)]
  • 需求二实现
//需求2:查询2021年的所有数据
Filter prefixFiter = new PrefixFilter(Bytes.toBytes("2021"));
//将过滤器加载到scan中
scan.setFilter(prefixFiter);
  • 需求三实现
//需求三:查询所有age = 20的数据
        /**
         *    * @param family name of column family
         *    * @param qualifier name of column qualifier
         *    * @param op operator
         *    * @param value value to compare column values against
         */
        Filter valueFilter = new SingleColumnValueFilter(
                Bytes.toBytes("basic"),//指定列族
                Bytes.toBytes("age"),//指定列
                CompareOperator.EQUAL,//指定比较器类型
                Bytes.toBytes("20")  //比较的值
        );
        //将过滤器加载到scan中
        scan.setFilter(valueFilter);
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sP5MLfRe-1616631335579)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318104213375.png)]
  • 需求四实现
//需求4:查询所有数据的name和age这两列
        //构建所有需要过滤的列
        byte[][] prefixes = {
            Bytes.toBytes("name"),
            Bytes.toBytes("age")
        };
        Filter columnFilter = new MultipleColumnPrefixFilter(prefixes);
        //将过滤器加载到scan中
        scan.setFilter(columnFilter);
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vkQbO9w9-1616631335580)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318104930496.png)]
  • 需求五实现
Filter valueFilter = new SingleColumnValueFilter(
                Bytes.toBytes("basic"),//指定列族
                Bytes.toBytes("age"),//指定列
                CompareOperator.EQUAL,//指定比较器类型
                Bytes.toBytes("20")  //比较的值
        );
        //需求4:查询所有数据的name和age这两列
        //构建所有需要过滤的列
        byte[][] prefixes = {
            Bytes.toBytes("name"),
            Bytes.toBytes("age")
        };
        Filter columnFilter = new MultipleColumnPrefixFilter(prefixes);
        //需求5:查询所有age = 20的人的name和age
        //构建FIlterList
        FilterList lists = new FilterList();//MUST_PASS_ALL:and,MUST_PASS_ONE:or
        //添加过滤器
        lists.addFilter(valueFilter);
        lists.addFilter(columnFilter);
        //将过滤器加载到scan中
        scan.setFilter(lists);
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GaXWQJwf-1616631335581)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318110732471.png)]
  • 总结
  • Rowkey范围过滤:StartRow和StopRow
  • Rowkey前缀过滤:PrefixFilter
  • Rowkey中列的值的过滤:SingleColumnValueFilter
  • Rowkey中列的过滤:MultipleColumnPrefixFilter
  • 多种条件的组合过滤:FilterList

知识点09:存储设计:存储架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QFiNIbeF-1616631335582)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317190105892.png)]

  • 问题:Hbase整体如何实现数据的存储?
  • 分析

知识点10:存储设计:Table、Region、RegionServer的关系


  • 问题:客户端操作的是表,数据最终存在RegionServer中,表和RegionServer的关系是什么?
  • 分析

知识点11:存储设计:Region的划分规则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xGxSZiF6-1616631335582)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317191202582.png)]

  • 问题:一张表划分为多个Region,划分的规则是什么?写一条数据到表中,这条数据会写入哪个Region,分配规则是什么?
  • 分析

知识点12:存储设计:Region内部存储结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KRgBXSLA-1616631335583)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317191716413.png)]

  • 问题:数据在Region的内部是如何存储的?
  • 分析

知识点13:存储设计:HDFS中的存储结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10viiw3z-1616631335583)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317191754182.png)]

  • 问题:Hbase的数据在HDFS中是如何存储的?
  • 分析

egionServer的关系


  • 问题:客户端操作的是表,数据最终存在RegionServer中,表和RegionServer的关系是什么?
  • 分析

知识点11:存储设计:Region的划分规则

[外链图片转存中…(img-xGxSZiF6-1616631335582)]

  • 问题:一张表划分为多个Region,划分的规则是什么?写一条数据到表中,这条数据会写入哪个Region,分配规则是什么?
  • 分析

知识点12:存储设计:Region内部存储结构

[外链图片转存中…(img-KRgBXSLA-1616631335583)]

  • 问题:数据在Region的内部是如何存储的?
  • 分析

知识点13:存储设计:HDFS中的存储结构

[外链图片转存中…(img-10viiw3z-1616631335583)]

  • 问题:Hbase的数据在HDFS中是如何存储的?
  • 分析


相关实践学习
lindorm多模间数据无缝流转
展现了Lindorm多模融合能力——用kafka API写入,无缝流转在各引擎内进行数据存储和计算的实验。
云数据库HBase版使用教程
&nbsp; 相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情:&nbsp;https://cn.aliyun.com/product/hbase &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
9天前
|
存储 缓存 NoSQL
常见的 NoSQL 数据库有哪些?
常见的 NoSQL 数据库有哪些?
12 2
|
25天前
|
存储 SQL JSON
介绍一下RDBMS和NoSQL数据库之间的区别
【10月更文挑战第21天】介绍一下RDBMS和NoSQL数据库之间的区别
54 2
|
25天前
|
存储 SQL NoSQL
数据库技术深度探索:从关系型到NoSQL的演变
【10月更文挑战第21天】数据库技术深度探索:从关系型到NoSQL的演变
32 1
|
27天前
|
NoSQL 前端开发 MongoDB
前端的全栈之路Meteor篇(三):运行在浏览器端的NoSQL数据库副本-MiniMongo介绍及其前后端数据实时同步示例
MiniMongo 是 Meteor 框架中的客户端数据库组件,模拟了 MongoDB 的核心功能,允许前端开发者使用类似 MongoDB 的 API 进行数据操作。通过 Meteor 的数据同步机制,MiniMongo 与服务器端的 MongoDB 实现实时数据同步,确保数据一致性,支持发布/订阅模型和响应式数据源,适用于实时聊天、项目管理和协作工具等应用场景。
|
1月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
3月前
|
NoSQL Redis
基于Redis的高可用分布式锁——RedLock
这篇文章介绍了基于Redis的高可用分布式锁RedLock的概念、工作流程、获取和释放锁的方法,以及RedLock相比单机锁在高可用性上的优势,同时指出了其在某些特殊场景下的不足,并提到了ZooKeeper作为另一种实现分布式锁的方案。
112 2
基于Redis的高可用分布式锁——RedLock
|
3月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
10天前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
46 16
|
1月前
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
59 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
|
1月前
|
NoSQL Redis 数据库
计数器 分布式锁 redis实现
【10月更文挑战第5天】
48 1