Mybatis-Plus(企业实际开发应用)

news2024/11/16 0:48:09

一、Mybatis-Plus简介

MyBatis-Plus是MyBatis框架的一个增强工具,可以简化持久层代码开发MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

官网:MyBatis-Plus

当前版本:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.5.3.2</version>
</dependency>

MyBatis-Plus特性:

• 无侵入:只做增强不做改变,不会对现有工程产生影响

• 强大的 CRUD 操作:内置通用 Mapper,少量配置即可实现单表CRUD 操作

• 支持 Lambda:编写查询条件无需担心字段写错

• 支持主键自动生成

• 内置分页插件

开发方式:

• 单独使用 MyBatis-Plus

• 基于 Spring 使用 MyBatis-Plus

基于 SpringBoot 使用 MyBatis-Plus(最常用) 

二、CRUD接口

2.1环境搭建 

①:创建maven工程,并配置相关基础信息

②:配置pom文件

<?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 https://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>2.5.0</version>
        <relativePath/>
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>mp-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

 ③:配置数据源(application.yml)

#数据源
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mp?useSSL=false&serverTimezone=UTC
    username: root
    password: root
#mybatis-plus
mybatis-plus:
  mapper-locations: classpath:/mapper/*Mapper.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl





⑤:创建实体类与表结构(类名与表名对应,属性名与字段名对应)

可以使用MybatisHelper插件自动生成实体类和Mapper

@TableName(value = "`user`")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
    /**
     * 用户id
     */
    @TableId(value = "id", type = IdType.INPUT)
    private Long id;

    /**
     * 用户名
     */
    @TableField(value = "username")
    private String username;

    /**
     * 密码
     */
    @TableField(value = "`password`")
    private String password;

    /**
     * 注册手机号
     */
    @TableField(value = "phone")
    private String phone;

    /**
     * 详细信息
     */
    @TableField(value = "info")
    private String info;

    /**
     * 使用状态(1正常 2冻结)
     */
    @TableField(value = "`status`")
    private Integer status;

    /**
     * 账户余额
     */
    @TableField(value = "balance")
    private Integer balance;

    /**
     * 创建时间
     */
    @TableField(value = "create_time")
    private Date createTime;

    /**
     * 更新时间
     */
    @TableField(value = "update_time")
    private Date updateTime;

    /**
     * 获取用户id
     *
     * @return id - 用户id
     */
    public Long getId() {
        return id;
    }

    /**
     * 设置用户id
     *
     * @param id 用户id
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * 获取用户名
     *
     * @return username - 用户名
     */
    public String getUsername() {
        return username;
    }

    /**
     * 设置用户名
     *
     * @param username 用户名
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * 获取密码
     *
     * @return password - 密码
     */
    public String getPassword() {
        return password;
    }

    /**
     * 设置密码
     *
     * @param password 密码
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * 获取注册手机号
     *
     * @return phone - 注册手机号
     */
    public String getPhone() {
        return phone;
    }

    /**
     * 设置注册手机号
     *
     * @param phone 注册手机号
     */
    public void setPhone(String phone) {
        this.phone = phone;
    }

    /**
     * 获取详细信息
     *
     * @return info - 详细信息
     */
    public String getInfo() {
        return info;
    }

    /**
     * 设置详细信息
     *
     * @param info 详细信息
     */
    public void setInfo(String info) {
        this.info = info;
    }

    /**
     * 获取使用状态(1正常 2冻结)
     *
     * @return status - 使用状态(1正常 2冻结)
     */
    public Integer getStatus() {
        return status;
    }

    /**
     * 设置使用状态(1正常 2冻结)
     *
     * @param status 使用状态(1正常 2冻结)
     */
    public void setStatus(Integer status) {
        this.status = status;
    }

    /**
     * 获取账户余额
     *
     * @return balance - 账户余额
     */
    public Integer getBalance() {
        return balance;
    }

    /**
     * 设置账户余额
     *
     * @param balance 账户余额
     */
    public void setBalance(Integer balance) {
        this.balance = balance;
    }

    /**
     * 获取创建时间
     *
     * @return create_time - 创建时间
     */
    public Date getCreateTime() {
        return createTime;
    }

    /**
     * 设置创建时间
     *
     * @param createTime 创建时间
     */
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * 获取更新时间
     *
     * @return update_time - 更新时间
     */
    public Date getUpdateTime() {
        return updateTime;
    }

    /**
     * 设置更新时间
     *
     * @param updateTime 更新时间
     */
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
}

