Mybatis-Plus学习笔记,包含mybatis-plus基本使用,各种插件使用等等

news2024/11/15 6:55:13

😀😀😀创作不易,各位看官点赞收藏.

文章目录

  • Mybatis-Plus笔记
    • 1、简介
    • 2、Mybatis-Plus Demo 程序
    • 3、Mybatis-Plus 常见注解
    • 4、Mybatis-Plus 条件构造器 Wrapper
    • 5、Mybatis-Plus 插件
      • 5.1、乐观锁插件
      • 5.2、分页插件
      • 5.3、逻辑删除插件
      • 5.4、自动填充
    • 6、代码生成器(新)

Mybatis-Plus笔记

Mybatis-Plus官网:https://baomidou.com/

1、简介

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

特点:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

2、Mybatis-Plus Demo 程序

导入依赖:基于一个 Spring-Boot 整合 mybatis-plus。

<dependencies>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.32</version>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3</version>
    </dependency>
</dependencies>

编写 yaml 配置文件:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serveTimezone=UTC
    username: root
    password: 1234567

# mybatis-plus 配置
mybatis-plus:
  # setting
  configuration:
    # 设置打印日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 开启驼峰映射
    map-underscore-to-camel-case: true
  # mapper 映射文件存放位置
  mapper-locations: classpsth:mapper/**/*.xml
  # 别名扫描包
  type-aliases-package: com.jx.app

编写实体类:

@Data
// 实体对应数据库中表名
@TableName("user")
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Integer version;
    private Integer deleted;
}

编写 mapper 接口、service 接口、mapper 映射文件:

// 只需要继承BaseMapper这个接口,这个接口的实现类就是CRUD代码,注意需要传入一个实体的泛型
public interface UserMapper extends BaseMapper<User> {
}
// service 接口文件,需要继承 IService 接口
public interface UserService extends IService<User> {
}
// 需要继承 ServiceImpl 实现类,两个泛型 mapper 接口和实体类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService  {
}

使用:

