RabbitMQ支持的消息模型

news2024/11/19 12:44:20

  • RabbitMQ基础
  • RabbitMQ支持的消息模型

一、第一种模型(直连)

我们将用Java编写两个程序,发送单个消息的生成者和接收消息并打印出来的消费者。
在下图,“P”是生成者,“C”消费者。中间框是一个队列RabbitMQ保留的消息缓冲区 。

首先构建一个Maven项目,然后引入依赖。

<!-- 导入rabbitmq原生依赖-->
<dependency>
  <groupId>com.rabbitmq</groupId>
  <artifactId>amqp-client</artifactId>
  <version>5.10.0</version>
</dependency>
定义生产者
import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @author db
* @version 1.0
* @description Provider 生产者代码
* @since 2022/12/29
*/
public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {

        //        // 1.创建连接工厂
        //        ConnectionFactory connectionFactory = new ConnectionFactory();
        //        // 2.设置连接属性
        //        connectionFactory.setHost("192.168.137.120");
        //        connectionFactory.setPort(5672);
        //        connectionFactory.setVirtualHost("/");
        //        connectionFactory.setUsername("admin");
        //        connectionFactory.setPassword("123456");
        //        connectionFactory.setHandshakeTimeout(60000);
        //
        //        // 3.从连接工厂获得连接
        //        Connection connection = connectionFactory.newConnection();

        // 从工具类中获得连接
        Connection connection = RabbitMqUtil.getConnection();
        // 4.从连接中获得channel
        Channel channel = connection.createChannel();
        // 5.声明队列queue存储消息

        /**
         * 参数s:队列名称 如果队列不存在就自动创建
         * 参数b:用来定义队列特性是否要持久化 true 持久化队列  false 不持久化
         * 参数b1: exclusive 是否独占队列  true 独占队列 false 不独占
         * 参数b2:autoDelete 是否在消费完成后自动删除队列 true 自动删除 false 不自动删除
         * 参数5:额外附加参数
         *
         */
        channel.queueDeclare("hello",true,false,false,null);

        // 7.发送消息给中间件
        // 参数1:交换机名称 参数2:队列名称 参数3:传递消息的额外设置 参数4:
        channel.basicPublish("","hello", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello rabbitmq".getBytes());

        System.out.println("消息发送成功");


        //        // 8.关闭连接
        //        channel.close();
        //        connection.close();

        RabbitMqUtil.closeConnectionAndChannel(channel,connection);
    }
}

执行发送,这个时候可以在web控制台查看到这个队列queue的信息。

定义消费者

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author db
 * @version 1.0
 * @description Consumer  消费者
 * @since 2022/12/29
 */
public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
//        ConnectionFactory connectionFactory = new ConnectionFactory();
//        connectionFactory.setHost("192.168.137.120");
//        connectionFactory.setPort(5672);
//        connectionFactory.setVirtualHost("/");
//        connectionFactory.setUsername("admin");
//        connectionFactory.setPassword("123456");
//        connectionFactory.setHandshakeTimeout(60000);
//
//        // 创建连接
//        Connection connection = connectionFactory.newConnection();

        // 从工具类中获得连接
        Connection connection = RabbitMqUtil.getConnection();
        // 创建信道
        Channel channel = connection.createChannel();

        // 消费者成功消费时的回调
        DeliverCallback deliverCallback = (consumerTag,message) ->{
            System.out.println(new String(message.getBody()));
        };

        // 消费者取消消费时的回调
        CancelCallback callback = consumerTag ->{
            System.out.println("消费者取消消费接口的回调");
        };

        // 参数1:消费队列的名称
        // 参数2:消息的自动确认机制(已获得消息就通知MQ消息已被消费)true 打开 false 关闭
        // 参数3:
        channel.basicConsume("hello",true,deliverCallback,callback);

//        channel.close();
//        connection.close();
    }
}


工具类的包装

package com.duan.rabbitmq.utils;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 * @author db
 * @version 1.0
 * @description RabbitMqUtil
 * @since 2023/1/2
 */
public class RabbitMqUtil {

