【Java中间件】RocketMQ

news2024/11/26 22:31:55

RocketMQ

一、MQ概述

Message Queue,是一种提供消息队列服务的中间件。提供了消息生产、存储、消费全过程API的软件系统。

MQ的作用

  • 限流削峰:当用户发送超量请求时,将请求暂存,以便后期慢慢处理。如果不使用MQ暂存直接请求到业务系统中容易引起系统崩溃。
  • 异步解耦:若上游系统和下游系统为同步调用,会大大降低系统的吞吐量和并发量。MQ层实现两个系统之间的异步调用
  • 数据收集:分布式系统会产生海量数据流,如业务日志、监控数据、用户行为。针对这些数据流采集汇总,进行大数据分析。

主流应用的MQ产品

  • Kafka:Scala/Java语言开发。特点是高吞吐量,但会丢数据,常用与大数据领域的实时计算、日志采集等场景。不遵循任何MQ协议,使用自研协议。
  • RocketMQ:Java语言开发。经过数年阿里双十一考验,性能与稳定性非常高,功能全面。不遵循任何MQ协议,使用自研协议。开源版不如云上版(阿里商业版)

MQ常见协议

  • JMS:Java Messaging Service。Java平台上有关MOM(Message Orientated Middleware)的技术规范。他便于Java应用程序的消息交换,提供标准的接口简化开发。ActiveMQ时典型实现

  • STOMP:Streaming Text Orientated Message Protocol。是一种MOM的简单文本协议。STOMP提供一个可互操作的连接格式,允许 客户端与任意STOMP消息代理进行交互。ActiveMQ时典型实现

  • AMQP:Advanced Message Queuing Protocol。一个提供统一消息服务的应用层标准,是应用层协议的一个开放标准。RabbitMQ是典型实现

  • MQTT:Message Queueing Telemetry Transport。IBM开发的一个即时通讯协议(二进制协议),主要用于服务器和低功耗IoT设备之间的通信

二、基本概念

主题(Topic):表示一类消息的集合(可以理解为消息的类型),每个消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。一个生产者可以同时发送多种Topic消息,而一个消费者只能接收一种Topic消息

标签(Tag):用于快速过滤消息

三、Linux部署RocketMQ服务

1、在官网下载编译好的二进制压缩包,版本5.0.0即可,上传到Linux中

2、进行解压

3、配置环境变量ROCKETMQ_HOME和NAMESRV_ADDR

在这里插入图片描述

4、配置bin目录下的runserver.sh,根据实际情况修改JVM的内存参数

5、配置bin目录下的runbroker.sh,根据实际情况修改JVM的内存参数

6、执行nohup命令后台运行RocketMQ服务(nameserver必须先启动,broker需要再nameserver上注册)

# 启动nameserver
nohup bin/mqnamesrv &	

# 启动broker
nohup bin/mqbroker -c [confFile] & # -c可指定加载的配置文件,默认为conf/broker.conf

# 查看日志rocketmq是否成功启动
tail nohup.out	

# 查看进程
jps		

# 停止broker
sh bin/mqshutdown broker

# 停止namesrv
sh bin/mqshutdown namesrv

7、执行命令测试(rocketmq提供的测试样例,生产者会发送一千条消息)

bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

8、执行命令测试(rocketmq提供的测试样例,消费者会接受一千条消息)

bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

四、RocketMQ API

生产者同步发送消息

