Zookeeper基础和简单使用

news2024/7/6 18:19:41

安装与配置

概念

基于观察者模式设计的分布式服务管理框架,负责存储和管理大家都关心数据,然后接受观察者的注册,一单这些数据的这状态发生了变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应

特点

  1. zookeeper由一个领导者,和多个跟随者组成的集群

  2. 集群中有半数节点存活,zookeeper就可以正常服务,所以zookeeper适合安装奇数台服务器

  3. 全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据一致

  4. 更新请求顺序一致,来自同一个client的更新请求按其发送顺序依次执行

  5. 数据更新原子性:一次数据更新要么成功,要么失败

  6. 实时性,在一定时间范围内,client能读到最新数据

数据结构

Zookeeper数据模型的结构与Unix文件系统类似,整体可以看做是一棵树,每个节点可以被称作一个ZNode。每一个ZNode默认存储1M数据,每个ZNode都可以通过其路径唯一标识

应用环境

提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、负载均衡等

  • 统一命名服务

    • 在分布式环境下,需要对环境进行统一命名,便于识别,例如IP用域名命名
  • 统一配置管理

    • 一个集群中,所有节点的配置信息是一致的,比如kafka集群
    • 对配置文件修改后,希望快速同步到各个节点上
  • 统一集群管理

    • 根据节点实时做出调整,将节点信息写入zookeeper上的一个ZNode,监听这个ZNode可以获取他们实时的变化
  • 服务器节点动态上下线

    • 让服务器动态上线下线
  • 负载均衡

    • 让访问数最少的服务器去处理最新的客户端请求

安装

安装地址:阿里云镜像

放在linux内,解压

tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz 

/zookeeper/conf/zoo_example.cfg 改名为/zookeeper/conf/zoo.cfg

更改zoo.cfg配置,路径改为自己自定义的路径,避免存放为tmp文件夹

dataDir=/usr/local/zookeeper-3.7.1/zkData

启动

  • 启动服务端(bin下)
./zkServer.sh start
  • 启动客户端
./zkCli.sh
[root@localhost zookeeper-3.7.1]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.7.1/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: standalone

配置详解

  • zoo.cfg文件内的参数
#服务器leader与客户端follower心跳时间,单位毫秒
tickTime=2000   
#LF初始通信时限,初始连接最多可以承受的tickTime数量
initLimit=10
#同步通信时限,如果超过syncLimit * tickTime,leader认为Follower死掉,从服务器节点删除
syncLimit=5
#保存zookeeper内的数据
dataDir=/usr/local/zookeeper-3.7.1/zkData
#通信端口
clientPort=2181

常用命令

数据模型

  • 树形目录结构,类似Unix,拥有层次化的结构
  • 每个节点被称为ZNode,每个节点会保存自己的数据和节点信息
  • 节点拥有子节点,同时也允许少量数据存储在该节点之下
  • 节点分类
    • PERSISTENT 持久化节点
    • EPHEMERAL 临时节点 : -e
    • PERSISTENT_SEQUENTIAL 持久化顺序节点: -s
    • EPHEMERAL_SEQUENTIAL 临时顺序节点: -es

image-20230513215942762

Zookeeper 服务端

  • 启动服务
./zkSever.sh start
  • 查看状态
./zkSever.sh status
  • 停止服务
./zkSever.sh stop
  • 重启服务
./zkSever.sh restart

Zookeeper 客户端

  • 启动
/zkCli.sh -server ip:端口
  • 退出客户端
./zkClie.sh quit
  • 增加节点
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 5] create /app1 test  #创建节点app1 数据为test
Created /app1
[zk: localhost:2181(CONNECTED) 6] ls /
[app1, zookeeper]
#获取节点存放的数据
[zk: localhost:2181(CONNECTED) 9] get /app1
test
  • 给节点追加数据,使用set修改数据
[zk: localhost:2181(CONNECTED) 10] create /app2
Created /app2
[zk: localhost:2181(CONNECTED) 12] set /app2 test2
[zk: localhost:2181(CONNECTED) 15] get /app2
test2
  • 删除节点
[zk: localhost:2181(CONNECTED) 16] delete /app1
[zk: localhost:2181(CONNECTED) 17] ls /
[app2, zookeeper]
  • 删除全部,用来删除节点下有节点的情况
deleteall /app1
  • 帮助命令
help
  • 创建临时节点和顺序节点
