手撸Mybatis(二)—— 配置项的获取

本专栏的源码:https://gitee.com/dhi-chen-xiaoyang/yang-mybatis。

配置项解析

在mybatis中,一般我们会定义一个mapper-config.xml文件,来配置数据库连接的相关信息,以及我们的mapperxml文件存放目录。在本章,我们会读取这些文件,将其配置信息进行解析。
因为涉及到xml的解析,因此,我们先添加dom4j的依赖,以方便后续解析xml

<dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>

mybatis-config.xml的内容如下,对于每一个环境,都有对应的数据源信息,此外,mappers标签存储的是mapper.xml文件的位置。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.102.128:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

首先,我们添加MybatisDataSource,用来记录数据源信息

package com.yang.mybatis.config;

import java.io.Serializable;

public class MybatisDataSource implements Serializable {
    private String driver;
    private String url;
    private String username;
    private String password;

    public String getDriver() {
        return driver;
    }

    public String getUrl() {
        return url;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

然后添加一个MybatisEnvironment,用来存储环境信息

package com.yang.mybatis.config;

import java.io.Serializable;

public class MybatisEnvironment implements Serializable {
    private String id;

    private MybatisDataSource mybatisDataSource;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public MybatisDataSource getMybatisDataSource() {
        return mybatisDataSource;
    }

    public void setMybatisDataSource(MybatisDataSource mybatisDataSource) {
        this.mybatisDataSource = mybatisDataSource;
    }
}

然后是MybatisConfiguration,我们读取mybatis-config.xml配置文件后,配置信息就存储在这个类中。

package com.yang.mybatis.config;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MybatisConfiguration implements Serializable {
    private Map<String, MybatisEnvironment> id2EnvironmentMap = new HashMap<>();

    private MybatisEnvironment defaultMybatisEnvironment;

    private List<String> mapperPaths = new ArrayList<>();

    public void addEnvironment(String id, MybatisEnvironment mybatisEnvironment) {
        this.id2EnvironmentMap.put(id, mybatisEnvironment);
    }

    public MybatisEnvironment getEnvironment(String id) {
        return id2EnvironmentMap.get(id);
    }

    public MybatisEnvironment getDefaultMybatisEnvironment() {
        return defaultMybatisEnvironment;
    }

    public void setDefaultMybatisEnvironment(MybatisEnvironment defaultMybatisEnvironment) {
        this.defaultMybatisEnvironment = defaultMybatisEnvironment;
    }

    public void addMapperPath(String mapperPath) {
        this.mapperPaths.add(mapperPath);
    }

    public List<String> getMapperPaths() {
        return this.mapperPaths;
    }

    public List<MybatisEnvironment> getEnvironments() {
        return new ArrayList<>(id2EnvironmentMap.values());
    }

}

对于mybatis-config.xml的解析,我们定义一个IMybatisConfigParser接口

package com.yang.mybatis.config.parser;

import com.yang.mybatis.config.MybatisConfiguration;

public interface IMybatisConfigurationParser {
    MybatisConfiguration parser(String path) ;
}

然后定义其实现类:

package com.yang.mybatis.config.parser;

import com.yang.mybatis.config.MybatisConfiguration;
import com.yang.mybatis.config.MybatisDataSource;
import com.yang.mybatis.config.MybatisEnvironment;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class XmlMybatisConfigurationParser implements IMybatisConfigurationParser {

    @Override
    public MybatisConfiguration parser(String path) {
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path);
            SAXReader saxReader = new SAXReader();
            // 1. 读取文档
            Document document = saxReader.read(inputStream);
            Element root = document.getRootElement();

            parseEnvironments(mybatisConfiguration, root.element("environments"));
            parseMappers(mybatisConfiguration, root.element("mappers"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mybatisConfiguration;
    }

    private void parseMappers(MybatisConfiguration mybatisConfiguration, Element mappers) {
        List<Element> mapperList = mappers.elements("mapper");
        for (Element mapper : mapperList) {
            String resource = mapper.attributeValue("resource");
            mybatisConfiguration.addMapperPath(resource);
        }
    }

    private void parseEnvironments(MybatisConfiguration mybatisConfiguration, Element environments) {
        String defaultId = environments.attributeValue("default");
        for (Element element : environments.elements()) {
            String id = element.attributeValue("id");

            Element dataSource = element.element("dataSource");
            List<Element> properties = dataSource.elements("property");
            Map<String, String> propertyMap = new HashMap<>();
            for (Element property : properties) {
                propertyMap.put(property.attributeValue("name"), property.attributeValue("value"));
            }
            String driver = propertyMap.get("driver");
            String url = propertyMap.get("url");
            String username = propertyMap.get("username");
            String password = propertyMap.get("password");
            MybatisDataSource mybatisDataSource = new MybatisDataSource();
            mybatisDataSource.setDriver(driver);
            mybatisDataSource.setUrl(url);
            mybatisDataSource.setUsername(username);
            mybatisDataSource.setPassword(password);

            MybatisEnvironment mybatisEnvironment = new MybatisEnvironment();
            mybatisEnvironment.setId(id);
            mybatisEnvironment.setMybatisDataSource(mybatisDataSource);
            mybatisConfiguration.addEnvironment(id, mybatisEnvironment);
            if (id.equals(defaultId)) {
                mybatisConfiguration.setDefaultMybatisEnvironment(mybatisEnvironment);
            }
        }
    }
}

然后添加测试代码进行测试:

 IMybatisConfigurationParser mybatisConfigurationParser = new XmlMybatisConfigurationParser();
        MybatisConfiguration mybatisConfiguration = mybatisConfigurationParser.parser("mybatis-config.xml");
        System.out.println("mapperPaths==========");
        for (String mapperPath : mybatisConfiguration.getMapperPaths()) {
            System.out.println(mapperPath);
        }
        System.out.println("environments========");
        for (MybatisEnvironment environment : mybatisConfiguration.getEnvironments()) {
            MybatisDataSource mybatisDataSource = environment.getMybatisDataSource();
            System.out.println("id:" + environment.getId()
            + ",driver:" + mybatisDataSource.getDriver()
            + ",url:" + mybatisDataSource.getUrl()
            + ",username:" + mybatisDataSource.getUsername()
            + ",password:" + mybatisDataSource.getPassword());
        }
        System.out.println("defaultEnvironment=======");
        MybatisEnvironment defaultMybatisEnvironment = mybatisConfiguration.getDefaultMybatisEnvironment();
        MybatisDataSource mybatisDataSource = defaultMybatisEnvironment.getMybatisDataSource();
        System.out.println("id:" + defaultMybatisEnvironment.getId()
                + ",driver:" + mybatisDataSource.getDriver()
                + ",url:" + mybatisDataSource.getUrl()
                + ",username:" + mybatisDataSource.getUsername()
                + ",password:" + mybatisDataSource.getPassword());

结果如下:
image.png

mapperXml的解析

首先添加一个MybatisSqlStatement

package com.yang.mybatis.config;

import java.io.Serializable;

public class MybatisSqlStatement implements Serializable {
    private String namespace;

    private String id;

    private String sql;

    public String getNamespace() {
        return namespace;
    }

    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }
}

添加解析mapper文件的接口

package com.yang.mybatis.config.parser;

import com.yang.mybatis.config.MybatisSqlStatement;

import java.util.List;

public interface IMybatisMapperParser {
    List<MybatisSqlStatement> parseMapper(String path);
}

具体实现:

package com.yang.mybatis.config.parser;

import com.yang.mybatis.config.MybatisSqlStatement;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class XmlMybatisMapperParser implements IMybatisMapperParser {
    private final static Set<String> tagSet = new HashSet<>();

    static {
        tagSet.add("select");
        tagSet.add("insert");
        tagSet.add("update");
        tagSet.add("delete");
        tagSet.add("SELECT");
        tagSet.add("INSERT");
        tagSet.add("UPDATE");
        tagSet.add("DELETE");
    }
    @Override
    public List<MybatisSqlStatement> parseMapper(String path) {
        List<MybatisSqlStatement> mybatisSqlStatements = new ArrayList<>();
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path);
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            Element root = document.getRootElement();

            for (String tag : tagSet) {
                List<Element> elements = root.elements(tag);
                parseStatement(mybatisSqlStatements, elements, root);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return mybatisSqlStatements;
    }

    private void parseStatement(List<MybatisSqlStatement> mybatisSqlStatements, List<Element> elements, Element root) {
        if (elements == null || elements.isEmpty()) {
            return;
        }
        String namespace = root.attributeValue("namespace");
        for (Element element : elements) {
            String id = element.attributeValue("id");
            String sql = element.getText().trim();

            MybatisSqlStatement mybatisSqlStatement = new MybatisSqlStatement();
            mybatisSqlStatement.setNamespace(namespace);
            mybatisSqlStatement.setId(id);
            mybatisSqlStatement.setSql(sql);

            mybatisSqlStatements.add(mybatisSqlStatement);
        }
    }
}

然后,我们创建一个UserMapper.xml,用于测试,该文件内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.yang.mybatis.test.IUserMapper">
    <select id="queryUserName">
        select user_name from user where id = #{id}
    </select>
    <select id="queryUserAge">
        select age from user where id = #{id}
    </select>
</mapper>

添加测试代码,进行测试:

    public static void main(String[] args) {
        IMybatisMapperParser mybatisMapperParser = new XmlMybatisMapperParser();
        List<MybatisSqlStatement> mybatisSqlStatements = mybatisMapperParser.parseMapper("mapper/UserMapper.xml");
        for (MybatisSqlStatement mybatisSqlStatement : mybatisSqlStatements) {
            System.out.println("=================");
            System.out.println("namespace:" + mybatisSqlStatement.getNamespace());
            System.out.println("id:" + mybatisSqlStatement.getId());
            System.out.println("sql:" + mybatisSqlStatement.getSql());
        }
    }

结果如下:
image.png

MapperProxyFactory注册Mapper

这里再修改一些MybatisConfiguration,因为mapperXML里的内容,其实我认为也属于配置项,因此收敛到MybatisConfiguration,方便后续统一管理

package com.yang.mybatis.config;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MybatisConfiguration implements Serializable {
    private Map<String, MybatisEnvironment> id2EnvironmentMap = new HashMap<>();

    private MybatisEnvironment defaultMybatisEnvironment;

    private List<String> mapperPaths = new ArrayList<>();

    private Map<String, List<MybatisSqlStatement>> mapper2SqlStatementsMap = new HashMap<>();

    public void putMybatisSqlStatementList(String mapperName, List<MybatisSqlStatement> mybatisSqlStatementList) {
        if (mapper2SqlStatementsMap.containsKey(mapperName)) {
            mapper2SqlStatementsMap.get(mapperName).addAll(mybatisSqlStatementList);
        } else {
            mapper2SqlStatementsMap.put(mapperName, mybatisSqlStatementList);
        }
    }

    public Map<String, List<MybatisSqlStatement>> getMapper2SqlStatementsMap() {
        return this.mapper2SqlStatementsMap;
    }

    public void addEnvironment(String id, MybatisEnvironment mybatisEnvironment) {
        this.id2EnvironmentMap.put(id, mybatisEnvironment);
    }

    public MybatisEnvironment getEnvironment(String id) {
        return id2EnvironmentMap.get(id);
    }

    public MybatisEnvironment getDefaultMybatisEnvironment() {
        return defaultMybatisEnvironment;
    }

    public void setDefaultMybatisEnvironment(MybatisEnvironment defaultMybatisEnvironment) {
        this.defaultMybatisEnvironment = defaultMybatisEnvironment;
    }

    public void addMapperPath(String mapperPath) {
        this.mapperPaths.add(mapperPath);
    }

    public List<String> getMapperPaths() {
        return this.mapperPaths;
    }

    public List<MybatisEnvironment> getEnvironments() {
        return new ArrayList<>(id2EnvironmentMap.values());
    }

}

然后修改MapperProxy,接收MybatisSqlStatement数组,在执行的时候,根据执行方法,找到对应的MybatisSqlStatement,获取mapper Xml对应的sql语句,并打印出来

package com.yang.mybatis.mapper;

import com.yang.mybatis.config.MybatisSqlStatement;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MapperProxy<T> implements InvocationHandler {
    private Map<String, MybatisSqlStatement> sqlSessionMap = new HashMap<>();

    private Class<T> mapperInterface;

    public MapperProxy(Class<T> mapperInterface, List<MybatisSqlStatement> mybatisSqlStatementList) {
        this.mapperInterface = mapperInterface;
        for (MybatisSqlStatement mybatisSqlStatement : mybatisSqlStatementList) {
            String mapperName = mybatisSqlStatement.getNamespace();
            String id = mybatisSqlStatement.getId();
            String key = mapperName + "." + id;
            sqlSessionMap.put(key, mybatisSqlStatement);
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }
        String key = this.mapperInterface.getName() + "." + method.getName();
        return "你的被代理了!" + sqlSessionMap.get(key).getSql();
    }
}

接着修改MybatisProxyFactory,通过配置信息,加载对应的mapper.xml文件并进行解析

package com.yang.mybatis.mapper;

import com.yang.mybatis.config.MybatisConfiguration;
import com.yang.mybatis.config.MybatisSqlStatement;

import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MapperProxyFactory {
    private Map<Class, MapperProxy> mapperProxyMap = new HashMap<>();


    public MapperProxyFactory(MybatisConfiguration mybatisConfiguration) {
        Map<String, List<MybatisSqlStatement>> mapperName2SqlStatementsMap = mybatisConfiguration.getMapper2SqlStatementsMap();
        mapperName2SqlStatementsMap.forEach((mapperName, sqlStatementList) -> {
            try {
                Class<?> type = Class.forName(mapperName);
                mapperProxyMap.put(type, new MapperProxy(type, sqlStatementList));
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        });
    }

    public Object newInstance(Class mapperType) {
        MapperProxy mapperProxy = mapperProxyMap.get(mapperType);
        return Proxy.newProxyInstance(mapperType.getClassLoader(),
                new Class[]{mapperType},
                mapperProxy);
    }

}

添加测试方法,进行测试:

public static void main(String[] args) {
        IMybatisConfigurationParser iMybatisConfigurationParser = new XmlMybatisConfigurationParser();
        MybatisConfiguration mybatisConfiguration = iMybatisConfigurationParser.parser("mybatis-config.xml");

        IMybatisMapperParser iMybatisMapperParser = new XmlMybatisMapperParser();
        List<String> mapperPaths = mybatisConfiguration.getMapperPaths();
        for (String mapperPath : mapperPaths) {
            List<MybatisSqlStatement> mybatisSqlStatements = iMybatisMapperParser.parseMapper(mapperPath);
            Map<String, List<MybatisSqlStatement>> mapperNameGroupMap = mybatisSqlStatements.stream()
                    .collect(Collectors.groupingBy(MybatisSqlStatement::getNamespace));

            for (Map.Entry<String, List<MybatisSqlStatement>> entry : mapperNameGroupMap.entrySet()) {
                String mapperName = entry.getKey();
                List<MybatisSqlStatement> sqlSessionList = entry.getValue();
                mybatisConfiguration.putMybatisSqlStatementList(mapperName, sqlSessionList);
            }
        }

        MapperProxyFactory mapperProxyFactory = new MapperProxyFactory(mybatisConfiguration);
        IUserMapper userMapper = (IUserMapper) mapperProxyFactory.newInstance(IUserMapper.class);
        System.out.println(userMapper.queryUserName(1));
    }

测试结果如下:
image.png

参考文章

https://zhuanlan.zhihu.com/p/338300626

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】---模板进阶

【C】---模板进阶 一、模版参数1、类型参数2、非类型参数 二、模板的特化1、函数模板的特化2、类模板特化&#xff08;1&#xff09;全特化&#xff08;2&#xff09;偏特化 三、模板分离编译1、模板支持分离编译吗&#xff1f;2、为什么模板不支持分离编译&#xff1f;3、如何…

《21天学通C++》(第十五章)标准模板库简介

本章简单介绍STL容器、迭代器和算法的基本概念&#xff0c;之后几章会分别详述 1.STL容器 STL容器是STL中用于存储集合数据的组件&#xff0c;它们可以被看作是模板类&#xff0c;允许开发者定义特定类型的容器发&#xff0c;这里按照C11标准分为四类&#xff1a;顺序容器、关…

Vmware虚拟机瘦身及Samba服务不可用问题解决

虚拟机磁盘空间膨胀是一个令人头疼的问题&#xff0c;特别是对许多搞开发的小伙伴。无论是做后台服务、嵌入式还是Android开发&#xff0c;都面临着这个难题。首先&#xff0c;操作系统本身就已占用不少空间&#xff0c;更新安装包&#xff0c;再下载一些开源软件&#xff0c;剩…

leetcode_47.全排列 II

47. 全排列 II 题目描述&#xff1a;给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] …

Server 2022 IIS10 PHP 7.2.33 升级至 PHP 8.3 (8.3.6)

下载最新版本 PHP 8.3 (8.3.6)&#xff0c;因为是 FastCGI 执行方式&#xff0c;选择 Non Thread Safe(非线程安全)。 若有以下提示&#xff1a; The mysqli extension is missing. Please check your PHP configuration. 或者 PHP Fatal error: Uncaught Error: Class &qu…

41 POSIX信号量

POSIX信号量 POSIX信号量和System V信号量作用相同&#xff0c;都是用于同步操作&#xff0c;达到无冲突的访问共享资源目的&#xff0c;但POSIX可以用于线程同步 31节说了信号量&#xff0c;信号量的本质是一个计数器。将共享资源从一个整体划分为很多不部分&#xff0c;就和…

可视化大屏应用场景:智慧安防,保驾护航

hello&#xff0c;我是大千UI工场&#xff0c;本篇分享智慧安防的大屏设计&#xff0c;关注我们&#xff0c;学习N多UI干货&#xff0c;有设计需求&#xff0c;我们也可以接单。 实时监控与预警 可视化大屏可以将安防系统中的监控画面、报警信息、传感器数据等实时展示在大屏上…

【word技巧】Word目录如何设置为对齐?

Word文档的目录有些在修改之后无法对齐&#xff0c;大家是不是会自己手动删除省略号&#xff1f;今天分享一个方法&#xff0c;设置之后&#xff0c;tab一键对齐目录。 先选中目录&#xff0c;然后点击段落设置界面&#xff0c;选择左下角的【制表位】 然后将制表位置设置为【…

蓝桥杯练习系统(算法训练)ALGO-947 贫穷的城市

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 某城市有n个小镇&#xff0c;编号是1~n。由于贫穷和缺乏城市规划的人才&#xff0c;每个小镇有且仅有一段单向的公路通往别…

一机游领航旅游智慧化浪潮:借助前沿智能设备,革新旅游服务效率,构建高效便捷、生态友好的旅游服务新纪元,开启智慧旅游新时代

目录 一、引言 二、一机游的定义与特点 &#xff08;一&#xff09;一机游的定义 &#xff08;二&#xff09;一机游的特点 三、智能设备在旅游服务中的应用 &#xff08;一&#xff09;旅游前的信息查询与预订支付 &#xff08;二&#xff09;旅游中的导航导览与互动体…

SHOW ME THE CODE - 面向对象程序设计之 - 接口隔离原则(ISP)

SHOW ME THE CODE - 面向对象设计系列 1 SHOW ME THE CODE - 面向对象基本概念2 SHOW ME THE CODE - 面向对象程序设计之 - 单一职责原则(SRP)3 SHOW ME THE CODE - 面向对象程序设计之 - 开闭原则&#xff08;OCP&#xff09;4 SHOW ME THE CODE - 面向对象程序设计之 - 里氏…

C语言实验-学生信息管理系统

按以下菜单界面编写学生信息管理系统&#xff1b; 1&#xff09;录入学生信息首先输入学生人数&#xff0c;然后根据学生人数开辟动态数组&#xff1b; 2&#xff09;学生信息包括学号、姓名、性别、三门课成绩、总分&#xff1b;其中学号、姓名、 性别、三门课成绩是需要从键盘…

用git上传本地文件到github

两种方式&#xff1a;都需要git软件&#xff08;1&#xff09;VScode上传 &#xff08;2&#xff09;直接命令行&#xff0c;后者不需要VScode软件 &#xff08;1&#xff09;vscode 上传非常方便&#xff0c;前提是下载好了vscode和git软件 1 在项目空白处右击&#xff0c;弹…

ReentrantReadWriteLock类

为了有了ReentrantLock还需要ReentrantReadWriteLock ReentrantReadWriteLock是一个读写锁&#xff0c;它允许多个读操作同时进行&#xff0c;但在写操作时会阻止其他所有读和写操作。这种锁特别适合于读取远多于写入的场景&#xff0c;因为它可以提高并发性而不会牺牲数据一致…

华为OD机试 - 小扇和小船的数字游戏 - 二进制(Java 2024 C卷 200分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

VsCode | 修改首页启动页 Logo

VsCode | 修改首页启动页 Logo 最终效果&#xff1a; 插件的安装 先安装插件 Custom CSS and JS Loader 插件配置 Ctrl Shift P 输入 打开用户设置&#xff0c;在末尾添加 "vscode_custom_css.imports": [""]下载 Logo 下载 Logo 点我下载 引入…

SDB2F3 1.5A,高达28V输出1.2MHz升压转换器芯片IC

一般说明 该SDB2F3是一个恒定的频率&#xff0c;5针SOT23用于小型低功率应用的电流模式升压转换器。 该SDB2F3开关在1.2MHz&#xff0c;并允许使用微小&#xff0c;低成本的电容器和电感2毫米或更少的高度。内部软启动的结果在小浪涌电流和延长电池寿命。 该SDB2F3工作从…

string底层浅析

char简单易用,但是string是万金油 char *b "123"; string a{"123"};a是不是地址 发现a是地址 a的地址是不是和a[0]地址重合 #include<iostream> #include<cstring> using namespace std; int main() {string a{ "123" };char g[…

Pytorch分布式train——pytorch.distributed.launch V.S. torchrun

1. 较早的pytorch.distributed.launch python -m torch.distributed.launch --nproc_per_node4 --nnodes1 --node_rank0 train.py --args XXX 参数解析&#xff1a; nnodes&#xff1a;节点&#xff08;主机&#xff09;的数量&#xff0c;通常一个节点对应一个主机 node_rank…

探索动态内存开辟的奥秘

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 前言 开始之前&#xff0c;我们先来了解一下C/C中程序内存区域划分。 在C/C程序中&#xff0c;内存区域通常被划分为以下几个部分&#xff1a; 1.栈&…