@SpringBootApplication
// mapper 接口的扫描包
@MapperScan({"com.jx.app.**.mapper"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class MyTest {

    @Resource
    private UserService userService;

    @Test
    public void test1(){
        // userService 继承了很多方法可以直接使用
        List<User> list = userService.list();
        System.out.println(list);

        // 也可以获取 mapper 接口,也可以使用对应封装了的方法
        BaseMapper<User> baseMapper = userService.getBaseMapper();
        User user = baseMapper.selectById(1);
        System.out.println(user);
    }
}

3、Mybatis-Plus 常见注解

@TableName:作用在实体类上要和数据库表相对应,用于在动态生成 SQL 是确定表名,如果不设置这个注解默认使用实体类名第一个字母小写作为表名。

  • value:指定对应数据库中的表名。
  • keepGlobalPrefix:boolean 值,是否使用全局配置的表前缀,需要设置了全局配置才会生效。
  • 设置全局表前缀:
mybatis-plus:
  global-config:
    db-config:
      # 全局表前缀
      table-prefix: 't_'

@TableId:作用于属性上,表示这个数据为数据库表中的主键,如果实体类不设置这个注解,默认会把 id 名称的属性作为组件,如果连 id 属性名都没有,对于一些主键操作方法会报错。

// 将对应字段指定为主键
/**
 * value属性:如果属性名称与数据库字段名称对应不上,可以使用 value 属性进行映射
 * type属性:指定主键生成策略
 *          IdType.AUTO:数据库自增
 *          IdType.INPUT:用户输入
 *          IdType.ASSIGN_ID:如果插入数据 id 是空的,会使用雪花算法自动生成 id(默认是雪花算法)
 *          IdType.ASSIGN_UUID:使用 UUID 生成 id
 */
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;

全局设置主键生成策略:

# mybatis-plus 配置
mybatis-plus:
  global-config:
    db-config:
      table-prefix: 't_'
      # 全局主键生成策略
      id-type: [assign_uuid|assign_id|auto|input|none]

雪花算法:是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的,后面的代码中有详细的注解。这 64 个 bit 中,其中 1 个 bit 是不用,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。

@TableField:作用在属性上。

// 映射属性名与数据库字段名
/**
 * value:映射的数据库字段名
 * exist:boolean 值,指定这个属性在数据库表中是否存在,默认 true。
 */
@TableField(value = "name", exist = true)
private String name;

4、Mybatis-Plus 条件构造器 Wrapper

image-20230625103823414

Wrapper 条件构造器:一些复杂的 sql 语句可以使用条件构造器来进行数据的查询,在 sql 能执行的一般 Wrapper 都可以实现。

  • UpdateWrapper:封装更新条件构造器。
  • QueryWrapper:封装查询条件构造器。
  • LambdaUpdateWrapper:使用 Lambda 表达式去封装更新条件。
  • LambdaQueryWrapper:使用 Lambda 表达式封装查询条件。

QueryWrapper:查询封装条件构造器,用于查询或则删除。

@Test
public void test2(){
    QueryWrapper<OssFile> wrapper = new QueryWrapper<>();
    // 进行查询条件构造
    wrapper.eq("file_name","test 1");
    // 可以使用链式编程去构造条件
    wrapper.groupBy("create_by").orderByAsc("id");

    // 通过构造器去查询
    List<OssFile> list = fileService.list(wrapper);
    list.forEach(System.out::println);
}

UpdateWrapper:更新封装条件构造器,用于更新数据。

@Test
public void test3(){
    UpdateWrapper<OssFile> wrapper = new UpdateWrapper<>();

    // 进行修改条件构造器
    wrapper.eq("file_name", "test 1").set("file_name", "测试数据");

    // 进行更新操作
    fileService.update(wrapper);
}

LambdaQueryWrapper | LambdaUpdateWrapper:使用 Lambda 表达式构建查询|更新条件构造器。

@Test
public void test4(){
    LambdaQueryWrapper<OssFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    LambdaUpdateWrapper<OssFile> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();

    // 使用 lambda 表达式去完成指定字段
    lambdaQueryWrapper.eq(OssFile::getFileName,"test 2");
    lambdaUpdateWrapper.eq(OssFile::getFileName,"test 2").set(OssFile::getFileName,"测试 2");

    // 查询数据
    List<OssFile> list = fileService.list(lambdaQueryWrapper);
    // 更新数据
    fileService.update(lambdaUpdateWrapper);

    list.forEach(System.out::println);
}

Wrappers:一个工具类可以创建所有的 wrapper 的示例,建议使用。

@Test
public void test7(){
    QueryWrapper<OssFile> queryWrapper = Wrappers.query();
    UpdateWrapper<OssFile> updateWrapper = Wrappers.update();
    LambdaQueryWrapper<OssFile> lambdaQueryWrapper = Wrappers.lambdaQuery();
    LambdaUpdateWrapper<OssFile> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
}

条件优先级调整:对于一些查询条件可能存在执行的先后顺序。

@Test
public void test5(){
    QueryWrapper<OssFile> wrapper = new QueryWrapper<>();
    // and|or方法:相当于给条件加了一个括号,可以改变它的优先级,参数是一个消费型函数接口,就是 wrapper,
    // 然后再通过 wrapper 参数进行条件构建
    wrapper.eq("file_name","test 1").and(e->{
        e.eq("url","test").or().eq("id","1");
    });

    // 通过构造器去查询
    List<OssFile> list = fileService.list(wrapper);
    list.forEach(System.out::println);
}

构建查询字段条件:可以指定查询哪些字段数据,不用把表中的所有字段查询出来。

@Test
public void test6(){
    QueryWrapper<OssFile> wrapper = new QueryWrapper<>();

    // 指定查询的字段,其它没有查询的属性全部为默认值
    wrapper.select("file_name","id","url");

    // 通过构造器去查询
    List<OssFile> list = fileService.list(wrapper);
    list.forEach(System.out::println);
}

构建子查询:可以使用构造器去创建子查询,然后把子查询作为一个表数据进行操作。

@Test
public void test8(){
    QueryWrapper<OssFile> queryWrapper = Wrappers.query();
    // 相当于使用in关键字拆查询,第二个参数是子查询的 SQL 语句
    queryWrapper.inSql("id","select id from oss_file");
    List<OssFile> list = fileService.list(queryWrapper);
    list.forEach(System.out::println);
}
条件名解释例子
allEq(map,boolean)参数为一个map,key为字段的名称,value是对应字段的值,第二个参数为true时值为null的条件会被解析为is Null,为false时会忽略值为null的数据。(默认为true)allEq({id:1,name:"老王",age:null})--->id = 1 and name = '老王' and age is null
eq(v1,v2)v1为数据库字段名,v2是字段对应的值,选择出v1字段等于v2的数据eq("name", "老王")--->name = '老王'
nq(v1,v2)不等于ne("name", "老王")--->name <> '老王'
gt(v1,v2)大于gt("age", 18)--->age > 18
ge(v1,v2)大于等于ge("age", 18)--->age >= 18
lt(v1,v2)小于lt("age", 18)--->age < 18
le(v1,v2)小于等于le("age", 18)--->age <= 18
between(v1,v2,v3)v1为数据库的字段名,v1字段的值在v2和v3之间的数据between("age", 18, 30)--->age between 18 and 30
notBetween(v1,v2,v3)v1的值不在v2和v3之间notBetween("age", 18, 30)--->age not between 18 and 30
like(v1,v2)v1是字段名,v2是值,相当于是一个模糊查询%v2%like("name", "王")--->name like '%王%'
notLike(v1,v2)排除包括模糊查询的其他内容notLike("name", "王")--->name not like '%王%'
likeLeft(v1,v2)相当于%v2,值得左边进行模糊查询likeLeft("name", "王")--->name like '%王'
likeRight(v1,v2)相当于v2%,值得右边进行模糊查询likeRight("name", "王")--->name like '王%'
isNull(v1,v2)v1字段名,v2字段值,查询v1字段值为null的数据isNull("name")--->name is null
isNotNull(v1,v2)查询v1的值不为null的数据isNotNull("name")--->name is not null
in(v1,v2)v1字段名,v2是一个集合,查询v1字段中值是v2集合中的值in("age",{1,2,3})--->age in (1,2,3)
notIn(v1,v2)查询v1字段的值不是v2集合中的值notIn("age",{1,2,3})--->age not in (1,2,3)
inSql(v1,v2)v1字段名,v2是一个子查询的sql语句,将查询的结果作为v1字段的in来使用(查询的字段和v1的字段名需要保持一致)inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
notInSql(v1,v2)不包含v2sql语句中查询到的结果notInSql("id", "select id from table where id < 3")--->id not in (select id from table where id < 3)
groupBy(v…)按照字段进行分组查询,可以传入多个字段groupBy("id", "name")--->group by id,name
orderByAsc(v…)按照字段将查询的结果进行升序排序orderByAsc("id", "name")--->order by id ASC,name ASC
orderByDesc(v…)按照字段将查询的结果进行降序排序orderByDesc("id", "name")--->order by id DESC,name DESC
having(v1,v2)v1是sql语句,v2是可变参数having("sum(age) > {0}", 11)--->having sum(age) > 11
or()主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王'
and()`and(i -> i.eq(“name”, “李白”).ne(“status”, “活着”))—>and (name = ‘李白’ and status <> ‘活着’)

5、Mybatis-Plus 插件

5.1、乐观锁插件

乐观锁:总是认为不会出现问题,所以无论干什么就不会去上锁,如果出现问题就加锁测试。

悲观锁:无论干什么都会觉得出现问题,所有所有操作都会加上锁然后操作。

  • 取出记录时,获取当前 version(需要有一个version字段)。
  • 更新时,带上这个 version。
  • 执行更新时, set version = newVersion where version = oldVersion( newVersion 就是原来的 version+1)。
  • 如果 version 不对,就更新就会失败。

现在有 A 线程在执行更新数据的操作(获取到的 version 为1),但是还没有确定。突然B线程也来修改这一条记录,获取到 version 为1,执行完更新后的版本version就为2,这时 A 线程继续执行操作,发现原先取出来的 version(1) 和表中新的 version(2) 不一样,这就会跟新失败。实际就是在sql语句中添加了一个and 条件判断。

Mybatis-Plus实现乐观锁:

  1. 表中添加一个 version 字段,默认值为1。实体类也加上对应的 version 属性。
  2. 实体类的 version 字段是添加@Version注解,表示是一个乐观锁。
@Version
private Integer version;
  1. 编写配置类MybatisPlusConfig
@Configuration
public class MybatisPlusConfig {
    
    // 添加Mybatis-Plus的插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加乐观锁的插件,也可以添加其他的插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}
  1. 测试成功的乐观锁:使用乐观锁之前需要将这个实体的version查询出来携带到查询实体中
@Test
public void updateTest(){
    // 使用乐观锁之前需要将这个实体的version查询出来携带到查询实体中
    User user = userMapper.selectById(1484525749204516866L);
    user.setName("赵六");
    int nums = userMapper.updateById(user);
    System.out.println(nums);
}

image-20220122170256062

  1. 测试失败的乐观锁
@Test
public void updateTest1(){
    // 线程A
    User user = userMapper.selectById(1484525749204516866L);
    user.setName("田七");
    // 线程B
    User user2 = userMapper.selectById(1484525749204516866L);
    user.setName("张三");
    // 线程B比线程A先执行操作,并更新了version为3
    userMapper.updateById(user2);
    // 线程A后执行更新操作,发现version不合法,更新就不会成功
    userMapper.updateById(user);
}

image-20220122174412914

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime

  • 整数类型下 newVersion = oldVersion + 1

  • newVersion会回写到entity中仅支持updateById(id)update(entity, wrapper)` 方法

  • update(entity, wrapper) 方法下, wrapper 不能复用 !!!

5.2、分页插件

Mybatis-Plus 中内置了分页插件,通过简单的分页插件的配置就可以使用了。

  1. 编写配置类。
@Configuration
public class MybatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 使用对应的插件
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
  1. 编写好配置文件后就可以使用分页插件了,内置Page对象,可以直接使用这个对象进行分页查询
// 分页的测试
@Test
public void pageTest(){
    // 参数1:查询的页码(为负数默认为第一页); 参数2:一页的数量(为负数就查询所有的数据); 泛型的查询的实体类
    Page<User> page = new Page<>(1, -1);
    // 进行查询,参数1:Page对象,第二个参数是Wrapper条件对象
    // 查询完成后,将查询的数据都封装到了传入的page对象中
    userMapper.selectPage(page,null);
    // 获取查询的数据
    List<User> users = page.getRecords();
    for (User user : users) {
        System.out.println(user);
    }
    System.out.println("================");
    // 数据的总页数
    long pages = page.getPages();
    System.out.println(pages);
    System.out.println("================");
    // 当前的页码
    long current = page.getCurrent();
    System.out.println(current);
    System.out.println("================");
    // 一页的数量
    long size = page.getSize();
    System.out.println(size);
    System.out.println("================");
    // 总的数据数
    long total = page.getTotal();
    System.out.println(total);
}

5.3、逻辑删除插件

物理删除:直接从数据库中删除,数据库中数据就不存在了。

逻辑删除:在数据库中没有被移除,而是通过一个字段表示是否被删除的状态,例如 0 表示未删除1表示已删除,但是并不是从数据库中删除了。

  • 在数据库中添加deleted字段,用于标识是否删除,默认值为 0。在实体类对应字段上使用 @TableLogic 标识为逻辑删除属性。
// 逻辑删除的注解
@TableLogic
private Integer deleted;
  • 指定逻辑删除对应的值。
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 也可以不用设置
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值
      logic-not-delete-value: 0 # 逻辑未删除值

注意:设置了逻辑删除后,在以后的查询都会在查询 SQL 语句中去拼接对应逻辑删除字段的条件。

5.4、自动填充

​ 在一些操作中某一些操作不需要手动去完成,直接可以通过自动去完成操作。例如创建的时间和更新的时间,直接通过系统的时间自动去完成操作。

数据库自动填充:添加 create_timeupdate_time 两个字段,这两个字段的是 timestamp 类型,在数据库中添加配置就能完成自动操作。

image-20220121220117272

​ 这样向表中添加数据时,create_time 字段就会有一个当前系统的默认值;更新的时候,update_time 字段的日期也会更新,即使 sql 语句中没有更新时间。但是在实际工作中不会接触到数据库,只会进行sql的操作。

Mybatis-Plus 自动填充:Mybatis-Plus使用的是代码来进行的自动填充,进行下面操作完成。

  1. 在实体类上添加注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    // 当插入的时候进行填充
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    // 当插入和更新的时候自动填充
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}
  1. 编写处理器来进行自动填充
// 需要将这个处理类放入spring容器中
@Component
public class MyMetaObjectHandler implements MetaObjectHandler{
    
    // 需要实现MetaObjectHandler接口,并实现这两个方法
    // 插入时的自动填充
    @Override
    public void insertFill(MetaObject metaObject) {    
        // 三个参数,(填充的实体属性名、填充的值、metaObject)
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
	}

    // 更新时的自动填充
    @Override
    public void updateFill(MetaObject metaObject) {
        // 三个参数,(填充的实体属性名、填充的值、metaObject)
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

6、代码生成器(新)

  1. 导入依赖:
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>
  1. 编写代码生成的代码
public static void main(String[] args) {
    // 获取项目的根目录
    String projectPath = System.getProperty("user.dir");
    System.out.println(projectPath);
    // 代码生成
    FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serveTimezone=UTC",
                             "root", "1234567")
        .globalConfig(builder -> {
            builder.author("xiaotanke") // 设置作者
                .enableSwagger() // 开启 swagger 模式
                //                            .fileOverride() // 覆盖已生成文件
                .disableOpenDir()   // 不打开资源管理器
                .outputDir(projectPath); // 指定输出目录
        })
        .packageConfig(builder -> {
            builder.parent("com.xiaotanke") // 设置父包名
                .moduleName("system") // 设置父包模块名
                .pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath)); // 设置mapperXml生成路径
        })
        .strategyConfig(builder -> {
            builder.addInclude("user") // 设置需要生成的表名
                .addTablePrefix("t_", "c_"); // 设置过滤表前缀
        })
        .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
        .execute();
}

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

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