Mapper 

@Mapper
public interface UserMapper extends BaseMapper<User> {
}
2.2 新增操作

新增操作可以调用BaseMapper中提供的insert方法:

/**
 * 插入一条记录
 *
 * @param entity 实体对象
 */
int insert(T entity);

单元测试方法:

    /**
     * 新增数据
     */
@Test
    public void testInsert(){
        User user = User.builder()
                .username("老八1")
                .password(Base64.getEncoder().encodeToString("123456".getBytes()))
                .phone("18941199302")
                .info("{\"age\": 20, \"intro\": \"青涩老八\", \"gender\": \"female\"}")
                .createTime(Date.from(Instant.now()))
                .updateTime(Date.from(Instant.now()))
                .build();
        userMapper.insert(user);

    }

2.3 删除操作

删除操作可以调用BaseMapper中提供的deleteById和deleteBatchIds方法:

/**
 * 根据 ID 删除
 *
 * @param id 主键ID
 */
int deleteById(Serializable id);

单元测试方法:  

    /**
     * 删除数据
     */
    @Test
    public void testDelete(){
        userMapper.deleteById(7L);
    }
/**
 * 删除(根据ID 批量删除)
 *
 * @param idList 主键ID列表(不能为 null 以及 empty)
 */
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

 单元测试方法:

//根据id批量删除数据
    int batchIds = userMapper.deleteBatchIds(1L,2L,3L);//可变参数
    System.out.println(batchIds);
2.4 修改操作
/**
 * 根据 ID 修改
 *
 * @param entity 实体对象
 */
int updateById(@Param(Constants.ENTITY) T entity);

 单元测试方法:

    /**
     * 根据Id修改
     */
    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(2L);
        user.setUsername("老六");
        userMapper.updateById(user);
    }

2.5 查询操作
/**
 * 根据 ID 查询
 *
 * @param id 主键ID
 */
T selectById(Serializable id);

单元测试:

    /**
     * 根据Id查找
     */
    @Test
    public void testSelect(){
        User user = userMapper.selectById(1);
        System.out.println(user);
    }
/**
 * 查询(根据ID 批量查询)
 *
 * @param idList 主键ID列表(不能为 null 以及 empty)
 */
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

 单元测试:

   //根据id批量查询数据
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1625307405933957121L, 1625310776384380930L));
    System.out.println(users);
/**
 * 根据 entity 条件,查询全部记录(并翻页)
 *
 * @param page         分页查询条件(可以为 RowBounds.DEFAULT)
 * @param queryWrapper 实体对象封装操作类(可以为 null)
 */
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

注意如果要实现分页功能,需要配置MP框架的分页拦截器:

@Configuration
public class MPConfig {

    @Bean
    public MybatisPlusInterceptor  pageinitInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //乐观锁
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        //分页配置
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL) );
        return mybatisPlusInterceptor;
    }
}

 单元测试:

    /**
     * 分页查询
     */
    @Test
    public void findPage(){
        IPage<User> page = new Page<>(1,3);
        userMapper.selectPage(page,null);
        System.out.println("总页数:" + page.getPages());
        System.out.println("总记录数:" + page.getTotal());
        System.out.println("当前页的页码:" + page.getCurrent());
        System.out.println("每页的数量:" + page.getSize());
        System.out.println("查到的当前页的内容:" + page.getRecords());

    }

三、常用注解

3.1 @TableName注解

通过@TableName注解可以映射实体类和表的对应关系。

  • 名称:@TableName

  • 类型:类注解

  • 位置:模型类上

  • 作用:设置当前类对应与数据库表关系

  • 范例:

@TableName("t_user") //当前实体类对应的表为t_user
public class User {
    private Long id;
}

注:如果类名和表名一致,MP可以自动进行映射,此时 @TableName 注解可以省略

3.2 @TableField注解

通过@TableField注解可以映射实体类的属性和表字段的对应关系。

  • 名称:@TableField

  • 类型:属性注解

  • 位置:模型类属性上

  • 作用:设置当前属性对应的数据库表中的字段关系

  • 相关属性:

    value:设置数据库表字段名称

    exist:设置属性在数据库表字段中是否存在,默认为true

  • 范例:

public class User {
    @TableField(value="pwd") //当前属性对应的字段为pwd
    private String password;
    
    @TableField(exist = false) //当前属性在表中没有对应的字段
    private String online;
}

如果属性名和字段名一致,MP可以自动进行映射,此时 @TableField 注解可以省略

如果属性名使用驼峰命名法命名,字段名使用对应的下划线分隔命名,MP可以自动进行映射,此时 @TableField 注解可以省略。

3.3 @TableId注解

 通过@TableId注解可以映射实体类的属性和表主键字段的对应关系,还可以设置主键的生成策略。

  • 名称:@TableId

  • 类型:属性注解

  • 位置:模型类中用于表示主键的属性上

  • 作用:映射类中属性和表中主键对应关系,设置主键的生成策略

  • 相关属性:

    value:设置数据库主键字段名称,如果属性名和字段名一致,可以省略此属性

    type:设置主键属性的生成策略,值参照IdType枚举值

  • 范例:

public class User {
    @TableId(type = IdType.AUTO) //当前id属性和表的主键字段id对应,并且设置主键生成策略为AUTO
    private Long id;
}

主键生成策略:

  • AUTO(0):使用数据库id自增策略控制id生成

  • NONE(1):不设置id生成策略

  • INPUT(2):用户手工输入id

  • ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)

  • ASSIGN_UUID(4):以UUID生成算法作为id生成策略

为了简化开发,可以在application.yml中配置全局的主键生成策略:

mybatis-plus:
  global-config:
    db-config:
      id-type: assign_id #全局设置主键生成策略

注:配置了全局的主键生成策略,在实体类中就无须再配置主键生成策略了。

四、条件构造器

4.1 条件构造器介绍

通过条件构造器(Wrapper),可以控制最终生成的 SQL 语句的条件部分,如下:

  • select_____________ from table where_________ order by

  • update table set________ where_________

  • delete from table where___________

通过条件构造器,就可以控制上面SQL语句中位置的SQL片段,在项目开发过程中经常使用到。

BaseMapper中的很多方法,都需要条件构造器作为参数,如下:

条件构造器的顶级父类为Wrapper:

条件构造器的继承关系如下:

使用比较多的条件构造器:

  • QueryWrapper

  • LambdaQueryWrapper

  • UpdateWrapper

  • LambdaUpdateWrapper

4.2 QueryWrapper

 通过 QueryWrapper 条件构造器,可以控制最终生成的查询、删除类的SQL语句。

SQL结构:

  • select ___ from table where ___ order by ___

  • delete from table where ___

  /**
     * 根据条件动态查询
     */
    @Test
    public void selectList(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","username","password","info") //设置查询字段
                .like("username","浩") //模糊查询
                .orderByDesc("id"); //排序条件
        List<User> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);

    }

分页查询

    /**
     * 分页查询
     */
    @Test
    public void findPage() {
        IPage<User> page = new Page<>(1, 3);
        userMapper.selectPage(page, null);
        System.out.println("总页数:" + page.getPages());
        System.out.println("总记录数:" + page.getTotal());
        System.out.println("当前页的页码:" + page.getCurrent());
        System.out.println("每页的数量:" + page.getSize());
        System.out.println("查到的当前页的内容:" + page.getRecords());

    }

 配置分页拦截器

/**
 * TODO 类描述
 *
 * @author Aaron.
 * @date 2023/10/24 11:18
 */
@Configuration
public class MPConfig {

    @Bean
    public MybatisPlusInterceptor  pageinitInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //乐观锁
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        //分页配置
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL) );
        return mybatisPlusInterceptor;
    }
}

4.3 LambdaQueryWrapper