#临时节点  生命周期维持到本次会话结束
[zk: localhost:2181(CONNECTED) 3] create -e /app1
Created /app1
[zk: localhost:2181(CONNECTED) 4] ls /
[app1, app2, zookeeper]

#顺序节点  每次建立按照顺序建立 可以容纳多个
[zk: localhost:2181(CONNECTED) 5] create -s /app3
Created /app30000000003
[zk: localhost:2181(CONNECTED) 6] ls /
[app1, app2, app30000000003, zookeeper]
[zk: localhost:2181(CONNECTED) 7] create -s /app3
Created /app30000000004
[zk: localhost:2181(CONNECTED) 8] create -s /app3
Created /app30000000005
[zk: localhost:2181(CONNECTED) 9] ls /
[app1, app2, app30000000003, app30000000004, app30000000005, zookeeper]

#创建临时顺序节点
[zk: localhost:2181(CONNECTED) 10] create -es /app3
Created /app30000000006
[zk: localhost:2181(CONNECTED) 11] ls /
[app1, app2, app30000000003, app30000000004, app30000000005, app30000000006, zookeeper]

#关闭本次会话再打开 临时节点都没了
[zk: localhost:2181(CONNECTED) 0] ls /
[app2, app30000000003, app30000000004, app30000000005, zookeeper]
  • 查看节点详细信息
[zk: localhost:2181(CONNECTED) 5] ls -s /app2
[]
cZxid = 0x9
ctime = Sat May 13 07:15:26 PDT 2023
mZxid = 0xa
mtime = Sat May 13 07:15:38 PDT 2023
pZxid = 0x9
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

JavaAPI操作

Curator介绍

是Apache Zookeeper 的 Java客户端库

常见:

  • 原生javaapi
  • ZkClient
  • Curator:目的是为了简化Zookeeper客户端的使用

Curator API

  • maven依赖
<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
<!--            <scope>test</scope>-->
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>1.18.24</version>
        </dependency>

        <!--            显示lombok日志信息-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency>
    </dependencies>

连接客户端

	@Test
    public void testConnect(){
        //重试策略 3s一次 重试10次
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000,10);
        //第一种方式
        //zkSever服务端地址和端口 多个用逗号隔开    会话超时时间(ms)     连接超时时间(ms)     重试策略
//        CuratorFramework client = CuratorFrameworkFactory.newClient(
//                "192.168.230.1:2181",
//                60 * 1000,
//                15 * 1000,
//                retry);
//        client.start();

        //第二种方式
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("192.168.230.1:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retry)
                .namespace("zkServer")          //名称空间 以后做的任何事情 会将命名的设置为根目录
                .build();
        client.start();
    }

操作节点

优化连接

	CuratorFramework client = null;
    @Before
    public void connect(){
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000,10);
        client = CuratorFrameworkFactory.builder()
                .connectString("192.168.230.1:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retry)
                .namespace("zkServer")          //名称空间 以后做的任何事情 会将命名的设置为根目录
                .build();
        client.start();
    }

    /**
     * 释放资源
     */
    @After
    public void close(){
        if(client != null){
            client.close();
        }
    }

增加节点

 /**
     * 创建节点
     */
    @Test
    public void create() throws Exception {
 		//1.基本创建  没有指定数据,将当前客户端ip作为数据存入
        String s1 = client.create().forPath("/app1");  //  /zkServer/app1
        System.out.println(s1);

        //2.带有数据的
        String s2 = client.create().forPath("/app2","data hello".getBytes());
        System.out.println(s2);

        //3.创建临时节点 通过withMode(CreateMode.EPHEMERAL)指定类型
        String s3 = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3");
        System.out.println(s3);         //打个断点  查看客户端 可以看见app3  如果程序意外停止 app3不会被删除

        //4.创建多级节点  creatingParentsIfNeeded() 父节点不存在也可也创建
        String s4 = client.create().creatingParentsIfNeeded().forPath("/app4/p1");
        System.out.println(s4);
    }
  • 客户端结果
[zk: localhost:2181(CONNECTED) 13] ls /
[zookeeper]
#1.基本创建
[zk: localhost:2181(CONNECTED) 14] ls /
[zkServer, zookeeper] 
[zk: localhost:2181(CONNECTED) 15] ls /zkServer 
[app1]
[zk: localhost:2181(CONNECTED) 16] get /zkServer/app1 
192.168.230.10

