MybatisPlus多表查询之零sql编写实现

news2025/1/18 7:55:44

1.前言

       年初节奏还没有快起来,适合做做技术前瞻,无论是对个人还是团队都是好事。真要说分享,其实感觉也没啥好分享的,就像接手新项目一样,代码都是自己看,别人讲的再多,不看,不用,不踩坑都不会刻骨铭心。
       今天要跟大家分享的mybatisPlus的join查询也是临时起意,早上有同事觉得在mybatisPlus的xml文件里配置子查询不好,嫌弃慢(其实是偷懒了没有正确使用,resultMap没有根据业务自己用自己的,避免多余的子查询),建议在代码层面实现,这里就分享这个join查询如你所愿。

2.分享内容

       MybatisPlus的join查询工具包,这个几乎可以满足零xml的sql编写。实现这一工具包的有2个人,一个是河南的,一个是北京的。个人偏向使用北京小哥实现的,有boot-starter可以支持配置文件,功能更强点。

3.使用方法

3.1北京小哥的join工具包

3.1.1源码与帮助介绍

Git地址:https://github.com/yulichang/mybatis-plus-join.git
使用帮助:https://ylctmh.com/

3.1.2使用集成

1、依赖引入

<!-- mybatis-plus-join依赖 -->
<dependency>
    <groupId>com.github.yulichang</groupId>
    <artifactId>mybatis-plus-join-boot-starter</artifactId>
    <version>1.4.2.2</version>
</dependency>

2、配置
       因为提供了boot-starter,所以可以直接使用配置文件,具体可以查看在线使用帮助。我这里是在多数据源场景下使用的,就不用配置文件了。
配置类
A、 MbatisPlus的配置类增加绑定配置

import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.github.yulichang.injector.MPJSqlInjector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;


/**
 * 分页插件配置
 *
 * @author zhengwen
 */
@Slf4j
@Configuration
public class MyBatisPlusConfig {

    /**
     * 分页插件 3.5.X
     */
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        log.debug("注册分页插件");
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        /* 只负责注册分页插件,不具体设置DbType、方言等
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(-1L);
        paginationInnerInterceptor.setDbType(DbType.TDENGINE);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInnerInterceptor.setOptimizeJoin(true);
        */
        return paginationInnerInterceptor;
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.setInterceptors(Collections.singletonList(paginationInnerInterceptor()));
        return mybatisPlusInterceptor;
    }

    /**
     * GlobalConfig 配置 MPJSqlInjector
     * 绑定MPJSqlInjector到全局配置
     */
    @Bean
    public GlobalConfig globalConfig(MPJSqlInjector mpjSqlInjector) {
        GlobalConfig config = new GlobalConfig();
        //绑定 mpjSqlInjector到全局配置
        config.setSqlInjector(mpjSqlInjector);
        //其他配置 略
        return config;
    }


}

B、 Mysql数据源配置注入全局配置
如果不是多数据源其实可以直接在MybatisPlus里的SqlSessionFactory注入全局配置。我这里是在Mysql数据源配置类注入配置。
MysqlServerConfig配置类的SqlSessionFactory增加配置

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.Collections;


/**
 * mysql配置类
 *
 * @author zhengwen
 */