public void test_SyncProducer() throws MQClientException {
    DefaultMQProducer producer = new DefaultMQProducer("producer_group_name");
    //设置注册服务的ip地址的端口
    producer.setNamesrvAddr(RocketMQConstant.NAME_SRV_ADDR);
    //启动生产者
    producer.start();


    for(int i=0; i<3; i++){
        try {
            // 封装消息,设置topic,tag(用于消息快速过滤),消息数据
            Message message = new Message(
                "TopicTest",
                "TagA",
                "ID04287777",
                ("Hello, RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
            //同步发送消息并获取发送结果,producer从broker获取发送结果
            SendResult sendResult = producer.send(message);

            System.out.println(sendResult);

            Thread.sleep(1500);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    producer.shutdown();
}

生产者异步发送消息

public void test_AsyncProducer() throws Exception{
    DefaultMQProducer producer = new DefaultMQProducer(RocketMQConstant.PRODUCER_GROUP_NAME);
    producer.setNamesrvAddr(RocketMQConstant.NAME_SRV_ADDR);
    producer.start();
    producer.setRetryTimesWhenSendAsyncFailed(0);

    int messageCount = 10;

    final CountDownLatch countDownLatch = new CountDownLatch(messageCount);

    for(int i=0; i<messageCount; i++){
        final int index = i;
        // 封装消息,设置topic,tag(用于消息快速过滤),消息数据
        Message message = new Message(
            "TopicTest",
            "TagA",
            "ID04287777",
            ("Hello, RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));

        // 异步发送消息,若broker有响应会调用SendCallback中的方法
        producer.send(message, new SendCallback() {
            public void onSuccess(SendResult sendResult) {
                countDownLatch.countDown();
                System.out.println("    Send Message "+ index +" OK: "+sendResult);
            }

            public void onException(Throwable throwable) {
                countDownLatch.countDown();
                System.out.println("    Send Message "+ index +" Exception: "+throwable);
            }
        });

        //单向发送
        producer.sendOneway(message);

        System.out.println("Message "+index+" send done");
    }
    //在100条消息发送完后关闭
    countDownLatch.await(5, TimeUnit.SECONDS);
    producer.shutdown();
}

生产者单向发送消息

public void test_OneWayProducer() throws Exception{
    DefaultMQProducer producer = new DefaultMQProducer(RocketMQConstant.PRODUCER_GROUP_NAME);
    producer.setNamesrvAddr(RocketMQConstant.NAME_SRV_ADDR);
    producer.start();
    producer.setRetryTimesWhenSendAsyncFailed(0);

    int messageCount = 10;

    final CountDownLatch countDownLatch = new CountDownLatch(messageCount);

    for(int i=0; i<messageCount; i++){
        final int index = i;
        // 封装消息,设置topic,tag(用于消息快速过滤),消息数据
        Message message = new Message(
            "TopicTest",
            "TagA",
            "ID04287777",
            ("Hello, RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));

        //单向发送
        producer.sendOneway(message);

        System.out.println("Message "+index+" send done");
    }
    //在100条消息发送完后关闭
    countDownLatch.await(5, TimeUnit.SECONDS);
    producer.shutdown();
}

消费者推模式

public static void test_PushConsumer() throws Exception{
    DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_group_name");

    consumer.setNamesrvAddr(RocketMQConstant.NAME_SRV_ADDR);
    consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
    //消费者订阅的消息topic和tag(subExpression,*表示任意)
    consumer.subscribe("TopicTest", "*");
    consumer.registerMessageListener(new MessageListenerConcurrently() {
        public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
            System.out.println("Receive New Message : "+list);
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
    });

    consumer.start();

    System.out.println("Consumer Start...");
}

消费者拉模式

不同于推模式消费者,拉模式下需要手动管理消息队列MessageQueue和偏移量offset的映射关系。但是最新的LitePullConsumer底层源码已经实现对mq和offset的管理,比较方便。

//拉模式消费者
public static void test_LitePullConsumer() throws Exception{
    DefaultLitePullConsumer litePullConsumer = new DefaultLitePullConsumer(RocketMQConstant.CONSUMER_GROUP_NAME);
    litePullConsumer.setNamesrvAddr(RocketMQConstant.NAME_SRV_ADDR);
    litePullConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
    litePullConsumer.subscribe("TopicTest", "*");
    litePullConsumer.start();

    try {
        while(true){
            List<MessageExt> messageExts = litePullConsumer.poll();
            System.out.printf("%s%n", messageExts);
        }
    }finally {
        litePullConsumer.shutdown();
    }
}

RocketMQ传递对象,对象所属类需要实现序列化接口,并且将对象转换为字节数组存入消息体中。

顺序消息

保证消息的局部有序(其中几条消息的有序,不一定是全部消息都要有序),以防止受到网络传输的影响。

实现原理

生产者将一组有序的消息一次发到同一个MessageQueue中(依靠队列的特点保证局部有序性)。消费者消费完一个MessageQueue的消息后才会去消费下一个MessageQueue的消息。

public class OrderProducer {
    public static void main(String[] args) {
        DefaultMQProducer producer = new DefaultMQProducer(WanfengConstant.PRODUCER_GROUP_NAME);
        try {
            producer.setNamesrvAddr(WanfengConstant.NAMESRV_ADDR);
            producer.start();
            for(int i=0; i<5; i++){
                //用于指定顺序的id
                int orderId = i;

                for(int j=0; j<5; j++){
                    Message message = new Message(
                            WanfengConstant.ORDER_TOPIC,
                            "order_"+orderId,
                            "KEY"+orderId,
                            ("order_"+orderId+" step "+j).getBytes(RemotingHelper.DEFAULT_CHARSET)
                    );
                    //实现消息队列选择器对象,使同一个orderId的消息发送到同一个消息队列
                    SendResult sendResult = producer.send(
                            message,
                            new MessageQueueSelector() {
                                @Override
                                public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                                    Integer id = (Integer) arg;
                                    int index = id % mqs.size();
                                    return mqs.get(index);
                                }
                            },
                            orderId
                    );
                    System.out.printf("%s%n", sendResult);
                }
            }

        }catch(Exception e){
            e.printStackTrace();
            producer.shutdown();
        }

    }
}
public class OrderConsumer {
    public static void main(String[] args) {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(WanfengConstant.CONSUMER_GROUP_NAME);
        consumer.setNamesrvAddr(WanfengConstant.NAMESRV_ADDR);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        try {
            consumer.subscribe(WanfengConstant.ORDER_TOPIC, "*");
            //实现顺序消息监听者接口
            consumer.registerMessageListener(new MessageListenerOrderly() {
                @Override
                public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
                    context.setAutoCommit(true);
                    for(MessageExt messageExt : msgs){
                        System.out.println("Receive Message: " + new String(messageExt.getBody()));
                    }
                    return ConsumeOrderlyStatus.SUCCESS;
                }
            });
            consumer.start();
            System.out.println("Consumer Start...");
        } catch (Exception e) {
            e.printStackTrace();
            consumer.shutdown();
        }
    }
}

广播消息

生产者发送的消息推送给所有group的消费者

实现原理:将消费者设置MessageModel为广播模式。

public class BroadcastConsumer {
    public static void main(String[] args) {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(WanfengConstant.CONSUMER_GROUP_NAME);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        //设定消息模式为广播
        consumer.setMessageModel(MessageModel.BROADCASTING);
        try {
            consumer.subscribe(WanfengConstant.ARCHIVE_TOPIC, "*");
            consumer.registerMessageListener(new MessageListenerConcurrently() {
                @Override
                public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                    msgs.forEach(messageExt -> {
                        Archive archive = (Archive) WanfengObjectUtil.bytesToObject(messageExt.getBody());
                        System.out.println("Receive Message : "+archive.getId());
                    });
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
            });
            consumer.start();
            System.out.println("Broadcast Consumer Start...");
        }catch (Exception e){
            e.printStackTrace();
            consumer.shutdown();
        }
    }
}

若指定MessageModel为CLUSTERING,则生产者发送的消息会随机指定消费者消费。

延迟消息

顾名思义就是消息发送到broker时延迟指定的时间后再发送给消费者。常用于定时发送

过滤消息

过滤消息通过tag实现,在消费者端指定过滤的tag即可。

//消费者订阅tag1或tag2的消息
consumer.subscribe("TopicTest", "tag1 || tag2");

在RocketMQ中,消费者指定过滤条件后,将其上推到Broker中,在Broker中进行tag过滤,以减少网络IO,但同时也增加了Broker的繁忙。

事务消息

在这里插入图片描述

public class TransactionProducer {
    public static void main(String[] args) {
        TransactionMQProducer producer = new TransactionMQProducer(WanfengConstant.PRODUCER_GROUP_NAME);
        TransactionListener transactionListener = new TransactionListener() {
            @Override
            public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
                System.out.println("[WANFENG-INFO] TransactionProducer.executeLocalTransaction(): 执行成功...");

                String tags = msg.getTags();
                if (StringUtils.contains(tags, "TagA")) {
                    //消息提交(发送出去)
                    return LocalTransactionState.COMMIT_MESSAGE;
                } else if (StringUtils.contains(tags, "TagB")) {
                    //消息回滚(丢掉消息)
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                } else {
                    return LocalTransactionState.UNKNOW;
                }
            }

            @Override
            public LocalTransactionState checkLocalTransaction(MessageExt msg) {
                System.out.println("[WANFENG-INFO] TransactionProducer.checkLocalTransaction(): 执行成功...");
                String tags = msg.getTags();
                if (StringUtils.contains(tags, "TagC")) {
                    return LocalTransactionState.COMMIT_MESSAGE;
                } else {
                    return LocalTransactionState.UNKNOW;
                }
            }
        };
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                5,
                100, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3)
        );
        producer.setExecutorService(executorService);
        producer.setTransactionListener(transactionListener);
        try {
            producer.start();
        } catch (Exception e) {
            e.printStackTrace();
        }

        String[] tags = new String[]{"TagA", "TagB", "TagC"};
        CountDownLatch countDownLatch = new CountDownLatch(9);
        for (int i = 0; i < 9; i++) {
            try {
                Message message = new Message("TopicTest", tags[i % tags.length], "Key" + i, ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
                SendResult sendResult = producer.sendMessageInTransaction(message, null);
                System.out.println(sendResult);
                Thread.sleep(1000);
                countDownLatch.countDown();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            producer.shutdown();
        }


    }
}

ACL权限控制

ACL对用户对Topic资源的访问权限进行控制

在pom依赖中引入acl的依赖包

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-acl</artifactId>
    <version>5.0.0</version>
</dependency>

在服务端的conf/broker.conf文件,添加配置,开启acl

aclEnable=true

在服务端的conf/plain_acl.yml文件,配置具体权限规则(热加载,不需要重启mq)

accounts:
  - accessKey: RocketMQ #用户名
    secretKey: 12345678 #密码
    whiteRemoteAddress:   #访问地址白名单
    admin: false	#是否为管理员(管理员可以访问所有Topic)
    defaultTopicPerm: DENY #默认Topic访问权限
    defaultGroupPerm: SUB  #默认组权限
    topicPerms:		#Topic对应的权限,若这里找不到则采用defaultTopicPerm
      - topicA=DENY 	
      - topicB=PUB|SUB
      - topicC=SUB
    groupPerms:
      # the group should convert to retry topic
      - groupA=DENY
      - groupB=PUB|SUB
      - groupC=SUB

在创建生产者对象时需加入RPCHook(acl的用户信息)

public class AclProducer {

    private static final String ACL_ACCESS_KEY = "RocketMQ";

    private static final String ACL_SECRET_KEY = "12345678";

    /**
     * 通过用户名和密码获取RPCHook
     * @return
     */
    public static RPCHook getAclRPCHook(){
        return new AclClientRPCHook(new SessionCredentials(ACL_ACCESS_KEY, ACL_SECRET_KEY));
    }

    public static void main(String[] args) throws MQClientException, InterruptedException {
        //创建生产者时加入用户信息,即RPCHook
        DefaultMQProducer producer = new DefaultMQProducer(WanfengConstant.PRODUCER_GROUP_NAME, getAclRPCHook());
        producer.setNamesrvAddr(WanfengConstant.NAMESRV_ADDR);
        producer.start();

        for (int i = 0; i < 20; i++) {
            try {
                Message message = new Message(
                        "TopicTest",
                        WanfengConstant.TAGS_NAME,
                        ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /*消息体转换成二进制数组*/
                );
                SendResult sendResult = producer.send(message);
                System.out.printf("%s%n", sendResult);
            } catch (Exception e) {
                e.printStackTrace();
                Thread.sleep(1000);
            }
        }
    }
}

消息轨迹

Producer,Consumer,Broker处理消息的相关信息

消息轨迹的实现原理是MQ把消息轨迹都往RMQ_SYS_TRACE_TOPIC的Topic中放

在Broker端配置文件开启消息轨迹

traceTopicEnable=true

创建生产者时指定enableMsgTrace参数为true,开启消息轨迹。也可以指定customizedTraceTopic参数来自定义消息轨迹的Topic。

public class TraceProducer {
    public static void main(String[] args) throws MQClientException {
        //指定enableMsgTrace参数为true,开启消息轨迹
        DefaultMQProducer producer = new DefaultMQProducer(WanfengConstant.PRODUCER_GROUP_NAME, true);
        producer.setNamesrvAddr(WanfengConstant.NAMESRV_ADDR);
        producer.start();

        for (int i = 0; i < 20; i++) {
            try {
                Message message = new Message(
                        "TopicTest",
                        WanfengConstant.TAGS_NAME,
                        ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /*消息体转换成二进制数组*/
                );
                SendResult sendResult = producer.send(message);
                System.out.printf("%s%n", sendResult);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/794036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

抖音小店开通指南:轻松打造个人电商王国

抖音小店是抖音推出的一个电商平台&#xff0c;为用户提供了开店、上传商品、管理店铺等功能&#xff0c;让用户可以在抖音上直接进行购物。下面不若与众就来谈谈抖音小店的开通的几个步骤&#xff1a; 1. 注册抖音账号&#xff1a;首先&#xff0c;你需要在抖音上注册一个账号…

什么是Koala?

Koala 介绍 koala 是一个前端预处理器语言图形编译工具&#xff0c;支持 Less、Sass、Compass、CoffeeScript&#xff0c;帮助 web 开发者更高效地使用它们进行开发。跨平台运行&#xff0c;完美兼容 windows、linux、mac。 关键特性 多语言支持 支持 Less、Sass、CoffeeSc…

使用PHP实现登录注册功能的完整指南

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。多年电商行业从业经验&#xff0c;对系统架构&#xff0c;数据分析处理等大规模应用场景有丰富经验。 &#x1f3c6;本文已收录于PHP专栏&#xff1a;PHP…

无涯教程-jQuery - trigger( event, data )方法函数

trigger(event&#xff0c;[data])方法在每个匹配的元素上触发一个事件。 触发事件不仅限于基于浏览器的事件&#xff0c;还可以触发向bind注册的自定义事件。 trigger( event, [data] ) - 语法 selector.trigger( event, [data] ) 这是此方法使用的所有参数的描述- event…

【技术干货】工业级BLE5.2蓝牙模块SKB378 使用教程,AT指令集

SKB378是一个高度集成的蓝牙5.2模组&#xff0c;可用来在2.4GHz ISM频段内做高速率、短距离无线通信。工业级标准&#xff0c;支持主从模式(1主对8从)&#xff0c;支持串口透传&#xff0c;AT指令控制&#xff0c;且支持AoA蓝牙高精度室内定位&#xff0c;模组内部集成32位ARM …

存储过程——存储函数

1.存储函数 存储函数的弊端&#xff0c;必须要有返回值&#xff0c;能使用存储函数的地方也能使用存储过程。 案例需求 create function fun1(n int) returns int deterministic begindeclare total int default 0;while n>0 doset total : total _n;set n : n - 1;end …

activemq消息中间件

ActiveMQ消息中间件详解 下载地址&#xff1a;https://activemq.apache.org/activemq-5015009-release 1、MQ的产品种类 1.1、消息中间件的特性/共同特性/共同维度 Kafka&#xff08;大数据专用、由java/scala编写&#xff09; API发送和接收MQ的高可用性MQ的集群和容错配置…

【uni-app2.0】实现登录页记住密码功能

使用uni-app的uni.setStorageSync()和uni.getStorageSync()方法来存储和读取密码 在登录页中添加一个记住密码的u-checkbox选项&#xff0c;并在data里面添加一个rememberPwd的布尔值&#xff0c;在每次点击记住密码change的时候来记录用户的选择 <u-checkbox-group place…

Spring Boot 自定义启动画面

文章目录 自定 Banner获取属性设置颜色实操关闭 Banner参考 我们启动项目的之后&#xff0c;会在控制台上看到类似下面的画面&#xff1a; 那么&#xff0c;我们是否可以自定义呢&#xff1f; 肯定可以 自定 Banner 上面的截图信息就是 Banner 信息&#xff0c;我们可以在项目…

JavaScript |(二)JavaScript自定义对象及函数 | 尚硅谷JavaScript基础实战

学习来源&#xff1a;尚硅谷JavaScript基础&实战丨JS入门到精通全套完整版 文章目录 &#x1f4da;自定义对象&#x1f407; 对象的分类&#x1f407;对象基本操作&#x1f407;对象的属性&#x1f407;基本和引用数据类型&#x1f407;对象字面量 &#x1f4da;函数&#…

边写代码边学习之全连接Dense

1. 全连接原理 全连接神经网络&#xff08;Fully Connected Neural Network&#xff09;是一种最基本的神经网络结构&#xff0c;也被称为多层感知器&#xff08;Multilayer Perceptron&#xff0c;MLP&#xff09;。其原理是模拟人脑神经元之间的连接方式&#xff0c;通过多个…

AI视频监控综合管理平台EasyCVR多分屏默认播放协议的配置优化

智能视频监控平台EasyCVR可拓展性强、开放度高&#xff0c;既能作为业务平台使用&#xff0c;也能作为视频能力层被调用和集成。视频监控综合管理平台兼容度高&#xff0c;支持自由调用、支持与第三方集成。在AI能力的接入上&#xff0c;TSINGSEE青犀视频平台可支持AI智能分析网…

SD NAND【商业】

SD NAND【商业】 前言版权推荐SD NAND外观NAND与TF卡的区别雷龙CS SD NAND(贴片式TF卡)性能体验及应用 最后 前言 2023-7-23 16:20:19 因为本人对硬件了解不是很多&#xff0c;所以该篇参考自官方文档。 以下内容源自《【商业】》 仅供学习交流使用 版权 禁止其他平台发布…

linux 学成之路(基础篇)(二十三)MySQL服务(下)

目录 一、用户权限管理概述 二、用户权限类型 三、用户赋予权限 四、删除权限 五、删除用户 一、用户权限管理概述 数据库用户权限管理是数据库系统中非常重要的一个方面&#xff0c;它用于控制不同用户访问和操作数据库的权限范围。数据库用户权限管理可以保护敏感数据和…

QT项目打包成软件进行发布的三种方式

目录 一、打包成绿色便携版 二、打包成单文件版 三、打包成可安装版本 本教程对应的IDE是Qt Creater。 保证绿色便携版能正常运行才能够打包成单文件版本和可安装版本。 一、打包成绿色便携版 特点&#xff1a;给别人发送的时候需要先制作成一个压缩包文件&#xff0c;解…

【javaSE】 递归与汉诺塔详解

目录 递归 生活中的故事 递归的概念 递归的必要条件 示例 递归执行过程分析 代码示例 递归练习 练习一 执行过程图 练习二 执行过程图 练习三 执行流程图 ​编辑斐波那契数列 汉诺塔 汉诺塔问题解析 总结 递归 关于递归博主在C语言部分也进行了详解&#xff…

Rabbit MQ整合springBoot

一、pom依赖二、消费端2.1、application.properties 配置文件2.2、消费端核心组件 三、生产端3.1、application.properties 配置文件2.2、生产者 MQ消息发送组件四、测试1、生产端控制台2、消费端控制台 一、pom依赖 <dependency><groupId>org.springframework.boo…

【lesson4】linux权限

文章目录 权限权限是什么&#xff1f;对人权限对角色和文件权限权限修改改属性改人 权限 权限分为两种对人权限和对角色和文件的权限 权限是什么&#xff1f; 在脑海中我们对权限有一定的理解那么权限的定义到底是什么我们却说不出来&#xff0c;接下来我们来举个例子介绍一…

黑客和网络安全学习资源,限时免费领取,点这里!

统计数据显示&#xff0c;目前我国网安人才缺口达140万之多… 不管你是网络安全爱好者还是有一定工作经验的从业人员 不管你是刚毕业的行业小白还是想跳槽的专业人员 都需要这份超级超级全面的资料 几乎打败了市面上90%的自学资料 并覆盖了整个网络安全学习范畴 来 收藏它&…

MySQL基础(三)用户权限管理

目录 前言 一、概述 二、用户权限类型 1.CREATE 2.DROP 三、用户赋权 例子 四、权限删除 例子 五、用户删除 例子 总结 前言 关于MySQL的权限简单的理解就是MySQL允许你做你权利以内的事情&#xff0c;不可以越界。MySQL服务器通过权限表来控制用户对数据库的访问&…