#2.带有数据的
[zk: localhost:2181(CONNECTED) 17] ls /
[zkServer, zookeeper]
[zk: localhost:2181(CONNECTED) 18] ls /zkServer 
[app1, app2]
[zk: localhost:2181(CONNECTED) 19] get /zkServer/app2
data hello

#3.临时节点
[zk: localhost:2181(CONNECTED) 20] ls /
[zkServer, zookeeper]
[zk: localhost:2181(CONNECTED) 21] ls /zkServer 
[app1, app2]
#debug还没关闭
[zk: localhost:2181(CONNECTED) 22] ls /zkServer 
[app1, app2, app3]
# debug 关闭之后
[zk: localhost:2181(CONNECTED) 23] ls /zkServer 
[app1, app2]

#4多级节点
[zk: localhost:2181(CONNECTED) 24] ls /zkServer 
[app1, app2, app4]
[zk: localhost:2181(CONNECTED) 25] ls /zkServer/app4
[p1]
[zk: localhost:2181(CONNECTED) 26] 

查询节点

/**
     * 查询节点
     */
    @Test
    public void query() throws Exception {
        //1.查询数据
        byte[] bytes = client.getData().forPath("/app1");
        System.out.println(new String(bytes));  //192.168.230.10

        //2.查询子节点
        List<String> list = client.getChildren().forPath("/");
        list.forEach(System.out::println);    //app1 app2 app4

        //3.查询状态
        Stat status = new Stat();
        //将查询到的结果封装给status对象
        client.getData().storingStatIn(status).forPath("/app1");
        System.out.println(status);     //33,33,1684034344358,1684034344358,0,0,0,0,14,0,33 懒蛋程序员
    }

修改节点

  	@Test
    public void update() throws Exception {
        //1.修改数据,但是可能发生并发问题
//        client.setData().forPath("/app1","testSet".getBytes());

        //2.CAS修改 版本号法
        Stat status = new Stat();
        client.getData().storingStatIn(status).forPath("/app1");
        int version = status.getVersion();
        System.out.println(version);   //1
        //根据查询出的version进行修改,如果修改的version和内部的version不匹配,将会报错
        client.setData().withVersion(version).forPath("/app1","haha".getBytes());
    }
  • 客户端
[zk: localhost:2181(CONNECTED) 28] ls -s /zkServer/app1
[]
cZxid = 0x21
ctime = Sat May 13 20:19:04 PDT 2023
mZxid = 0x44
mtime = Sun May 14 00:30:25 PDT 2023
pZxid = 0x21
cversion = 0
dataVersion = 2					#此处为2,上面的为1 操作过之后会+1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4

删除节点

 	 /**
     * 删除
     * @throws Exception e
     */
	@Test
    public void delete() throws Exception {
        //1.普通删除
        client.delete().forPath("/app1");

        //2.删除全部(带子节点)
        client.delete().deletingChildrenIfNeeded().forPath("/app4");

        //3.一定成功的删除  防止网络原因没有成功删除
        client.delete().guaranteed().forPath("/app3");

        //4.回调  inBackground()
        client.delete().guaranteed().inBackground(new BackgroundCallback(){
            @Override
            public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                System.out.println("我被删除啦");
                System.out.println(curatorFramework);
                System.out.println(curatorEvent);
            }
        }).forPath("/app3");
    }
  • 控制台结果
我被删除啦
org.apache.curator.framework.imps.CuratorFrameworkImpl@1eda9cdc
CuratorEventImpl{type=DELETE, resultCode=-101, path='/app3', name='null', children=null, context=null, stat=null, data=null, watchedEvent=null, aclList=null, opResults=null}

Watch事件监听

zookeeper允许用户在指定节点上注册一些watcher,并且在一些特定事件触发的时候,zookeeper服务端将会将事件通知到感兴趣的客户端上,该机制是zookeeper实现分布式协调服务的重要特性。

根据watch机制可以实现发布订阅功能,可以让多个订阅者同时监听一个对象,当一个对象自身状态变化时,会通知所有订阅者。

zookeeper原生支持通过注册watch来进行事件监听,但是其使用并不是很方便,需要自己实现,比较繁琐

curator引入了cache来实现对zookeeper服务端事件的监听

