MyBatis-Plus学习总结

一.快速入门

(一)简介

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

(二)快速入门

1.准备数据库脚本
2.准备boot工程
(1)创建空项目
(2)创建maven模块
3.导入依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.5</version>
    </parent>
    <groupId>com.yan</groupId>
    <artifactId>mybatis-plus-base-quick-01</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- 测试环境 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <!-- mybatis-plus  -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>

        <!-- 数据库相关配置启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- druid启动器的依赖  -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-3-starter</artifactId>
            <version>1.2.18</version>
        </dependency>

        <!-- 驱动类-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>

    </dependencies>


    <!--    SpringBoot应用打包插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
4.配置文件和启动类

完善连接池配置:

通过源码分析,druid-spring-boot-3-starter目前最新版本是1.2.18,虽然适配了SpringBoot3,但缺少自动装配的配置文件,需要手动在resources目录下创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,文件内容如下!

com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure

连接池配置

resources/application.yml

# 连接池配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      url: jdbc:mysql:///day01
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

启动类

@MapperScan("com.xx.mapper")
@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class,args);
    }
    
}
5.编写实体类和Mapper接口 
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

继承mybatis-plus提供的基础Mapper接口,自带crud方法!

public interface UserMapper extends BaseMapper<User> {
    //定义方法

}
6.编写测试类
@SpringBootTest
public class SpringBootMybatisPlusTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test() {
        List<User> list = userMapper.selectList(null);
        System.out.println("users:" + list);
    }

}

二.核心功能

(一)基于Mapper接口的crud

通用 CRUD 封装BaseMapper接口,Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器! 内部包含常见的单表操作!

Insert方法

// 插入一条记录
// T 就是要插入的实体对象
// 默认主键生成策略为雪花算法(后面讲解)
int insert(T entity);

Delete方法

// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

// 根据 ID 删除
int deleteById(Serializable id);

// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

Update方法

// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, 
            @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);

// 根据 ID 修改  主键属性必须值
int updateById(@Param(Constants.ENTITY) T entity);

实体类属性值为Null则不会修改,所以,实体类的属性必须是包装类型,如果不是,例如int类型,会赋初值为0,会将数据库的年龄修改为0

whereWrapper为null,表示全部修改

Select方法

// 根据 ID 查询
T selectById(Serializable id);

// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

 (二)自定义和多表映射