相关文章

Vue + Element-ui组件上传图片报错问题解决方案

在前端开发中&#xff0c;我们经常需要模拟网络请求以进行单元测试或开发调试。而在模拟网络请求时&#xff0c;我们常常会使用到MockXMLHttpRequest对象。MockXMLHttpRequest对象是一个用于模拟XMLHttpRequest对象的工具&#xff0c;它提供了一种简单的方式来模拟网络请求&…

【uniapp】实现买定离手小游戏

前言 最近玩了一个小游戏&#xff0c;感觉挺有意思&#xff0c;打算放进我的小程序【自动化小助手】里面&#xff0c;“三张押一张&#xff0c;专押花姑娘&#xff01;”&#xff0c;从三张卡牌&#xff0c;挑选一张&#xff0c;中奖后将奖励进行发放&#xff0c;并且创建下一…

【Linux线程】第一章||理解线程概念+创建一个线程(附代码加讲解)

线程概念 &#x1f335;什么是线程&#x1f332;线程和进程的关系&#x1f384;线程有以下特点&#xff1a;&#x1f333; 线程的优点&#x1f334; 线程的缺点&#x1f331;线程异常&#x1f33f;线程用途 ☘️手动创建一个进程&#x1f340;运行 &#x1f335;什么是线程 在L…