zookeeper提供了三种watcher

  • NodeCache:只是监听某一个特定的节点
  • PathChildrenCache:监控一个ZNode的字节点
  • TreeCache:可以监控整个树上的所有节点,类似PathChildrenCache和NodeCache的组合
  1. NodeCache普通节点监听
	/**
     * 给指定节点 注册监听
     */
    @Test
    public void NodeCacheTest() throws Exception {
        //1.创建NodeCache对象
        NodeCache nodeCache = new NodeCache(client, "/app1");
        //2.注册监听
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("节点变化了");
                //对之后的操作进行记录
                //获取修改节点后的数据
                byte[] data = nodeCache.getCurrentData().getData();
                System.out.println(new String(data));
            }
        });
        //3.开启监听  true表示,开启监听,将会一次性加载缓存内的数据
        nodeCache.start(true);

        while (true){

        }
    }
  1. PathChildrenCache监听子节点
/**
     * 监听某个节点的所有子节点们 只能监听儿子们 孙子们和自己不监听
     */
    @Test
    public void PathChildrenCacheTest() throws Exception {
        //true 是否缓存状态信息
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/app2",true);

        //绑定监听
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                System.out.println("子节点变化");
                System.out.println(curatorFramework);
                System.out.println(pathChildrenCacheEvent);
                //监听子节点数据变更
                PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
                //特别对修改数据感兴趣
                if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    //getData() 是获取孩子数据 getData().getData() 是获得具体孩子修改数据
                    byte[] data = pathChildrenCacheEvent.getData().getData();
                    System.out.println(new String(data));
                }
            }
        });
        pathChildrenCache.start();

        while (true);
    }

新增节点和修改节点

[zk: localhost:2181(CONNECTED) 47] create /zkServer/app2/p2
Created /zkServer/app2/p2

#控制台输出
子节点变化
org.apache.curator.framework.imps.WatcherRemovalFacade@d013913
PathChildrenCacheEvent{type=CHILD_ADDED, data=ChildData{path='/app2/p2', stat=101,101,1684052651069,1684052651069,0,0,0,0,0,0,101
, data=null}}


[zk: localhost:2181(CONNECTED) 49] set /zkServer/app2/p2 aaa

#控制台输出
子节点变化
org.apache.curator.framework.imps.WatcherRemovalFacade@d013913
PathChildrenCacheEvent{type=CHILD_UPDATED, data=ChildData{path='/app2/p2', stat=101,103,1684052651069,1684052677940,1,0,0,0,3,0,101
, data=[97, 97, 97]}}
aaa    #因为if只对修改感兴趣
  1. TreeCache,上面两个合体
/**
     * 监听自己和子节点变化
     */
    @Test
    public void TreeCacheTest() throws Exception {
        //1.创建
        TreeCache treeCache = new TreeCache(client, "/app2");

        //2.注册监听
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
                System.out.println("子节点变化");
                System.out.println(curatorFramework);
                System.out.println(treeCacheEvent);
                //监听子节点数据变更
            }
        });

        //3.开启
        treeCache.start();
        while (true);
    }

分布式锁

除了使用mysql、redis实现分布式锁以外,现在更多的使用zookeeper实现分布式锁

原理

**核心思想:**使用临时顺序节点,当客户端需要获取锁,则创建节点(不能有多个客户端创建同一个节点),使用完锁之后删除该节点

  • 客户端获取锁的时候,在lock节点下创建临时顺序节点

  • 然后获取lock下面所有子节点,客户端获取所有子节点之后,如果发现自己创建的子节点序号最小,那么就任务该客户端获取到了锁,使用完之后,将该节点删除

  • 如果自己不是最小的,说明自己还没获取到锁,那么客户端需要找到比自己小的那个节点,同时对其注册事件监听,监听删除事件

  • 如果发现比自己小的那个节点被删除,则客户端的watcher会收到通知,此时再判断自己创建的节点是否是lock序列最小的,如果是获取锁,不是重复第三步

模拟12306售票

Curator中有五种锁案例:

  • InterProcessSemaphorMutex:分布式排他锁(非可重入)
  • InterProcessMutex:分布式可重入排他锁
  • InterProcessReadWriteLock:分布式读写锁
  • InterProcessMultiLock:将多个锁作为单个实体管理的容器
  • InterProcessSemaphoreV2:共享信号量

编写案例

  • 12306类
/**
 * @author 我见青山多妩媚
 * @date 2023/5/14 0014 17:04
 * @Description TODO
 */
public class Ticket12306 implements Runnable{
    //票数
    private int tickets = 10;

    //分布式锁
    private InterProcessMutex lock;

    public Ticket12306(){
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000,10);
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("192.168.230.1:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retry)
                .build();
        client.start();
        lock = new InterProcessMutex(client,"/lock");
    }