LambdaQueryWrapper的作用和QueryWrapper相同,都是控制最终生成的查询、删除类的SQL语句。不同点在于语法层面。QueryWrapper是通过字段名来设置条件,LambdaQueryWrapper是通过Lambda语法来设置条件,可以做到在编译期就能够发现错误。

    @Test
    public void testLambdaQueryByQueryWrapper() {

        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>()
                .like(User::getUsername, "o")
                .gt(User::getBalance, 2000);
        List<User> users = userMapper.selectList(lambdaQueryWrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

项目开发中建议使用 LambdaQueryWrapper 来代替 QueryWrapper。

4.4 UpdateWrapper

 通过 UpdateWrapper 条件构造器,可以控制最终生成的更新类的SQL语句。

SQL结构:

  • update table set ___ where ___

BaseMapper中的如下方法可以传入UpdateWrapper对象:  

    //将Id为1、5、7的人员工资扣200
    @Test
    public void testUpdateWrapper() {
        UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
                .setSql("balance = balance - 200")
                .in("id", 1L, 5L, 7L);

        userMapper.update(null, wrapper);
    }

使用 BaseMapper 的 update 方法设置 set 条件时,既可以通过第一个参数(实体对象)设置,也可以通过第二个参数(UpdateWrapper)设置。

注:使用UpdateWrapper设置条件时,是通过字符串指定字段名,如果字段名有误,在编译阶段无法发现错误,在程序运行阶段会抛出异常。

4.5 LambdaUpdateWrapper

 LambdaUpdateWrapper的作用和UpdateWrapper相同,都是控制最终生成的更新类的SQL语句。不同点在于语法层面。UpdateWrapper是通过字段名来设置条件,LambdaUpdateWrapper是通过Lambda语法来设置条件,可以做到在编译期就能够发现错误。

    //使用LambdaWrapper进行查询
    @Test
    public void testSelectWithLambdaWrapper() {
        //select username,info from user where status = 1 order by balance Desc
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getUsername, User::getInfo)
                .eq(User::getStatus, 1)
                .orderByDesc(User::getBalance);
        userMapper.selectList(wrapper);

    }
4.6 润物无声

已经使用了MP,还能够使用 mybatis 进行 SQL 定义吗?

注意:MP只是对 mybatis 框架进行增强,不会改变 mybatis 框架的使用方法。也就是说原来怎么使用 mybatis 的,现在还可以按照原来的方式使用即可,如下:

为了进一步增强 mybatis 的功能,我们还可以在 Mapper 中声明方法时,方法的参数使用MP提供的Wrapper条件构造器对象,例如:

上面Mapper中声明的findByCondition方法,参数为 Wrapper类型,即条件构造器对象。并且通过@Param注解修饰,为其指定了别名为ew,这样就可以在SQL语句中通过 ${ew.customSqlSegment} 来获取到对应的SQL片段,这个SQL片段就是通过当前Wrapper对象解析成的。

注意,customSqlSegment为固定写法,底层会调用Wrapper对象的getCustomSqlSegment方法来获取对应的SQL片段。下面是Wrapper类的部分源码:

  

在单元测试方法中测试findByCondition方法  

五、扩展功能

5.1 逻辑删除

删除数据库中的数据,可以通过物理删除,也可以通过逻辑删除。

  • 物理删除 指的是直接将数据从数据库中删除,执行的是delete语句

  • 逻辑删除 指的是修改数据的某个字段,使其表示为已删除状态,执行的是update语句

如下是逻辑删除的效果,在表中增加deleted字段,标识数据是否被删除(例如:1表示删除,0表示未删除)。

注意:对于重要的、后期可能需要恢复的数据,可以考虑使用逻辑删除

由于在项目开发过程中经常会使用到逻辑删除,所以MP框架已经对逻辑删除提供了实现,我们直接使用即可。

具体使用步骤如下:

第二步:在application.yml中配置逻辑删除相关配置项

      logic-delete-field: deleted #指定用于标记数据被删除的字段名
      logic-delete-value: 1 #表示已删除
      logic-not-delete-value: 0 #表示未删除

 第三步:在实体类中加入逻辑删除属性(和表中的逻辑删除字段对应),并加入 @TableLogic 注解

加入逻辑删除后,再次调用BaseMapper的删除方法和查询方法,发出的SQL语句已经发生了变化。

删除数据时发出的SQL为update语句,将deleted字段的值改为1,表示当前数据被删除了。

查询数据时发出的SQL语句自动追加上查询条件 deleted=0,表示查询的数据是未删除的数据。

5.2 MP对于Service层的支持

MP 框架除了可以简化持久层代码开发,还为 Service 层提供了业务接口和实现类,可以简化 Service 层的开发。

MP提供的业务接口:

MP提供的业务层实现类:

5.3 代码生成器

MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。

安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装,如下所示:

代码生成器的操作步骤:

① 在IDEA的DataBase窗口中配置数据源

 ② 通过代码生成器提供的菜单项生成代码

选中表,然后点右键,在弹出的菜单中点击 MybatisX-Generator,此时会弹出如下窗口:

module path:指定代码生成到哪个模块中

base-package:指定代码生成的包结构

ignore table prefix:忽略表名前缀,例如表名为t_user,此时指定当前输入框为t_,则生成的实体类名就是User,否则生成的实体类名为TUser

ignore field prefix:忽略字段名前缀,例如字段名为f_name,此时指定当前输入框为f_,则生成的属性名就是name,否则生成的属性名为fName

通过代码生成器,就可以根据表结构,反向生成对应的实体类、Mapper、Service等,可以简化开发,提供开发效率。

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

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

相关文章

【Java系列】LinkedList

LinkedList 介绍使用 LinkedList 的情况使用 ArrayList 的情况 LinkedList 的基本使用LinkedList 类位于 java.util 包中&#xff0c;使用前需要引入它&#xff0c;语法格式如下&#xff1a;创建一个简单的链表实例&#xff1a;在列表开头添加元素在列表结尾添加元素&#xff1…

MATLAB中polyvalm函数用法

目录 语法 说明 示例 特征多项式的矩阵计算 polyvalm函数的功能是矩阵多项式计算。 语法 Y polyvalm(p,X) 说明 Y polyvalm(p,X) 以矩阵方式返回多项式 p 的计算值。此计算方式等同于使用多项式 p 替换矩阵 X。 示例 特征多项式的矩阵计算 求解 4 阶帕斯卡矩阵的特征…

二维码智慧门牌管理系统升级解决方案:采集项目的建立与运用

文章目录 前言一、采集项目的建立二、采集项目的运用三、采集项目的意义 前言 在二维码智慧门牌管理系统的升级过程中&#xff0c;一个至关重要的环节是采集项目的建立与运用。采集项目是新建采集任务的前提&#xff0c;同时也是整个系统升级的关键步骤。其意义近似于现实中的…

hdlbits系列verilog解答(8位宽移位寄存器)-24

文章目录 一、问题描述二、verilog源码三、仿真结果一、问题描述 这项练习是module_shift移位寄存器的延伸。模块端口不是只有单个引脚,我们现在有以向量作为端口的模块,您将在其上附加线向量而不是普通线网数据。与 Verilog 中的其他位置一样,端口的向量长度不必与连接到它…

CTF-Crypto学习记录-第四天 “ “ --- SHA1安全散列算法,实现原理。

文章目录 前言SHA-1加密算法介绍关于SHA-1和MD5 SHA-1 加密过程原文处理设置初始值和数据结构定义加密运算原理过程 在python中调用SHA-1 前言 MD5学习MD5加密算法 SHA-1加密算法介绍 SHA-1&#xff08;Secure Hash Algorithm1&#xff0c;安全散列算法1&#xff09;是一种密…

Python3打印九九乘法表

# 九九乘法表 # 定义行数 i 1while i<9:# 定义列数j 1while j<i: # print(" %d * %d %d\t" %(j,i,(j*i)),end) # \t:对齐;end:不换行&#xff1b;j1i1print() # 必须添加这句话&#xff01;&#xff01;&#xff01;print("九九乘法表打印完毕&#xf…

环形链表-力扣

一、题目描述 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 二、题解 解题思路&#xff1a; 快慢指针&#xff0c;即慢指针一次走一步&#xff0c;快指针一次走两步&#xff0c;两个指针从链表起始位置开始运行&#xff0c;…

Windows相关知识

目录 window用户管理 前言 SID 内置账户 与使用者关联的 与Windows组件关联的 用户相关命令 查看命令 用户管理 windows用户组 内置组账户 需要人为添加进入的组 动态包含成员的组&#xff08;符合某种条件自动进入的&#xff09; 管理组命令 NTFS权限 前言 常…

AFsim 三维地图部署

1.打开三维地图 点击上面菜单栏的地球&#xff0c;打开三维地图&#xff0c;或者按快捷键f4&#xff0c;弹出三维地球&#xff0c;如下图&#xff1a; 2.三维地图设置平台 在地球上任意位置&#xff0c;右击选择创建平台&#xff0c;弹出创建平台窗口&#xff0c;输入平台名称…

docker的安装部署nginx和mysql

小白自己整理&#xff0c;如有错误请指示&#xff01; 自我理解&#xff1a;docker就是把应用程序所用的依赖程序&#xff0c;函数库等相关文件打包成镜像文件&#xff0c;类似系统光盘&#xff0c;然后可以在任意电脑上安装使用&#xff08;方便运维人员部署程序&#xff09;…

设计模式面试知识点总结

文章目录 设计原则常用设计模式单例模式1. 饿汉式2. 懒汉式3. 双重检测 工厂方法模式&#xff08;简单工厂、工厂方法、抽象工厂&#xff09;简单工厂静态工厂工厂方法模式抽象工厂模式 策略模式责任链模式 设计原则 标记设计模式原则名称简单定义OCP开闭原则对扩展开放&#…

C生万物 | 从浅入深理解指针【第一部分】

C生万物 | 从浅入深理解指针【第一部分】 文章目录 C生万物 | 从浅入深理解指针【第一部分】一、内存和地址1.1 内存1.2 究竟该如何理解编址 二、指针变量和地址2.1 取地址操作符&#xff08;&&#xff09; 三、指针变量和解引用操作符&#xff08;*&#xff09;3.1 指针变…

①【数据库操作】 MySQL数据库的查询、创建、删除、使用。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 目录 数据库相关概念数据库的查询、创建、删除…

UI组件库基础

UI组件库 全局组件* 全局注册组件 & 并且使用了require.context 模块化编程 & webpack打包 const install(Vue)>{const contextrequire.context(.,true,/\.vue$/)context.keys().forEach(fileName>{const modulecontext(fileName)Vue.component(module.default.n…

【MySQL】并发事务产生的问题及事务隔离级别

先来复习一下事务的四大特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务是不可分割的最小操作单位&#xff0c;事务中的所有操作要么全部执行成功&#xff0c;要么全部失败回滚&#xff0c;不能只执行其中一部分操作。一致性&#xff08;Consisten…

vue2组件库-上传组件

vue2组件库 上传组件 核心思路&#xff1a;监控整个上传的流程 上传成功 上传失败 类型&#xff1a;拖拽 多个文件上传 上传必备属性 & 钩子属性 跟上传强关联的属性&#xff0c;上传必备的字段 name: 提交的那个formData字段名 action&#xff1a;ajax接口路径 limit&…

如何中断一个正在运行的线程?

线程 线程是系统级别的概念&#xff0c;在 Java 里面实现的线程&#xff0c;最终的执行和调度都是由操作系统来决定的&#xff0c;JVM 只是对操作系统层面的线程做了一层包装而已。所以我们在 Java 里面通过 start 方法启动一个线程的时候&#xff0c;只是告诉操作系统这个线程…

R语言入门看这一章就够了(上)

目录 一、R的基础 1.1、R的安装 1.2、牛刀小试 1.3、线性关系实例 1.4、工作空间 1.5、R包的使用 包的安装 结果的重用 二、R数据集 2.1、向量 2.2、矩阵 2.3、数组 2.4、数据框 2.5、列表 三、R的常用命令 四、list列表详解 五、数据源导入方法 5.1、键盘输…

黔院长 | 黄帝内经:人有四经十二从!

"人有四经十二从"这句话出自《黄帝内经素问》&#xff0c;“四经”指的是与四时相应的正常脉象&#xff0c;也是指四个主要经络&#xff1a;太阳经、少阳经、太阴经和少阴经。在中医理论当中这些经络被认为是人体气血运行的通道。 而“十二从”则表示人体的十二个经脉…

VulnHub Metasploitable-2

一、信息收集 nmap扫描 访问80端口 二、漏洞利用 1.漏洞一 1.vsftpd 2.3.4&#xff08;CVE-2011-2523&#xff09; 2.msf msf6 > search vsftpd msf6 > use 0 msf6 exploit(unix/ftp/vsftpd_234_backdoor) > set rhosts 192.168.103.189 msf6 exploit(unix/ftp/vs…