【需求响应DR】一种新的需求响应机制DR-VCG研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【技术架构】技术架构的演进

文章目录 前言1.名词解释(常见概念)1.1 应用&#xff08;Application&#xff09; / 系统&#xff08;System&#xff09;1.2 模块&#xff08;Module&#xff09; / 组件&#xff08;Component&#xff09;1.3 分布式&#xff08;Distributed&#xff09;1.4 集群&#xff08;…

AOP概念 和 使用

目录 AOP的概念 什么是AOP? 什么是SpringAOP? 为什要⽤ AOP? AOP的作用&#xff1f; AOP的组成 通知 AOP的实现 1. 添加 Spring AOP 框架⽀持。 2. 定义切面和切点。 3. 定义通知。 切点表达式 AOP的概念 什么是AOP? AOP&#xff08;Aspect Oriented Programm…

工程师分享:如何解决传导干扰?

电磁干扰 EMI 中电子设备产生的干扰信号是通过导线或公共电源线进行传输&#xff0c;互相产生干扰称为传导干扰。传导干扰给不少电子工程师带来困惑&#xff0c;如何解决传导干扰&#xff1f; 找对方法&#xff0c;你会发现&#xff0c;传导干扰其实很容易解决&#xff0c;只要…

献给大一新生的JavaSE入门篇章 大三秋招JavaSE