mybatis-plus: # mybatis-plus的配置
  # 默认位置 private String[] mapperLocations = new String[]{"classpath*:/mapper/**/*.xml"};    
  mapper-locations: classpath:/mapper/*.xml
public interface UserMapper extends BaseMapper<User> {

    //正常自定义方法!
    //可以使用注解@Select或者mapper.xml实现
    List<User> queryAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace = 接口的全限定符 -->
<mapper namespace="com.xxx.mapper.UserMapper">

   <select id="queryAll" resultType="user" >
       select * from user
   </select>
</mapper>

 (三)基于Service接口CRUD

1.接口继承IServce接口
public interface UserService extends IService<User> {
}
 2.类继承ServiceImpl实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{

}
3.测试
@SpringBootTest
public class SpringBootMybatisPlusTest {
    @Autowired
    private UserService userService;

    @Test
    public void test_save() {
        ArrayList<User> lists = new ArrayList<>();
        User user = new User(null, "张三三", 32, "22445432@qq.com");
        User user2 = new User(null, "李四四", 32, "3423423@qq.com");
        lists.add(user);
        lists.add(user2);
        userService.saveBatch(lists);
    }

    @Test
    public void test_saveOrUpdate() {
        User user = new User(null, "王五", 23, "234234@qq.com");
        //id有值则为修改,否则为更新
        boolean b = userService.saveOrUpdate(user);
    }

    @Test
    public void test_getOrList() {
        User byId = userService.getById(1);//返回单个对象
        List<User> list = userService.list(null);//查询全部
    }
}

 (四)分页查询实现

1.导入分页插件

@SpringBootApplication
@MapperScan("com.yan.mapper")
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Bean
    public MybatisPlusInterceptor plusInterceptor() {
        //mybaits-plus的插件集合[加入到这个集合中即可,分页插件.....]
        MybatisPlusInterceptor mybatisPlusInterceptor
                = new MybatisPlusInterceptor();
        //分页插件
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}
2.非自定义的mapper方法使用分页

@SpringBootTest
public class SpringBootMybatisPlusTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testPage(){
        Page<User> page = new Page<>(1,3);
        userMapper.selectPage(page,null);
        //结果 page最后也会被封装结果
        long current = page.getCurrent();
        long size = page.getSize();
        List<User> records = page.getRecords();
        long total = page.getTotal();
    }

}
 3.自定义的mapper方法使用分页
(1)定义接口

传入参数携带Ipage接口

返回结果为IPage

public interface UserMapper extends BaseMapper<User> {
    //定义一个根据年龄参数查询,并且分页的方法
    IPage<User> queryByAge(IPage<User> page,@Param("age") Integer age);
}
 (2)接口实现
<?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.yan.mapper.UserMapper">
<select id="queryByAge" resultType="com.yan.pojo.User">
    select *
    from user
    where age > #{age}
</select>

</mapper>
(3)测试
  @Test
    public void testPage2(){
        Page<User> page = new Page<>(1,3);
        IPage<User> userIPage = userMapper.queryByAge(page, 4);
    }

 (五)条件构造器的使用

1.基于QueryWrapper组装条件
(1)案例

 查询用户名包含a,年龄在20--30之间,邮箱不为Null的,按年龄降序查询用户,如果年龄相同则按id升序排列

  @Test
    public void test_01() {
        //查询用户名包含a,年龄在20--30之间,邮箱不为Null的,按年龄降序查询用户,如果年龄相同则按id升序排列
        QueryWrapper<User> queryWrapper
                = new QueryWrapper<>();
        queryWrapper.like("name", "a")
                .between("age", 20, 30)
                .isNotNull("email")
                .orderByDesc("age")
                .orderByAsc("id");

        userMapper.selectList(queryWrapper);
    }

删除email为空的用户 

   @Test
    public void test2() {
        //删除邮箱为空的
        QueryWrapper<User> queryWrapper
                = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int delete = userMapper.delete(queryWrapper);
    }

将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改

    @Test
    public void test3() {
        QueryWrapper<User> queryWrapper
                = new QueryWrapper<>();
        queryWrapper.gt("age", 20)
                .like("name", "a")
                .or()
                .isNull("email");
        User user = new User(null, "test", 88, "fdfsdf");
        userMapper.update(user, queryWrapper);
    }
(2)组装条件 
(3)指定列映射

要给User对象设置无参构造器!

 @Test
    public void test4() {
        QueryWrapper<User> queryWrapper
                = new QueryWrapper<>();
        queryWrapper.gt("id", 1)
                .select("name", "age");
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }
 (4)condition判断组织条件
public Children eq(boolean condition, R column, Object val) {
    return this.addCondition(condition, column, SqlKeyword.EQ, val);
}
 @Test
    public void test6() {
        //前端传入两个参数
        //name不为空,作为条件查询
        //age>18 作为条件,查询=
        String name = "";
        Integer age = 19;
        QueryWrapper<User> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq(StringUtils.isNotBlank(name), "name",name)
                .eq(age != null && age > 18, "age", age);
        userMapper.selectList(objectQueryWrapper);
    }
2.UpdateWrapper组装条件

使用updateWrapper可以随意设置列的值!! 

使用queryWrapper + 实体类形式可以实现修改,但是无法将列值修改为null值!

将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改

@SpringBootTest
public class MybatisPlusUpdateWrapper {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test1() {
        UpdateWrapper<User> objectUpdateWrapper = new UpdateWrapper<>();
        objectUpdateWrapper.gt("age", 20)
                .like("name", "a")
                .or().isNotNull("email")
                .set("email", null)
                .set("age", 90);
        userMapper.update(null, objectUpdateWrapper);
    }
}
3.LambdaQueryWrapper组装条件 

Java 8 支持以下几种方法引用的形式:

1.静态方法引用: 引用静态方法,语法为 `类名::静态方法名`。
2.实例方法引用: 引用实例方法,语法为 `实例对象::实例方法名`。
3.对象方法引用:引用特定对象的实例方法,语法为 `类名::实例方法名`。
4.构造函数引用: 引用构造函数,语法为 `类名::new`。

相比于 QueryWrapper,LambdaQueryWrapper 使用了实体类的属性引用(例如User::getName、User::getAge),而不是字符串来表示字段名,这提高了代码的可读性和可维护性 

@SpringBootTest
public class LambdaQueryWrapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void test1() {
        //将年龄在20到100,并且用户名中包含a或者邮箱不为Null 的用户信息修改
        LambdaQueryWrapper<User> objectUpdateWrapper = new LambdaQueryWrapper<>();
        objectUpdateWrapper.between(User::getAge, 20,100)
                .like(User::getName, "a")
                .or().isNotNull(User::getEmail);
        User user = new User(null, "test1", 98, "eefe");
        userMapper.update(user, objectUpdateWrapper);
    }
}
4.LambdaUpdateWrapper
@SpringBootTest
public class LambdaQueryWrapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void test1() {
        //将年龄在20到100,并且用户名中包含a或者邮箱不为Null 的用户信息修改
        LambdaUpdateWrapper<User> objectUpdateWrapper = new LambdaUpdateWrapper<>();
        objectUpdateWrapper.between(User::getAge, 20,100)
                .like(User::getName, "a")
                .or().isNotNull(User::getEmail)
                .set(User::getEmail, null)
                .set(User::getAge, 91);
        userMapper.update(null, objectUpdateWrapper);
    }
}
5.核心注解使用
(1)@TableName注解 

- 描述:表名注解,标识实体类对应的表
- 使用位置:实体类

特殊情况:如果表名和实体类名相同(忽略大小写)可以省略该注解!

其他解决方案:全局设置前缀 

mybatis-plus: # mybatis-plus的配置
  global-config:
    db-config:
      table-prefix: sys_ # 表名前缀字符串
(2)@TableId 注解

- 描述:主键注解
- 使用位置:实体类主键字段

属性类型必须指定默认值描述
valueString""主键字段名
typeEnumIdType.NONE指定主键类型

 IdType属性可选值:

描述
AUTO数据库 ID 自增 (mysql配置主键自增长)
ASSIGN_ID(默认)分配 ID(主键类型为 Number(Long )或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
@TableName("sys_user")
public class User {
    @TableId(value="主键列名",type=主键策略)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
mybatis-plus:
  configuration:
    # 配置MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 配置MyBatis-Plus操作表的默认前缀
      table-prefix: t_
      # 配置MyBatis-Plus的主键策略
      id-type: auto

在以下场景下,添加`@TableId`注解是必要的:

1. 实体类的字段与数据库表的主键字段不同名:如果实体类中的字段与数据库表的主键字段不一致,需要使用`@TableId`注解来指定实体类中表示主键的字段。


2. 主键生成策略不是默认策略:如果需要使用除了默认主键生成策略以外的策略,也需要添加`@TableId`注解,并通过`value`属性指定生成策略。

雪花算法(Snowflake Algorithm)是一种用于生成唯一ID的算法。它由Twitter公司提出,用于解决分布式系统中生成全局唯一ID的需求。

在传统的自增ID生成方式中,使用单点数据库生成ID会成为系统的瓶颈,而雪花算法通过在分布式系统中生成唯一ID,避免了单点故障和性能瓶颈的问题。

(3)@TableField

描述:字段注解(非主键)

属性类型必须指定默认值描述
valueString""数据库字段名
existbooleantrue是否为数据库表字段

 MyBatis-Plus会自动开启驼峰命名风格映射!!!

@TableName("sys_user")
public class User {
    @TableId
    private Long id;
    @TableField("nickname")
    private String name;
    private Integer age;
    private String email;
}

三.高级拓展

(一)逻辑删除字段

1.概念

- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

逻辑删除以后,没有真正的删除语句,删除改为修改语句!

2.实现
(1)数据库添加逻辑删除字段

数据库和实体类添加逻辑删除字段

ALTER TABLE USER ADD deleted INT DEFAULT 0 ;  # int 类型 1 逻辑删除 0 未逻辑删除
(2)实体类添加逻辑删除属性
@Data
public class User {

   // @TableId
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    
    @TableLogic
    //逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 1 
    private Integer deleted;
}
  (3) 指定逻辑删除字段和属性值
     a.单一指定
@Data
public class User {

   // @TableId
    private Integer id;
    private String name;
    private Integer age;
    private String email;
     @TableLogic
    //逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 1 
    private Integer deleted;
}
     b.全局指定
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
    (4)测试 
 @Test
    public void test_02() {
        userMapper.deleteById(1);
    }

(二)乐观锁实现

1.思路

乐观锁:

乐观锁的基本思想是,认为并发冲突的概率较低,因此不需要提前加锁,而是在数据更新阶段进行冲突检测和处理。乐观锁的核心思想是"先修改,后校验"。在乐观锁的应用中,线程在读取共享资源时不会加锁,而是记录特定的版本信息。当线程准备更新资源时,会先检查该资源的版本信息是否与之前读取的版本信息一致,如果一致则执行更新操作,否则说明有其他线程修改了该资源,需要进行相应的冲突处理。乐观锁通过避免加锁操作,提高了系统的并发性能和吞吐量,但是在并发冲突较为频繁的情况下,乐观锁会导致较多的冲突处理和重试操作。

悲观锁:

悲观锁的基本思想是,在整个数据访问过程中,将共享资源锁定,以确保其他线程或进程不能同时访问和修改该资源。悲观锁的核心思想是"先保护,再修改"。在悲观锁的应用中,线程在访问共享资源之前会获取到锁,并在整个操作过程中保持锁的状态,阻塞其他线程的访问。只有当前线程完成操作后,才会释放锁,让其他线程继续操作资源。这种锁机制可以确保资源独占性和数据的一致性,但是在高并发环境下,悲观锁的效率相对较低。

2.解决方案

乐观锁

a.版本号/时间戳:为数据添加一个版本号或时间戳字段,每次更新数据时,比较当前版本号或时间戳与期望值是否一致,若一致则更新成功,否则表示数据已被修改,需要进行冲突处理。

b.CAS(Compare-and-Swap):使用原子操作比较当前值与旧值是否一致,若一致则进行更新操作,否则重新尝试。

c.无锁数据结构:采用无锁数据结构,如无锁队列、无锁哈希表等,通过使用原子操作实现并发安全。

悲观锁

a.锁机制:使用传统的锁机制,如互斥锁(Mutex Lock)或读写锁(Read-Write Lock)来保证对共享资源的独占访问。
b.数据库锁:在数据库层面使用行级锁或表级锁来控制并发访问。
c.信号量(Semaphore):使用信号量来限制对资源的并发访问。

3.使用mybatis-plus数据实现乐观锁
(1) 添加版本号更新插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
}
(2)乐观锁字段添加@Version注解

数据库也需要添加version字段

@Version
private Integer version;

ALTER TABLE USER ADD VERSION INT DEFAULT 1 ;  # int 类型 乐观锁字段

(3)正常更新使用即可
    @Test
    public void testQuick7(){
        //步骤1: 先查询,在更新 获取version数据
        //同时查询两条,但是version唯一,最后更新的失败
        User user  = userMapper.selectById(5);
        User user1  = userMapper.selectById(5);

        user.setAge(20);
        user1.setAge(30);

        userMapper.updateById(user);
        //乐观锁生效,失败!
        userMapper.updateById(user1);
    }

(三)防止全表更新和删除实现

针对 update 和 delete 语句 作用: 阻止恶意的全表更新删除

添加防止全表更新和删除拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
  MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
  return interceptor;
}
}

当发生全表删除和全表更新时,mybatis会自动阻止 

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

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

相关文章

交易文本数据:情感分析 -另类数据交易- 舆情数据

交易文本数据:情感分析 这是三章中的第一章,专门介绍使用自然语言处理(NLP)和机器学习从文本数据中提取交易策略信号。 文本数据内容丰富但高度非结构化,因此需要更多预处理才能使ML算法提取相关信息。一个关键挑战是在不丢失其含义的情况下将文本转换为数值格式。我们将介绍…

从大量文本中挖掘‘典型意见‘-基于DBSCAN的文本聚类实战

文本聚类,是一个无监督学习里面非常重要的课题,无论是在风控还是在其他业务中,通过对大规模文本数据的分析,找出里面的聚集观点,有助于发现新的问题或者重点问题。 通过对评论文本的分析,我们可以发现消费者关注的产品或服务痛点 通过对店铺商品标题的文本聚类,可以知…

RS485和CAN电路中的TVS管选择

在RS485和CAN电路设计中&#xff0c;经常要考虑“静电和浪涌保护”&#xff0c;怎么选择TVS管&#xff0c;很少有人讲解。 1、先了解TVS管 TVS管有单向管和双向管&#xff0c;通常后缀为CA的是双向TVS管&#xff0c;只有字母A的是单向TVS管。见下图&#xff1a; 2、TVS选择依…

【LeetCode:2786. 访问数组中的位置使分数最大 + 递归 + 记忆化缓存 + dp】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

关于element-plus中el-select自定义标签及样式的问题

关于element-plus中el-select自定义标签及样式的问题 我这天天的都遇到各种坑&#xff0c;关于自定义&#xff0c;我直接复制粘贴代码都实现不了&#xff0c;研究了一下午&#xff0c;骂骂咧咧了一下午&#xff0c;服气了。官网代码实现不了&#xff0c;就只能 “ 曲线救国 ”…

RK3568技术笔记七 安装Ubuntu Linux

在新弹出的窗口中&#xff0c;单击“CD/DVD &#xff08;SATA&#xff09;”。如下图所示&#xff1a; 在右侧选择“使用ISO映像文件”。然后单击“浏览”&#xff0c;找到SAIL-RK3568开发板光盘->通用工具->虚拟机Ubuntu->ubuntu-18.04.4-desktop-amd64.iso。最后点击…

Java面试题汇总(持续更新.....)

Java面试题 1. JVM & JDK & JRE Java虚拟机&#xff08;JVM&#xff09;是运行Java字节码的虚拟机&#xff0c;JVM有针对不同系统的特定实现&#xff0c;目的是使用相同的字节码&#xff0c;他们都会给出相同的结果。字节码和不同系统的JVM实现是Java语言“一次编译、…

制作ubuntu18.04 cuda10.2+ROS1的 docker镜像

使用的硬件平台为Xavier NX&#xff0c;系统环境如下图&#xff1a; 搭建docker环境需求跟实际环境一致如下图&#xff1a; 从官网获取cuda10.2版本只有支持x86的&#xff0c;如下网站: https://developer.nvidia.com/cuda-10.2-download-archive 下面从sdk manager中获取方法的…

PAT B1011. A+B和C

题目描述 给定区间[-,]内的三个整数A、B和C,请判断AB是否大于C。 输入格式 第一行给出正整数T(≤10),即测试用例的个数。随后给出T组测试用例,每组占一行,顺序给出A、B和C。整数间以空格分隔。输出格式 对每组测试用例,如果AB>C,在一行中输出“Case#: true";否则输出“…

13.ChatGPT 大模型训练核心技术

ChatGPT 大模型训练核心技术 从 GPT-3 到 ChatGPT 的大模型训练技术演进 基于RLHF训练大模型的三阶段 • Domain Specific Pre-Training: Fine-tune a pre-trained LLM on raw text with a Causal Language Modelling Objective.• Supervised fine-tuning: Fine-tune the do…

填表统计预约打卡表单系统(FastAdmin+ThinkPHP+UniApp)

填表统计预约打卡表单系统&#xff1a;一键搞定你的预约与打卡需求​ 填表统计预约打卡表单系统是一款基于FastAdminThinkPHPUniApp开发的一款集信息填表、预约报名&#xff0c;签到打卡、活动通知、报名投票、班级统计等功能的自定义表单统计小程序。 &#x1f4dd; 一、引言…

深入解析B树:数据结构、存储结构与算法优势

一、引言 在计算机科学中&#xff0c;数据结构和算法是核心内容。它们的选择和应用直接影响程序的效率和性能。B树&#xff08;B-Tree&#xff09;作为一种自平衡的多叉树数据结构&#xff0c;广泛应用于数据库和文件系统中。本文将详细介绍B树的数据结构模型、存储结构&#…

算法金 | 再见!!!K-means

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 今天我们来聊聊达叔 6 大核心算法之 —— k-means 算法。最早由斯坦福大学的 J. B. MacQueen 于 1967 年提出&#xff0c;后来经过许多…

Liquibase(Oracle SQLcl集成版)简明示例

本文使用的是Oracle SQLcl中集成的Liquibase&#xff0c;而非开源版Liquibase。 Liquibase的快速入门可以参见Liquibase Core Concepts。需要了解一下概念&#xff1a; Change log&#xff1a;基于文本的更改日志文件按顺序列出对数据库所做的所有更改Change set&#xff1a;…

BFD(简单配置实验)

实验拓扑 配置接口IP地址 正常互通 配置静态BFD 查看状态&#xff1a;为UP 与静态路由联动 查看静态路由状态为active 将交换机的接口down掉 BFD的状态为down 再次查看静态路由的状态为Inactive

C++ | Leetcode C++题解之第151题反转字符串中的单词

题目&#xff1a; 题解&#xff1a; class Solution { public:string reverseWords(string s) {int left 0, right s.size() - 1;// 去掉字符串开头的空白字符while (left < right && s[left] ) left;// 去掉字符串末尾的空白字符while (left < right &…

中国首台!紧随美国,重磅发布100比特中性原子量子计算机

2024年6月11日上午&#xff0c;“武汉量子论坛—2024”隆重开幕&#xff0c;国家自然科学基金委员会主任窦贤康院士&#xff0c;武汉大学校长张平文院士&#xff0c;以及叶朝辉、徐红星、祝世宁等院士出席大会。在会议上&#xff0c;中科酷原重磅发布国内首台原子量子计算机——…

安川机器人MA1440减速机维修方法

一、安川机械臂减速器维修方法 1. 齿轮磨损维修 对于轻微磨损的齿轮&#xff0c;可以通过重新调整啮合间隙来恢复性能。对于严重磨损的齿轮&#xff0c;需要更换新安川MA1440机械手齿轮箱齿轮。 2. 轴承损坏维修 对于损坏的轴承&#xff0c;需要更换新的轴承。在更换过程中&…

Dev C++ 安装及使用方法教程-干活多超详细

Dev C 是一款非常好用&#xff0c;简约的C/C开发工具。可以减少很多创建工程的繁琐步骤&#xff0c;很快的进行开发。对于只用于来写代码的人来说&#xff0c;是比较轻量以及极速的。 Dev C 是一个windows下的c和c程序的集成开发环境。它使用mingw32/gcc编译器&#xff0c;遵循…

计算机网络(8) Finite State Machines(有限状态机)

一.建立连接&#xff08;三次握手&#xff09; 建立连接过程中的状态转换如下&#xff1a; 客户端&#xff1a; 发送SYN CLOSED >>>>>>>>>>>>>>SYN SENT(第一次握手) 接收SYNACK发送ACK …