    // 定义提供连接对象的方法
    public static Connection getConnection(){
        try{
            // 1.创建连接工厂
            ConnectionFactory connectionFactory = new ConnectionFactory();
            // 2.设置连接属性
            connectionFactory.setHost("192.168.137.120");
            connectionFactory.setPort(5672);
            connectionFactory.setVirtualHost("/");
            connectionFactory.setUsername("admin");
            connectionFactory.setPassword("123456");

            connectionFactory.setHandshakeTimeout(60000);
            return connectionFactory.newConnection();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    // 关闭连接通道和关闭连接的工具方法
    public static void closeConnectionAndChannel(Channel channel,Connection connection){
        try{
            if(channel !=null){
                channel.close();
            }
            if(connection != null){
                connection.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

报连接超时错误

**解决方案:**原因是连接超时,加超时时间。

maevn项目设置超时时间:factory.setHandshakeTimeout\(60000\)

二、第二种模型(work quene)

work queues被称为任务队列(Task queues)。当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。此时就可以使用work 模型: 让多个消费者绑定到一个队列,共同消费队列中的消息。 队列中的消息一旦消费,就会消失,因此任务是不会被重复执行的。

  • P:生产者
  • C1:消费者1
  • C2:消费者2
定义生成者
package com.duan.rabbitmq.work;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Producer
 * @since 2023/3/24
 */
public class Producer {

    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();
        /**
         * 声明队列queue存储信息
         * 参数1: 队列名称
         * 参数2: 用来定义队列是否要持久化
         * 参数3: exclusion 是否是独占队列
         * 参数4: autoDelete 是否再消费完成后自动删除队列
         * 参数5: 额外附加参数
         */
        channel.queueDeclare("work",true,false,false,null);

        for(int i = 0; i<10; i++){
            // 参数1:交换机名称 参数2:队列名称 参数3:消息传递的额外设置
            channel.basicPublish("","work",null,(i+"work").getBytes());
        }
        RabbitMqUtil.closeConnectionAndChannel(channel,connection);
    }
}
定义消费者1
package com.duan.rabbitmq.work;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Consumer1
 * @since 2023/3/24
 */
public class Consumer1 {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMqUtil.getConnection();
        // 创建信道
        Channel channel = connection.createChannel();

        // 消费者消费成功时的回调
        channel.queueDeclare("work",true,false,false,null);
        channel.basicConsume("work",true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{
                System.out.println("消费者1: "+new String(body));
            }
        });
        RabbitMqUtil.closeConnectionAndChannel(channel,connection);
    }
}
定义消费者2
package com.duan.rabbitmq.work;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Consumer1
 * @since 2023/3/24
 */
public class Consumer2 {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMqUtil.getConnection();
        // 创建信道
        Channel channel = connection.createChannel();

        // 消费者消费成功时的回调
        channel.queueDeclare("work",true,false,false,null);
        channel.basicConsume("work",true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{
                try{
                    Thread.sleep(2000);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("消费者2: "+new String(body));
            }
        });
        RabbitMqUtil.closeConnectionAndChannel(channel,connection);
    }
}

rabbitMQ讲按照顺序将每个消息发给下一个使用者,每个消费者都会收到相同数量的消息。
测试结果

消息确认机制

前面看到的是所有的消费者均分消息,会有一个问题,如果一个消费者宕机了,会出现消息丢失现场,希望当出现消费者宕机时,消息被另一个消费者消费,也就是多劳多得生产者代码。

package com.duan.rabbitmq.work;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Producer
 * @since 2023/3/24
 */
public class Producer {

    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();
        /**
         * 声明队列queue存储信息
         * 参数1: 队列名称
         * 参数2: 用来定义队列是否要持久化
         * 参数3: exclusion 是否是独占队列
         * 参数4: autoDelete 是否再消费完成后自动删除队列
         * 参数5: 额外附加参数
         */
        channel.queueDeclare("work",true,false,false,null);

        for(int i = 0; i<20; i++){
            // 参数1:交换机名称 参数2:队列名称 参数3:消息传递的额外设置
            channel.basicPublish("","work",null,(i+"work").getBytes());
        }

        RabbitMqUtil.closeConnectionAndChannel(channel,connection);

    }
}

生成者1

package com.duan.rabbitmq.work;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Consumer3
 * @since 2023/11/27
 */
public class Consumer3 {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMqUtil.getConnection();
        // 创建信道
        Channel channel = connection.createChannel();