Java反射 反射实现有哪些? Class.forName(“com.jdbc.cj.Driver.mysql”) 类名.class 对象名.getClass() 反射优缺点有哪些? 优点: 能够动态的获取类的实例&#xff0c;提高灵活性 缺点: 会降低性能&#xff0c;解决办法: 1. 如果多次创建某个对象的实例&#xff0c;使用…

Pixelmator Pro 3.3.10 Mosaic (macOS Universal) - 专业图像编辑工具

Pixelmator Pro 3.3.10 Mosaic (macOS Universal) - 专业图像编辑工具 请访问原文链接&#xff1a;https://sysin.org/blog/pixelmator-pro-3/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Pixelmator Pro 真正基于 Apple M…

机器学习算法实现(基于numpy)

《机器学习公式推导与代码实现》学习笔记&#xff0c;记录一下自己的学习过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 这篇博客是将笔者边学边刷《机器学习公式推导与代码实现》的模型跟代码记录下来&#xff0c;部分地方结合自己的思考对原作者的代码有一定的改动…

【自定义图库】

sld文件 前段时间,有网友委托我帮他做一个家具的图库。 首先,做图库的方法有很多,最简单的是MFC拖控件然后自己把做好的bmp图贴进去就可以了,麻烦一点的是sld文件,最麻烦 是用blockview做。 下面先说说3种办法的区别: 首先,如果用MFC拖控件的办法,最简单也最方便,用st…