@Configuration
@MapperScan(basePackages = {"com.xiaotian.datatrans.mapper.mysql"}, sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
public class MysqlServerConfig {

    @Autowired
    private PaginationInnerInterceptor paginationInnerInterceptor;

    private static final String MAPPER_LOCATION = "classpath:mapper/mysql/*.xml";

    @Bean(name = "mysqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.mysql-service")
    @Primary
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "mysqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource, GlobalConfig globalConfig) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));

        //关联SqlSessionFactory与GlobalConfig
        bean.setGlobalConfig(globalConfig);

        //不在这里注入分页插件,会失效,(MyBatisPlusConfig只负责注册分页插件)
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        paginationInnerInterceptor.setMaxLimit(-1L);
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInnerInterceptor.setOptimizeJoin(true);
        mybatisPlusInterceptor.setInterceptors(Collections.singletonList(paginationInnerInterceptor));
        bean.setPlugins(mybatisPlusInterceptor);

        return bean.getObject();
    }

    @Bean(name = "mysqlTransactionManager")
    @Primary
    public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "mysqlSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

3、Mapper变更
业务mapper原先是继承MybatisPlus的BaseMapper,这里改为继承MPJBaseMapper,点击进去实际上这个接口最终也有继承了BaseMapper的。


/**
 * <p>
 * 设备推送信息表 Mapper 接口
 * </p>
 *
 * @author zhengwen
 * @since 2023-02-03
 */
@DS("mysql-service")
public interface DeviceRecordMapper extends MPJBaseMapper<DeviceRecord> {


    /**
     * 测试
     *
     * @param page
     * @param deviceRecord
     * @return
     */
    IPage<DeviceRecordDto> selectListBy(Page page, @Param("deviceRecord") DeviceRecord deviceRecord);
}

4、service实现使用

/**
 * <p>
 * 设备推送信息表 服务实现类
 * </p>
 *
 * @author zhengwen
 * @since 2023-02-03
 */
@Service
public class DeviceRecordServiceImpl extends ServiceImpl<DeviceRecordMapper, DeviceRecord> implements DeviceRecordService {

    @Autowired
    private DeviceRecordMapper deviceRecordMapper;

    @Override
    public IPage<DeviceRecordDto> selectPage(Page page, DeviceRecord customQueryParams) {
        QueryWrapper<DeviceRecord> qw = new QueryWrapper<>();
        IPage<DeviceRecordDto> records = deviceRecordMapper.selectPage(page, qw);
        //IPage<Student> records = deviceRecordMapper.selectStudentPage(page, customQueryParams);

        return records;

    }

    @Override
    public IPage<DeviceRecordDto> getPageUseJoin(Page page, DeviceRecord customQueryParams) {
        //分页查询
        IPage<DeviceRecordDto> list = deviceRecordMapper.selectJoinPage(page, DeviceRecordDto.class,
                new MPJLambdaWrapper<DeviceRecord>()
                        .selectAll(DeviceRecord.class)
                        //子查询
                        .selectCollection(DeviceRecordInfo.class, DeviceRecordDto::getRecordInfoList)
                        .leftJoin(DeviceRecordInfo.class, DeviceRecordInfo::getRecordId, DeviceRecord::getId));

        return list;
    }
}

3.1.3效果查看

1、2张表的sql
设备推送信息表:device_record
设备上报信息详情:device_record_info

CREATE TABLE `device_record` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `device_no` varchar(100) DEFAULT NULL COMMENT '设备编码',
  `record_time` datetime DEFAULT NULL COMMENT '上报时间',
  `device_type_no` varchar(10) DEFAULT NULL COMMENT '设备类型编码',
  `device_name` varchar(200) DEFAULT NULL COMMENT '设备名称',
  `record_type` varchar(10) DEFAULT NULL COMMENT '上报数据类型',
  `service_id` varchar(20) DEFAULT NULL COMMENT '服务id',
  `record_content` varchar(4000) DEFAULT NULL COMMENT '上报原始内容',
  `create_by` int(11) DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='设备推送信息表';
CREATE TABLE `device_record_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `tag_name` varchar(100) DEFAULT NULL COMMENT '字段名称',
  `tag_key` varchar(50) DEFAULT NULL COMMENT '字段key',
  `tag_val` varchar(50) DEFAULT NULL COMMENT '字段值',
  `record_id` bigint(20) DEFAULT NULL COMMENT '记录id',
  `tag_unit` varchar(30) DEFAULT NULL COMMENT '单位',
  `tag_val_name` varchar(100) DEFAULT NULL COMMENT '字段值释意',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='设备上报信息详情';

2、2张表关系说明
Device_record的主键关联device_record_info的record_id字段:
3、接口请求效果
A、执行的sql
在这里插入图片描述

B、返回的数据
在这里插入图片描述

3.1.4使用总结

1、这里做了个简单示例,它的使用确实应该是可以做到零xml的sql编写的,就看你愿意不。
2、MPJLambdaWrapper增加过滤条件就跟MybatisPlus的QueryWrapper一致。
3、还有很多使用方法,可以自行去在线帮助文档查看,也可以自己在mapper后面“.“的看。
4、个人认为还是挺香的

3.2河南小哥的join工具包

3.2.1源码与帮助介绍

Git地址:https://gitee.com/mhb0409/mybatis-plus-join
使用帮助:就是项目的README.md里介绍

3.2.2使用集成

1、依赖引入

<dependency>
    <groupId>icu.mhb</groupId>
    <artifactId>mybatis-plus-join</artifactId>
    <version>1.3.4</version>
</dependency>

2、配置
A、配置类
MyBatisPlusConfig需要继承JoinDefaultSqlInjector,并且需要重写getMethodList方法

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import icu.mhb.mybatisplus.plugln.injector.JoinDefaultSqlInjector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;
import java.util.List;


/**
 * 分页插件配置
 *
 * @author zhengwen
 */
@Slf4j
@Configuration
public class MyBatisPlusConfig extends JoinDefaultSqlInjector {

    /**
     * 分页插件 3.5.X
     */
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        log.debug("注册分页插件");
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        /* 只负责注册分页插件,不具体设置DbType、方言等
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(-1L);
        paginationInnerInterceptor.setDbType(DbType.TDENGINE);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInnerInterceptor.setOptimizeJoin(true);
        */
        return paginationInnerInterceptor;
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.setInterceptors(Collections.singletonList(paginationInnerInterceptor()));
        return mybatisPlusInterceptor;
    }

    
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        return methodList;
    }
}

B、Mysql数据源配置类
全局配置绑定join的Injector

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import icu.mhb.mybatisplus.plugln.injector.JoinDefaultSqlInjector;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.Collections;


/**
 * mysql配置类
 *
 * @author zhengwen
 */
@Configuration
@MapperScan(basePackages = {"com.xiaotian.datatrans.mapper.mysql"}, sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
public class MysqlServerConfig {

    @Autowired
    private PaginationInnerInterceptor paginationInnerInterceptor;

    private static final String MAPPER_LOCATION = "classpath:mapper/mysql/*.xml";

    @Bean(name = "mysqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.mysql-service")
    @Primary
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean
    public GlobalConfig globalConfig(JoinDefaultSqlInjector joinDefaultSqlInjector) {
        GlobalConfig config = new GlobalConfig();
        //绑定 mpjSqlInjector到全局配置
        config.setSqlInjector(joinDefaultSqlInjector);
        //其他配置 略
        return config;
    }

    @Bean(name = "mysqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource, GlobalConfig globalConfig) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));

        //关联SqlSessionFactory与GlobalConfig
        bean.setGlobalConfig(globalConfig);

        //不在这里注入分页插件,会失效,(MyBatisPlusConfig只负责注册分页插件)
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        paginationInnerInterceptor.setMaxLimit(-1L);
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInnerInterceptor.setOptimizeJoin(true);
        mybatisPlusInterceptor.setInterceptors(Collections.singletonList(paginationInnerInterceptor));
        bean.setPlugins(mybatisPlusInterceptor);

        return bean.getObject();
    }

    @Bean(name = "mysqlTransactionManager")
    @Primary
    public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "mysqlSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

3、springBoot3的启动类还要增加import
否则,查询结果不能成功映射到MybatisPlus的IPage对象的records
启动类上增加注解@Import({JoinInterceptor.class, JoinInterceptorConfig.class})

import icu.mhb.mybatisplus.plugln.interceptor.JoinInterceptor;
import icu.mhb.mybatisplus.plugln.interceptor.JoinInterceptorConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Import;

/**
 * @author zhengwen
 */

@Import({JoinInterceptor.class, JoinInterceptorConfig.class})
@EntityScan("com.xiaotian")
@SpringBootApplication
public class DataGeniusApplication {

    public static void main(String[] args) {
        SpringApplication.run(DataGeniusApplication.class, args);
        System.out.println("--数据精灵启动成功--");
    }

}

4、Mapper变更
业务mapper原先是继承MybatisPlus的BaseMapper,这里改为继承JoinBaseMapper,点击进去实际上这个接口最终也继承了BaseMapper的。


/**
 * <p>
 * 设备推送信息表 Mapper 接口
 * </p>
 *
 * @author zhengwen
 * @since 2023-02-03
 */
@DS("mysql-service")
public interface DeviceRecordMapper extends JoinBaseMapper<DeviceRecord> {


    /**
     * 测试
     *
     * @param page
     * @param deviceRecord
     * @return
     */
    IPage<DeviceRecordDto> selectListBy(Page page, @Param("deviceRecord") DeviceRecord deviceRecord);
}

5、service实现类使用

/**
 * <p>
 * 设备推送信息表 服务实现类
 * </p>
 *
 * @author zhengwen
 * @since 2023-02-03
 */
@Service
public class DeviceRecordServiceImpl extends ServiceImpl<DeviceRecordMapper, DeviceRecord> implements DeviceRecordService {

    @Autowired
    private DeviceRecordMapper deviceRecordMapper;

    @Override
    public IPage<DeviceRecordDto> selectPage(Page page, DeviceRecord customQueryParams) {
        QueryWrapper<DeviceRecord> qw = new QueryWrapper<>();
        IPage<DeviceRecordDto> records = deviceRecordMapper.selectPage(page, qw);
        //IPage<Student> records = deviceRecordMapper.selectStudentPage(page, customQueryParams);

        return records;

    }

    @Override
    public IPage<DeviceRecordDto> getPageUseJoin(Page page, DeviceRecord customQueryParams) {
         //分页查询
        JoinLambdaWrapper<DeviceRecord> joinLambdaWrapper = new JoinLambdaWrapper<>(DeviceRecord.class);
        joinLambdaWrapper.leftJoin(DeviceRecordInfo.class, DeviceRecordInfo::getRecordId, DeviceRecord::getId)
                .manyToManySelect(DeviceRecordDto::getRecordInfoList,DeviceRecordInfo.class)
                //下面的这个end一定不能少哦,否在sql不会出现 left join xxx
                .end();
        IPage<DeviceRecordDto> list = deviceRecordMapper.joinSelectPage(page, joinLambdaWrapper, DeviceRecordDto.class);

        return list;
    }
}

3.2.3使用效果查看

       效果与3.1.3一致

3.2.4使用总结

1、总体感觉基本与3.1.4一致
2、没有boot-starter感觉没有北京小哥的高大上
3、在线文档没有专门的网址
4、配置略比北京小哥的复杂一丢丢

4.总体感想

  • 首先应该确实可以做到零XML的sql编写了
  • 零sql编写应该是优缺点各一半吧
  • 有没有觉得有了这个,JPA真的是没有必要用了呢?
  • 这2各包在Maven中心库,看到发布第一版时间是同年同月,不过走的方向不一样,一个走插件方式,一个走重写。
  • 2个作者都还在不断更新兼容新版本的MybatisPlus,点赞
  • 2个作者,我也联系到人了,都很友好。就喜欢技术人这种面向问题的交流方式。
           如果有需要,可以去我CSDN的gitCode下载demo,地址:https://gitcode.net/zwrlj527/data-trans.git。这个还是集成上次的多数据源做的集成。更多使用姿势,大家可以自行去他们的帮助文档查看并解锁使用。
           希望可以帮到大家,uping!!!

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

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

相关文章

OpenMP For Construct dynamic 调度方式实现原理和源码分析

OpenMP For Construct dynamic 调度方式实现原理和源码分析 前言 在本篇文章当中主要给大家介绍 OpenMp for construct 的实现原理&#xff0c;以及与他相关的动态库函数分析&#xff0c;与 for construct 非常相关的是循环的调度方式&#xff0c;在 OpenMP 当中一共有四种调…

KVM,QEMU与libvirt关系

KVM&#xff1a;负责cpu虚拟化内存虚拟化&#xff0c;实现了cpu和内存的虚拟化&#xff0c;但kvm不能模拟其他设备&#xff1b;KVM是linux内核的模块&#xff0c;它需要CPU的支持&#xff0c;采用硬件辅助虚拟化技术Intel-VT&#xff0c;AMD-V&#xff0c;内存的相关如Intel的E…

FPGA纯verilog代码实现8位精简指令集CPU,一学期的微机原理不如看懂这套代码,提供工程源码和技术支持

目录1、前言2、设计思想和架构3、硬件组成讲解4、vivado仿真5、vivado工程6、上板调试验证7、福利&#xff1a;工程源码获取1、前言 本文章主要针对大学本科阶段学生&#xff1b; 读文章之前先来几个灵魂拷问&#xff1a; 1、你是否学过《微机原理》、《单片机》、《汇编语言》…

怎样做一个优秀的程序员?这10个问题ChatGPT这样说 ……

本文目录 1 怎样做一个优秀的程序员? 2 怎样成为优秀的架构师? 3 怎样写容易阅读的代码? 4 怎样做项目管理? 5 怎样学习计算机程序设计? 6 怎样提升个人影响力? 7 怎样提升认知? 8 程序员怎样面试通过几率高? 9 怎样提升研发效能? 10 怎样保障软件系统的稳定…

字体图标的使用【购物车】

方法1 <link rel"stylesheet" href"2购物车/iconfont.css"><style>*{padding: 0;margin: 0;}li{width: 90px;height: 40px;background-color: pink;margin: 0 auto; list-style: none;text-align: center;line-height: 40px;}a{text-decoratio…

4.6 Python元组

列表非常适合用于存储在程序运行期间可能变化的数据集。Python将不能修改的值称为不可变的&#xff0c;而不可变的列表被称为元组。4.5.1 定义元组元组看起来犹如列表&#xff0c;但使用圆括号而不是方括号来标识。定义元组后&#xff0c;就可以使用索引来访问其元素&#xff0…

vue3组件库项目学习笔记(七):正式开发问题拾遗

目前组件库的开发还在进行中&#xff0c;这里把一些开发过程中遇到的问题和解决方案总结一下&#xff0c;也方便后续开发的同学踩坑了可以马上解决问题&#xff0c;这期的问题主要是&#xff1a; 多项目开发的配置文件优化和全局导入方法的修改怎么样使用 icon 组件怎么样使用…

git-学习git,这一篇就足够了(初学者视角实战教程)

目录git概念命令git配置README.gitignore工作区、暂存区和版本库基础配置创建远程仓库克隆修改查看工作区当前状态添加到暂存区回退版本比较工作区与缓存区的差异添加到本地仓库并加注释push提高git pull文件删除与恢复分支管理列出分支创建分支切换分支分支操作标签管理创建标…

【linux】进程间通信——管道通信

进程间通信一、进程间通信1.1 通信的介绍1.2 通信的目的1.3 通信的分类二、管道2.1 匿名管道2.1.1 pipe2.2.2 读写特征2.2.3 命名管道一、进程间通信 1.1 通信的介绍 通信就是一个进程把数据传递给另一个进程&#xff0c;但是每个进程都具有独立性。通信的本质&#xff1a;OS需…

STL——vector

一、标准库中的vector 1.vector文档介绍 &#xff08;1&#xff09;vector是表示可变大小数组的序列容器。 &#xff08;2&#xff09;像数组一样&#xff0c;vector也采用连续存储空间来存储元素&#xff0c;也就意味着可以采用下标对vector的元素进行访问&#xff0c;和数…

深度:用10000字总结了嵌入式C语言必学知识点

导读&#xff1a;怎么做好嵌入式&#xff1f;相信这个问题无论问谁你都会得到一句学好C语言&#xff01;今天推荐一篇大佬写的嵌入式C语言知识点总结&#xff0c;非常值得一读。 目录 1 关键字 2 数据类型 3 内存管理和存储架构 4 指针和数组 5 结构类型和对齐 6 预处理…

RDC 2022纪念版开发板-D1S在RT-Smart运行

开发环境 软件 ubuntu20.04VMware Workstation 硬件 RDC2022纪念版开发板全志D1s芯片 材料下载 首先打开虚拟机&#xff0c;创建一个目录存放本次测试的代码&#xff0c;然后克隆RT-Smart用户态代码。 git clone https://github.com/RT-Thread/userapps.git在userapps目…

SMB2协议特性之oplock与lease(下

前期回顾上篇文章我们介绍了oplock/lease的相关概念及其基本工作原理&#xff0c;由于间隔时间较长&#xff0c;忘记的读者可以先去回顾一下。本篇文章带大家了解一下&#xff0c;在实际场景中&#xff0c;oplock/lease是如何工作的。实际场景分析在一些警匪影视剧中&#xff0…

PCI驱动程序框架

PCI驱动程序框架 文章目录PCI驱动程序框架参考资料&#xff1a;一、 PCI驱动框架二、 RK3399驱动致谢参考资料&#xff1a; 《PCI Express Technology 3.0》&#xff0c;Mike Jackson, Ravi Budruk; MindShare, Inc.《PCIe扫盲系列博文》&#xff0c;作者Felix&#xff0c;这是…

【NS2】打印c++函数名字/bash将echo赋值给变量

需求&#xff1a;将tcl在c调用的路由算法名字&#xff08;函数名&#xff09;输出&#xff0c;并作为变量赋值给文件名字&#xff0c;但就怎么将函数名字打印出来就思考了很久&#xff0c;并尝试了其他网站“在shell脚本使用tcl变量、如何在bash脚本打印tcl变量、NS2&#xff0…

【实际开发12】- 经验 experience

目录 1. 经验 experience 1. 无多大价值 , 停留数据展示层面 2. 保证数据一致性问题 3. 新增时 , 可先关注核心基础数据 ( 复杂数据以修改形式完善 ) 4. 新增 / 修改 ( 幂等性处理 ) 5. 增 / 删 / 改 添加日志 , 查询无需日志 6. 需要对接多模块的通用字段设计 : String…

什么是CRM系统 企业如何选择合适的CRM系统

在如今市场竞争激烈情况下&#xff0c;企业更加注重客户的数据和管理&#xff0c;因此逐渐形成了“以客户为核心”的理念。而借助CRM系统管理客户数据已然成为一种趋势。 选择一款适合企业的CRM系统可以帮助企业实现更多的价值。但一些企业在初期根本不了解什么是CRM系统&…

Hadoop安装(一) --- JDK安装

目录 1.安装虚拟机 2.关防火墙 3.修改网络配置文件 4.重启网络服务 5.连接shell 6.安装vim工具 7.免密登陆 8. 开启远程免密登录配置 9.远程登录 10.同步时间 10.1.安装ntpdate 10.2.定时更新时间 10.3.启动定时任务 10.4.查看状态 11.修改计算机名 12.配置ho…

数据仓库的架构以及传统数据库与数据仓库的区别

一、数据仓库的分层架构 数据仓库的数据来源于不同的源数据&#xff0c;并提供多样的数据应用&#xff0c;数据自下而上流入数据仓库后向上层开放应用&#xff0c;而数据仓库只是中间集成化数据管理的一个平台。 1&#xff0c;源数据层&#xff08;ODS&#xff09; 操作性数…

袁树雄和杨语莲究竟什么关系 ,《早安隆回》走红后又是《汉川》

自从《早安隆回》火爆全网后&#xff0c;歌迷们就有一种担心&#xff0c;不知道这首好听的歌曲&#xff0c;究竟还能再够火爆多久。歌迷们的担心也不无道理&#xff0c;毕竟花无百日红&#xff0c;人无千般好&#xff0c;《早安隆回》就是再好听&#xff0c;也不可能红一辈子吧…