        channel.basicQos(1); // 每次只消费一个消息
        // 消费者消费成功时的回调
        channel.queueDeclare("work",true,false,false,null);
        channel.basicConsume("work",false,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{
                System.out.println("消费者1: "+new String(body));

                // 手动确认,参数1:消息标识  参数2:每次确认1个
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });

    }
}

生成者2

package com.duan.rabbitmq.work;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Consumer4
 * @since 2023/11/27
 */
public class Consumer4 {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMqUtil.getConnection();
        // 创建信道
        Channel channel = connection.createChannel();

        channel.basicQos(1);  // 每次消费一个消息
        // 消费者消费成功时的回调
        channel.queueDeclare("work",true,false,false,null);
        channel.basicConsume("work",false,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{
                try{
                    Thread.sleep(2000);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("消费者2: "+new String(body));
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });


    }
}

测试结果

三、第三种模型(Fanout)

广播模式下:发送消息流程是可以有多个消费者每个消费者都有自己的队列(queue)每个队列都要绑定交换机(exchange)生成者发送消息,只能发送到交换机,交换机决定把消息发给哪个队列,生成者无法决定交换机把消息发给绑定过的所有队列,队列的消费者都能拿到消息,一条消息可以被多个消费者消费。

生产者
package com.duan.rabbitmq.fanout;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Provider
 * @since 2023/11/28
 */
public class Provider {
    public static void main(String[] args) throws IOException {

        // 获取连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 将通道声明交换机  参数1:交换机名称 参数2:交换机类型
        channel.exchangeDeclare("logs","fanout");

        // 发送消息
        channel.basicPublish("logs","",null,"fanout type message".getBytes());

        // 释放资源
        RabbitMqUtil.closeConnectionAndChannel(channel,connection);

    }
}
消费者1
package com.duan.rabbitmq.fanout;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Customer1
 * @since 2023/11/28
 */
public class Customer1 {
    public static void main(String[] args) throws IOException {
        // 获得连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 通道绑定交换机
        channel.exchangeDeclare("logs","fanout");

        // 绑定临时队列
        String queue = channel.queueDeclare().getQueue();

        // 绑定交换机和队列
        channel.queueBind(queue,"logs","");

        // 消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1: "+new String(body));
            }
        });
    }
}
消费者2
package com.duan.rabbitmq.fanout;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Customer1
 * @since 2023/11/28
 */
public class Customer2 {
    public static void main(String[] args) throws IOException {
        // 获得连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 通道绑定交换机
        channel.exchangeDeclare("logs","fanout");

        // 绑定临时队列
        String queue = channel.queueDeclare().getQueue();

        // 绑定交换机和队列
        channel.queueBind(queue,"logs","");

        // 消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者2: "+new String(body));
            }
        });
    }
}
消费者3
package com.duan.rabbitmq.fanout;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Customer1
 * @since 2023/11/28
 */
public class Customer3 {
    public static void main(String[] args) throws IOException {
        // 获得连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 通道绑定交换机
        channel.exchangeDeclare("logs","fanout");

        // 绑定临时队列
        String queue = channel.queueDeclare().getQueue();

        // 绑定交换机和队列
        channel.queueBind(queue,"logs","");

        // 消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者3: "+new String(body));
            }
        });
    }
}
测试结果

四、第四种模型(Routing)

fanout模式中,一条消息,会被所有绑定的队列都能消费,但是,在某些场景下,希望不同的消息被不同的队列消费,就需要Direct类型的exchange

Direct模型下:队列与交换机的绑定,不是任意绑定的,而是要指定一个RoutingKey(路由key)消息的发送方在向Exchange发送消息时,也必须指定消息的 RoutingKeyExchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息。

生产者
package com.duan.rabbitmq.direct;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Provider
 * @since 2023/11/28
 */