安全帽检测+反光衣检测+工作服检测数据集

安全帽检测反光衣检测工作服检测数据集下载地址分享:https://download.csdn.net/download/qq_34717531/88112870

AF 350 tyramide,AlexaFluor350 TSA,AF350酪胺,荧光标记试剂

文章资料汇总来源于&#xff1a;陕西新研博美生物科技有限公司小编MISSwu​ PART1----产品描述 AF350 tyramide&#xff08;AlexaFluor350酪酰胺&#xff09;&#xff0c;用于荧光标记的试剂&#xff0c;Tyramide信号放大&#xff08;TSA&#xff09;已被证明是一种特别通用且…

SAS-input和put的使用

在SAS中经常会遇到数值型变量与字符型变量之间进行相互转换&#xff0c;如何进行转换呢&#xff1f; 一、字符型转数值型 方法1&#xff1a;字符型变量通过运算进行转换&#xff0c;如Numeric Character * 1。运算符可以转换&#xff0c;但是会有NOTE提示&#xff0c;不推荐…

一个外贸业务员的鸡飞蛋打

最近在论坛上看到一个案例&#xff0c;案例是一个是SOHO的业务员从他朋友厂子拿货, 然后他发现他的前同事在他朋友的厂子做sales director&#xff0c;然后最近一个客户A出货&#xff0c;这个小伙伴就去他朋友的工厂做发货前的质检&#xff0c;正好碰到以前的一个同事也去他朋友…

【Docker】Docker安全性与安全实践(五)

前言&#xff1a; Docker安全性的作用和意义在于确保容器化应用程序和镜像的隔离性、保护数据和系统资源、防止恶意攻击&#xff0c;以及提高应用的整体安全性。 文章目录 1. Docker安全性1.1 隔离性1.2 镜像安全1.3 特权访问1.4 数据保护 2. Docker安全实践2.1 使用官方镜像或…

管理类联考——数学——趣味篇——可视化——安装Manim软件

Manim: 一个数学可视化的动画引擎 官网&#xff1a;https://3b1b.github.io/manim/index.html 名词解析 python3.7是python语言的解释器, 运行python程序的环境必备品. 这个没啥说的,大家都能懂. 虽然官方建议3.7,但是我用3.8发现也没问题.考虑未来的历史进程,大伙最好还是装…

Windows Subsystem for Android (WSA) 下载:在 Windows 11 上运行 Android 应用 (July 2023)

Windows Subsystem for Android (WSA) 下载&#xff1a;在 Windows 11 上运行 Android 应用 (July 2023) 适用于 Android™️ 的 Windows 子系统&#xff0c;2023 年 7 月更新&#xff1a;2306.40000.4.0 请访问原文链接&#xff1a;https://sysin.org/blog/wsa/&#xff0c;…

探讨高校公共建筑能耗监测系统的设计与应用

安科瑞 华楠 摘要&#xff1a;在资源节约型社会建设进程中&#xff0c;高校公共建筑能耗管理存在问题已经成为办学成本加大、社会资源浪费的桎梏。在各级政府的推动下&#xff0c;高校公共建筑能耗监测系统建设在探索中发展&#xff0c;依托互联网大数据技术逐步实现能耗管理信…

跨域冲突问题解决

1、问题分析 服务端和nginx代理 都做了跨域配置&#xff0c;导致请求头重复 headers 里面有两个重复的 Access-Control-Allow-Origin Access-Control-Allow-Methods Access-Control-Allow-Credentials 2、解决方法 在nginx去除服务端的跨域配置 proxy_hide_header Access-…