    @Override
    public void run() {
        while (true){
            //获取锁 3s内
            try {
                lock.acquire(3, TimeUnit.SECONDS);
                if(tickets > 0){
                    System.out.println(Thread.currentThread().getName()+":"+tickets);
                    tickets--;
                }else {
                    break;
                }
            }catch (Exception e){
                e.printStackTrace();
            } finally {
                try {
                    //释放锁
                    lock.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 测试类
/**
 * @author 我见青山多妩媚
 * @date 2023/5/14 0014 16:42
 * @Description TODO
 */
public class LockTest {
    public static void main(String[] args) {
        Ticket12306 ticket = new Ticket12306();

        //创建客户端
        Thread t1 = new Thread(ticket, "携程");
        Thread t2 = new Thread(ticket, "飞猪");

        t1.start();
        t2.start();
    }
}

运行没问题,我们看客户端

[zk: localhost:2181(CONNECTED) 53] ls /
[lock, zkServer, zookeeper]
[zk: localhost:2181(CONNECTED) 54] ls /lock 
[_c_780e8659-46bd-44fa-ae1a-c6d63df66a76-lock-0000001543, _c_a1d87292-26c3-452c-b02b-f9c4cf19711e-lock-0000001542]

这里142肯定比143先获取锁,因为他小

长时间不用时,lock节点将会被自动删除

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

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

相关文章

当JS遇到加密:解密你的JS代码!

作为一名程序员&#xff0c;我们经常会遇到各种加密算法&#xff0c;比如常见的AES、RSA、MD5等等&#xff0c;但是今天我想和大家聊一聊一个日常生活中比较常见的加密方式——JavaScript加密。 在我们日常浏览网页时&#xff0c;经常会看到一些网站的JavaScript代码经过加密&…

【Redis】布隆过滤器原理与应用

文章目录 原理应用实战总结 布隆过滤器&#xff08;Bloom Filter&#xff09;是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 它的优点是空间效率和查询时间都比一般的算法要好的多&#xff…

AJAX实现搜索联想 自动补全

分析: 1.想实现联想搜索需要数据库的数据支撑,需要进行模糊查询,搜索出所有包含用户输入的关键字信息,并将这些信息都反馈到前端,简化用户输入,从而提高用户的体验。 2.为了提高用户的使用体验&#xff0c;整个页面不能全部刷新&#xff0c;需要局部刷新&#xff0c;为此需要…

Python中的各种报错-一般错误

目录 ValueError: check_hostname requires server_hostname missing 1 required positional argument: self xxx is not a package libpng warning: iCCP: cHRM chunk does not match sRGB check_hostname requires server_hostname python 安装第三方库&#xff0c;超时…

MQTTC数据桥接上云

[小 迪 导 读]&#xff1a;在工业物联网蓬勃发展的背景下&#xff0c;私有化部署已经不能满足当前的发展趋势了&#xff0c;因此dgiot在原有基础上进行创新&#xff0c;将私有化部署的区域数控一体机上的数据通过mqtt桥接的方式上传到云服务器上&#xff0c;完成数据的实时同步…

Baumer工业相机堡盟工业相机软件CameraExplorer常见功能使用说明一

Baumer工业相机堡盟工业相机软件CameraExplorer常见功能使用说明一 Baumer工业相机Baumer工业相机图像采集功能Baumer工业相机图像基本参数设置 Baumer工业相机 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、…

【前端提效】-- Chrome浏览器开发者工具使用技巧

介绍一下 DevTools 的一些好用的技巧&#xff0c;它能够很好地帮助你提高生产力和解决问题的能力。 1、打开命令行 或者使用&#xff1a;快捷键 Ctrl Shift P (Mac&#xff1a; ⌘ Shift P ) 命令行可以做很多事情&#xff0c;包括但不限于截图、更换主题等 2、控制 DevT…

暑假线上兼职:300-500元/小时,安利一个大学生也能月入8K的线上兼职

在后台经常收到这样的留言&#xff1a; 快接近暑假了&#xff0c;有没有线上兼职推荐&#xff1f; 如何提升自己的眼界和能力&#xff0c;为之后的职场铺路&#xff1f; 不知道有多少朋友是想提升自己获取资源信息的速度&#xff0c;发展自己的爱好&#xff0c;或者增加第二收入…

用友U8增加查询条件

1、检查要增加的条件是否在该表单中&#xff1b; 2、在查询条件中增加查询条件的管理方案 3、参照ID就是要参照的表 4、数据源&#xff0c;在要增加的表单数据库中查询该字段名&#xff0c;进行增加即可。 select * from purbillvouch where cpbvcode 0000000312 --PurBillV…

调用legend资源,生成地图图例

作者&#xff1a;lly 文章目录 前言一、接口详情二、具体实现三、结果展示 前言 最近很多小伙伴资源关于iServer图例的问题&#xff0c; 接下来我们就来介绍下如何使用iServer legend资源&#xff0c;生成地图图例 一、接口详情 请求示例 {"layerLegends": [{&quo…

达索的天线设计和仿真软件Antenna Magus 2023版本下载与安装配置教程

目录 前言一、Antenna Magus安装二、使用配置总结 前言 Antenna Magus软件是一款用于天线设计和仿真的软件&#xff0c;提供了一个全面的设计工具集&#xff0c;帮助工程师优化天线设计&#xff0c;同时减少设计周期。 Antenna Magus的主要特点&#xff1a; ——高级天线库&…

如何用 ChatGPT 帮你自动分析数据?

误判 好几天之前&#xff0c;我就在 ChatGPT 选单里看到了 Code Interpreter。它正在灰度测试中 —— 先给一部分用户试用&#xff0c;如果反响不错并做了一定改进&#xff0c;就能推广给更多用户。 可惜当时我没能正确理解它的含义&#xff0c;犯了一个大错误 —— 望文生义。…

ChatGPT 上线联网和插件功能;投资者看好新版搜索引擎

&#x1f680; ChatGPT 上线联网和插件功能 OpenAI宣布将在这周推出联网和插件功能&#xff0c;位于Alpha和Beta通道的ChatGPT Plus用户都可使用70多个上线的插件。 更新意味着ChatGPT将利用最新的信息和资讯为使用者提供服务。 上线的ChatGPT插件种类涵盖了行程安排助理、代…

Android开发-Android常用组件-Date Time组件

4.11 Date & Time组件 1.TextClock(文本时钟) TextClock是在Android 4.2(API 17)后推出的用来替代DigitalClock的一个控件&#xff01; TextClock可以以字符串格式显示当前的日期和时间&#xff0c;因此推荐在Android 4.2以后使用TextClock。 这个控件推荐在24进制的and…

[内网]RDP远程桌面密码凭证获取

文章目录 RDP保存凭据通过注册表查看当前主机本地连接过的目标机器记录查看当前主机保存的RDP凭据查看本地用户是否存有RDP密码文件通过密码文件获取guidMasterKey的值根据guidMasterKey找到对应Masterkey解密获取明文以上总结&#xff1a; 在授权渗透过程中&#xff0c;如果获…

PCB当中的跳线有什么作用

在PCB设计中&#xff0c;跳线是一种常见的连接方式。跳线是为了连接电路中的距离较远或无法直接连接的电路元件而设置的&#xff0c;其作用是非常重要的。在本文中&#xff0c;我们将探讨PCB中跳线的作用和应用。 一、什么是跳线 跳线是一种特殊的电路连接方式&#xff0c;它是…

EXCEL 0开头的数据处理

方法一&#xff1a;从数据库中存为csv 再新建一个EXCEL 数据——从文本/CSV 方法二&#xff1a; 在数据库里面加A&#xff0c;在EXCEL里面将A替换成 上单引号 ‘

【002】C++的关键字介绍

C的关键字介绍 引言一、关键字一览表二、数据类型相关的关键字三、存储相关的关键字四、控制语句相关的关键字总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高性能程序设计和开发&#xff0c;理论与代码实践结合&#xff0c;让世界没有难学的技术。包括C/C、Linux、M…

CentOS7搭建keepalived+DRBD+NFS高可用共享存储

一、服务器信息 IP地址 类型 主机名 操作系统 内存 磁盘 192.168.11.110 主服务器 node01 CentOS7.9 2G 系统盘20G 存储盘20G 192.168.11.111 备服务器 node02 CentOS7.9 2G 系统盘20G 存储盘20G 二、两台主机…

新王诞生!ACP世界大赛中国区总决赛超燃收官!

“夺最高的冠&#xff0c;摘最亮的星&#xff01;” 2023 Adobe Certified Professional 世界大赛中国区总决赛 冠军诞生&#xff01; 2023ACP世界大赛中国区总决赛于5月13日-5月14日在苏州西交利物浦大学举办&#xff0c;历时2天的精彩角逐&#xff0c;于今日圆满收官&…