public class Provider {
    public static void main(String[] args) throws IOException {
        // 建立连接
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        channel.exchangeDeclare("logs_direct","direct");

        String routingKey = "error";
        channel.basicPublish("logs_direct",routingKey,null,("这是direct模型发布的基于route key: ["+routingKey+"] 发送的消息").getBytes());

        RabbitMqUtil.closeConnectionAndChannel(channel,connection);
    }
}
消费者1
package com.duan.rabbitmq.direct;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Consumer1
 * @since 2023/11/28
 */
public class Consumer1 {
    public static void main(String[] args) throws IOException {
        // 获得连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 通道绑定交换机
        channel.exchangeDeclare("logs_direct","direct");

        // 绑定临时队列
        String queue = channel.queueDeclare().getQueue();

        // 绑定交换机和队列
        channel.queueBind(queue,"logs_direct","error");

        // 消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1: "+new String(body));
            }
        });
    }
}
消费者2
package com.duan.rabbitmq.direct;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Consumer1
 * @since 2023/11/28
 */
public class Consumer2 {
    public static void main(String[] args) throws IOException {
        // 获得连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 通道绑定交换机
        channel.exchangeDeclare("logs_direct","direct");

        // 绑定临时队列
        String queue = channel.queueDeclare().getQueue();

        // 绑定交换机和队列
        channel.queueBind(queue,"logs_direct","info");
        channel.queueBind(queue,"logs_direct","error");
        channel.queueBind(queue,"logs_direct","warning");

        // 消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1: "+new String(body));
            }
        });
    }
}
测试结果

routingKeyinfo时,消费者1和消费者2结果如下:

routingKeyerror时,消费者1和消费者2结果如下:

五、第五种模型(topic)

Topic类型的ExchangeDirect相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定BindingKey 的时候使用通配符!BindingKey 一般都是有一个或多个单词组成,多个单词之间以.分割,例如: item.insert通配符规则:

  • #:匹配一个或多个词
  • *:匹配不多不少恰好1个词

举例:

  • item.#:能够匹配item.spu.insert 或者 item.spu
  • item.*:只能匹配item.spu
生产者
package com.duan.rabbitmq.topic;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Provider
 * @since 2023/11/30
 */
public class Provider {

    public static void main(String[] args) throws IOException {
        //获取连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        //声明交换机以及交换机类型 topic
        channel.exchangeDeclare("topics","topic");

        //发布消息
        String routekey = "save.user.delete";

        channel.basicPublish("topics",routekey,null,("这里是topic动态路由模型,routekey: ["+routekey+"]").getBytes());

        //关闭资源
        RabbitMqUtil.closeConnectionAndChannel(channel,connection);

    }


}
消费者1
package com.duan.rabbitmq.topic;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Customer1
 * @since 2023/11/30
 */
public class Customer1 {
    public static void main(String[] args) throws IOException {
        // 获得连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 通道绑定交换机
        channel.exchangeDeclare("topics","topic");

        // 绑定临时队列
        String queue = channel.queueDeclare().getQueue();

        // 绑定交换机和队列
        channel.queueBind(queue,"topics","*.user.*");

        // 消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1: "+new String(body));
            }
        });
    }
}
消费者2
package com.duan.rabbitmq.topic;

import com.duan.rabbitmq.utils.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @author db
 * @version 1.0
 * @description Customer1
 * @since 2023/11/30
 */
public class Customer2 {
    public static void main(String[] args) throws IOException {
        // 获得连接对象
        Connection connection = RabbitMqUtil.getConnection();
        Channel channel = connection.createChannel();

        // 通道绑定交换机
        channel.exchangeDeclare("topics","topic");

        // 绑定临时队列
        String queue = channel.queueDeclare().getQueue();

        // 绑定交换机和队列
        channel.queueBind(queue,"topics","*.user.#");

        // 消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1: "+new String(body));
            }
        });
    }
}
测试结果

代码地址:https://gitee.com/duan138/practice-code/tree/dev/rabbitmq-java

六、总结

以上就是rabbitMQ中常见的几种模式,这些模型通过交换机(Exchange)和队列(Queue)的不同组合与绑定方式实现。本文只是初步了解RabbitMQ相关知识。后续会讲解怎么在SpringBoot中应用。


改变你能改变的,接受你不能改变的,关注公众号:程序员康康,一起成长,共同进步。

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

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

相关文章

十一、完善增删改查操作

分为两部分&#xff1a; 第一部分在解析xml的时候&#xff0c;要解析select、insert、update、delete的语句&#xff0c;封装成mapperStatement放到configuration中 第二部分在执行的时候&#xff0c;执行到代理类的invoke方法&#xff0c;然后在MapperMethod判断执行增删改查…

dns域名解析服务和bond网卡

目录 dns域名解析服务 一、DNS 1、定义 2、以www.baidu.com为例 3、域名体系结构 4、DNS解析使用的协议和端口 5、dns域名解析的过程 6、dns解析的优先级 二、如何实现域名解析 1、域名解析 2、bind配置文件位置 &#xff08;一&#xff09;正向解析 &#xff08;…

基础数学-求平方根(easy)

一、问题描述 二、实现思路 1.题目不能直接调用Math.sqrt(x) 2.这个题目可以使用二分法来缩小返回值范围 所以我们在left<right时 使 mid (leftright)/21 当mid*mid>x时&#xff0c;说明right范围过大&#xff0c;rightright-1 当mid*mid<x时&#xff0c;说明left范…

圈子社区系统源码 开源 多端圈子社区论坛系统 社区圈子管理系统

介绍 圈子论坛小程序&#xff0c;是一款为用户提供交流分享、互动沟通的平台。在这个小程序中&#xff0c;用户可以轻松地加入各种不同兴趣爱好的圈子&#xff0c;与志同道合的朋友们交流互动。圈子论坛小程序不仅仅是一个简单的社交工具&#xff0c;更是一个打开新世界大门的…

CUDA12.0 + cuDNN9.0.0安装

目录 1. 查看显卡支持的CUDA版本1.1 指令查看1.2 控制面板查看 2. 安装CUDA2.1 下载2.2 安装2.3 验证 3. 安装cuDNN3.1 下载3.2 安装3.2 验证 1. 查看显卡支持的CUDA版本 1.1 指令查看 打开cmd输入nvidia-smiDriver Version表示显卡驱动版本&#xff0c;CUDA Version表示支持…

三维前端开发项目中Threejs的THREEScene函数详解

THREE.Scene函数用于创建一个场景对象。大家好&#xff01;艾斯视觉作为在IT行业中负责ui设计和前端开发环节的服务商很高兴能在这里与大家共同探讨学习&#xff1a;场景是 Three.js 中所有图形元素的容器&#xff0c;它可以包含相机、光源、几何体、材质等。 创建场景对象的基…

【control_manager】无法加载,gazebo_ros2_control 0.4.8,机械臂乱飞

删除URDF和SDRF文件中的特殊注释#, !,&#xff1a; xacro文件解析为字符串时出现报错 一开始疯狂报错Waiting for /controller_manager node to exist 1717585645.4673686 [spawner-2] [INFO] [1717585645.467015300] [spawner_joint_state_broadcaster]: Waiting for /con…

【UE5.1 角色练习】11-坐骑——Part1(控制大象移动)

前言 在上一篇&#xff08;【UE5.1 角色练习】10-物体抬升、抛出技能 - part2&#xff09;基础上创建一个新的大象坐骑角色&#xff0c;并实现控制该角色行走的功能。 效果 步骤 1. 在商城中下载“African Animal Pack”资产和“ANIMAL VARIETY PACK”资产导入工程中 2. 复…

猫熊超市管理系统

import java.util.Scanner;//增加商品类 //此类用来录入一个商品的所有属性&#xff0c;并作为结果对其返回 public class Add {public Goods add1() {Scanner scanner new Scanner(System.in);System.out.println("请输入商品名称");String name scanner.next();S…

处理一对多的映射关系

一对多关系&#xff0c;比如说根据id查询一个部门的部门信息及部门下的员工信息 在Dept类中先添加List emps属性 1、collection DeptMapper.xml文件中 <resultMap id"deptAndEmpResultMap" type"Dept"><id property"did" column&qu…

【c++设计模式17】行为模式2:命令模式(Command Pattern)

【c设计模式17】行为模式2&#xff1a;命令模式&#xff08;Command Pattern&#xff09; 一、定义二、适用场景三、过程四、命令模式类图五、C示例代码六、使用注意事项 原创作者&#xff1a;郑同学的笔记 原创地址&#xff1a;https://zhengjunxue.blog.csdn.net/article/det…

面试官:你知道 ES6 的 生成器 Generator 吗?小明:说起 Generator,还得从我上次去餐馆点餐开始说起。

讲故事学 Generator 这篇文章先说一个小故事&#xff0c;作为引子&#xff0c;然后系统讲讲 Generator。阅读这篇文章的话&#xff0c;需要一些前置知识&#xff1a;起码用过 Promise 和 async/await。 小故事 吃货小明去了一家菜鸟镇非常有名的餐馆——《老三样餐馆》&…

如何修改cPanel面板的语言

本周有一个客户&#xff0c;购买Hostease的主机&#xff0c; 客户购买的是Linux虚拟主机&#xff0c;带cPanel面板的。询问我们的在线客服&#xff0c;他想修改cPanel面板的默认语言。Hostease虚拟主机默认英语&#xff0c;客户想要修改成中文。 在cPanel面板中修改语言设置是一…

3 - 大的国家(高频 SQL 50 题基础版)

3.大的国家 -- 查询属性&#xff1a;国家名称、人口和面积 select name,population,area fromWorld where area>3000000 OR population>25000000;

React中常见的面试题

本文是结合实践中和学习技术文章总结出来的笔记(个人使用),如有雷同纯属正常((✿◠‿◠)) 喜欢的话点个赞,谢谢! 1. 约束性组件与非约束性组件 1.1. 非约束性组件 非约束性组件其实就是不能控制状态的组件,比如: <input type"text" defaultValue"123&qu…

一个思维狂赚20万+?揭秘电商平台隐藏的流量认知!

你想要的流量&#xff0c;资源&#xff0c;人脉&#xff0c;都已经有人为你准备&#xff0c;你只需要找到拥有这些资源的人。对于流量和信息&#xff0c;也是一样&#xff0c;你想找的客户和产品&#xff0c;都已经有人为你准备在淘宝、拼多多等电商平台&#xff0c;你只需要找…

【踏雪无痕的痕六】——数学中有意思的问题

一、背景介绍 提出一个问题往往比解决一个问题更有意义&#xff0c;因为提出一个问题相当于提出了一个思考问题的维度&#xff1b;而解决一个问题是沿着这个维度将已有的知识串起来的过程 三、过程 1.数人数你会吗&#xff1f; 小名再第10位&#xff0c;小李再第15位&#…

VRTK4.0学习——(二)

手柄绑定以及显示 1.导入CameraRigs.UnityXRPluginFramework 和 CameraRigs.TrackedAlias 预设&#xff0c;将CameraRigs.UnityXRPluginFramework拖入CameraRigs.TrackedAlias的Elements中即可&#xff0c;运行软件后即可看到手柄了 注&#xff1a;如果无法看到手柄&#xff…

AI降痕工具使用指南:如何有效降低AIGC疑似度

随着人工智能技术的突飞猛进&#xff0c;AI生成内容&#xff08;AIGC&#xff09;已被广泛用于学术论文撰写中&#xff0c;提高效率同时也带来了原创性的挑战。面对日益严格的学术审查&#xff0c;一个突出的问题是&#xff1a;使用AI代写的论文能否通过内容检测&#xff1f;因…

《精品生活》万方普刊投稿发表简介

《精品生活》杂志是由国家新闻出版总署批准&#xff0c;南方出版传媒股份有限公司主管&#xff0c;广东大沿海出版工贸有限公司主办&#xff0c;广东精品生活杂志社出版的综合性文化期刊。主要栏目&#xff1a;教学研究、艺术教育、文化广角、民族文化、理论前沿、综合论坛。 刊…