MyBatis使用教程详解<上>

news2024/11/27 9:58:16

一. 什么是MyBatis?

  • Mybatis是一个持久层框架,用于简化JDBC的操作
  • MyBatis原本是Apache的一个开源项目ibatis,后来更名为MyBatis

上面我们提到了一个概念----持久层

不知道小伙伴们有没有想到五大注解的关系,类似于下图

其中MyBatis就是Mapper层的框架,是基于JDBC的封装,可以帮助我们更方便的操作数据库.

二. MyBatis入门

MyBatis操作数据库的步骤:

  1. 创建SpringBoot项目,准备数据库,实体类...
  2. 引入MyBatis依赖
  3. 编写SQL语句(注解/XML)

2.1 创建MyBatis项目

创建工程不必多说,但是这次我们要导入MyBatis的依赖

可以在创建项目时直接添加,也可以创建项目后使用Spring Boot Helper插件引入依赖.

下面演示一下创建项目后的引入依赖.

点开pom.xml文件->右键单击,选择Generate,就可以看到下面这样一个小框

选择第一个->点击OK,就可以看到创建项目时的引入依赖界面

接下来需要在SQL中找到MyBatis,因为此处博主操作的是MySQL,所以也需要引入MySQL Driver依赖.

 然后就可以在pom.xml中看到引入的依赖了

这时候点击启动项目,会启动失败,提示信息显示没有指定数据源的URL,因此我们需要修改一下配置文件.

2.2 数据库准备&修改Spring配置

这里演示的是.yml配置文件,properties配置文件读者可自行操作.

在修改配置时,我们需要先创建一个数据库(博主创建的数据库名为config1114)

 然后在.yml文件中添加下列项(同学们不必记忆,只需要复制粘贴即可):

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/config1114?characterEncoding=utf8&useSSL=false
    username: root
    password: '******'
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true

为了演示方便, 这里博主创建了两个表:User表和Student表

 

 接下来我们需要创建实体类,建立Java对象和数据库中表的映射

//Student表对应的实体类
@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Date createTime;
    private Date updateTime;
}
//User表对应的实体类
@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;

}

2.3 写持久层代码

持久层操作数据库有两种方式:

1. 使用注解

2. 使用xml文件

我们简单演示一下第一种,先创建一个持久层的接口UserMapper

@Mapper
public interface UserMapper {
    @Select("select * from user")
    List<User> selectAll();
}

@Mapper是ibatis(MyBatis的前身)提供的注解,表示MyBatis创建了这个对象,并将该对象交给Spring管理.

这里的Mapper必须是接口类型,因为它的方法不是由程序猿实现的,而是交给MyBatis实现

 2.4 测试持久层方法

我们知道,在启动SpringBoot项目后,需要前端进行访问才可以调用后端写的方法,这样做未免太过麻烦.我们可以直接使用单元测试类解决.

右键Generate->点击test

按照上图进行操作,这是我们会发现test目录下多了一个对应的UserMapperTest类

下面是这个类的代码.

@SpringBootTest//测试类进行方法测试时需要启动Spring容器
@Slf4j//使用该注解方便进行日志打印
class UserMapperTest {

    @BeforeEach
    void setUp() {
        log.info("所有测试方法执行前执行");
    }

    @AfterEach
    void tearDown() {
        log.info("所有测试方法执行后执行");
    }

    @Autowired
    private UserMapper userMapper;//注入userMapper对象
    @Test
    void selectAll() {
        List<User> userList=userMapper.selectAll();
        log.info("查询全部User:{}",userList);
    }
}

下面我们点击selectAll方法旁边的倒三角进行测试(Test类的每个方法都可以独立运行).

可以看到打印日志上显示了全部的查询结果(博主自己提前加的数据).

 三. 使用注解实现方法

3.1 参数传递

刚才我们简单演示了使用注解查询user表中的全部数据,如果想要指定查询条件该怎么办呢?

这就需要借助#{}向SQL语句中传递参数.

@Select("select * from user where id=#{id}")//第一个id是user表中的字段名,第二个id是传递的参数名
User selectById(Integer id);

 现在在测试类中针对selectById()生成一个测试方法.

 @Test
 void selectById() {
        User user=userMapper.selectById(5);
        log.info("根据Id查询user:{}",user);
 }

可以看到查询结果(也是博主自己偷偷加的数据).

可能有些友友疑惑这个SQL语句是从哪里来的?这实际上是yml配置文件中设置的,用于开发环境中,帮助程序猿调试代码.

同时也可以看到 ,上面的SQL语句和我们使用JDBC时的语句是一样的,MyBatis框架是对JDBC进行了封装.

  •  如果SQL语句只需要传递一个参数,则这个参数可以任意命名(但不推荐).

这是再次使用运行测试方法,仍然能拿到刚才的数据

  •  可以使用@Param给传递的参数设置别名,这时SQL中的名字必须和注解内的名字对应.
@Select("select * from user where name=#{userName}")//name是user表中的字段名,userName是@Param中的参数
User selectByName(@Param("userName") String name);

针对这个方法生成一个测试方法.

@Test
void selectByName() {
    User user=userMapper.selectByName("李白");
    log.info("根据name查询user:{}",user);
}

下图为查询结果. 

3.2 @Insert

刚才我们展示的是@Select注解,现在来学习Insert操作.

@Insert("insert into user(name,age) values(#{name},#{age})")//name是传递的user对象的name属性,age是user对象的age属性

int insertUser(User user);
  • insert,delete,updata这些更新数据库的操作都默认返回int表示表中更新的行数.(实际上是MySQL返回的)

针对这个方法生成一个测试方法.

@Test
void insertUser() {
        User user=new User();
        user.setName("薛宝钗");
        user.setAge(21);
        log.info("插入user结果:{}",userMapper.insertUser(user));
 }

 我们可以根据打印日志查看插入结果.

  •  如果传递的参数是一个对象,并且使用了@Param注解,那么#{}中的属性名就必须是对象名.属性的形式

这时候我们再次运行测试方法,会抛出异常

 需要对原方法进行更改.

 再次运行测试方法,即可运行成功


 上面的步骤中,我们只是向数据库插入了一条记录,但是不知道这条记录的主键id,下面演示一下如何获取自增主键,需要借助另一个注解@Options

@Insert("insert into user(name,age) values(#{name},#{age})")

@Options(useGeneratedKeys = true,keyProperty = "id")//此处的id对应的是Java对象的属性名,表示将user表中的自增主键赋给哪个属性
int insertUserWithGetId(User user);

为该方法创建测试方法

@Test
void insertUserWithGetId() {
     User user=new User();
     user.setName("史湘云");
     user.setAge(19);
     userMapper.insertUserWithGetId(user);
     log.info("插入user:{}",user);
}

 可以从打印日志中看到插入该对象后的Id

3.3 @Delete

童靴们肯定都熟悉这个套路了,下面直接进行演示.

Mapper方法实现

@Delete("delete  from user where id=#{id}")
int deleteById(Integer id);

测试方法实现 

@Test
void deleteById() {
    int result=userMapper.deleteById(20);
    log.info("删除条目:"+result);
}

测试结果 

3.4 @Update

Mapper方法实现

@Update("update user set name=#{name},age=#{age} where id=#{id}")
int updateById(User user);

 测试方法实现

@Test
    void updateById() {
        User user=new User();
        user.setName("张爱莲");
        user.setAge(28);
        user.setId(21);
        int result=userMapper.updateById(user);
        log.info("更新条目: "+result);
    }

 测试结果

当然了,如果不放心可以直接查询数据库查看是否更新完成.

 

3.5 @Select

同学们肯定会疑惑,我们不是一开始演示的就是查询操作嘛.

刚才我们的查询操作中,Java对象的属性名和user表中的字段名是完全一致的,所以从user表中查询的字段值可以直接赋给对象的成员变量,但是如果二者不一致该怎么办呢? 

下面有三种解决办法:

  • 将查询的数据库字段重命名
  • 使用@Results注解
  • 修改yml配置文件(推荐)

这时我们借助的是Student表,对应的实体类属性见右图.

 

如果我们按照原来的方式进行查询 :

先创建一个StudentMapper接口.

@Mapper
public interface StudentMapper {
    @Select("select * from student")
    List<Student> selectAll();
}

在创建一个对应的测试类并在该类中注入StudentMapper接口.

@SpringBootTest
@Slf4j//使用Slf4j提供的对象进行日志打印
class StudentMapperTest {
    @Autowired
    private StudentMapper studentMapper;//注入StudentMapper对象

   @Test
    void selectAll() {
        List<Student> studentList=studentMapper.selectAll();
        log.info("查询全部Student:{}",studentList);
    }
}

 点击方法旁边的倒三角,可得到下图中类似的查询结果(我插入的)

 可以看到,所有查询出来的对象,其createTime和updateTime成员的值均为null,这是因为没有与数据库中查询的字段对应.


先来演示第一种----对查询的数据库字段重命名

@Select("select id,name,age,create_time as createTime,update_time as updateTime from student")
List<Student> selectAll();

再来运行测试方法,可以看到没有createTime和updateTime属性都被赋上了值.

 同学们肯定会觉得,select后面跟上数据库中的字段名未免过于麻烦,不如直接使用*简单,但是实际开发过程中,我们最好还是使用前者,因为*所查询的数据量往往是非常大的,这就导致了效率变低.

下面演示第二种方法----使用@Results注解

@Select("select * from student")
@Results({@Result(column = "create_time",property = "createTime"),
          @Result(column = "update_time",property = "updateTime")})
          //column对应的是数据库中的字段名,property对应的是Java对象中的属性名
List<Student> selectAll2();

生成该方法的测试方法

@Test
    void selectAll2() {
        List<Student> studentList=studentMapper.selectAll2();
        log.info("查询全部Student:{}",studentList);
    }

 可以看到,createTime和updateTime成员变量同样拿到了对应的值

 如果别的方法也需要使用这种映射关系的话,只需给@Results注解添加一个id值,然后借助@ResultMap注解实现复用

@Select("select * from student where id=#{id}")
@ResultMap("map")
Student selectById(Integer id);

生成测试方法

 @Test
    void selectById() {
        Student student=studentMapper.selectById(1);
        log.info("根据id查询Student:{}",student);
    }

 

 接下来展示第三种,也是最简单的一种----借助yml配置文件解决

我们只需要给.yml配置文件添加一项信息

 重新编写一次查询方法

@Select("select * from student")
List<Student> selectAll3();
@Test
    void selectAll3() {
        List<Student> studentList=studentMapper.selectAll3();
        log.info("查询全部Student:{}",studentList);
    }

可以看到,这次即便我们什么也不做,同样获取到了响应的值

这里不得不强调一下企业的命名规范:

  1.  表名,字段名使用小写字母或数字,单词之间以下划线分割
  2. Java成员变量名,使用小驼峰的形式,第一个单词首字母小写,另外的单词首字母大写
  3. Java类名,使用大驼峰的形式,所有单词的首字母均大写

四. 使用XML文件实现方法

 学习了使用注解的方式操作数据库,与JDBC相比是不是灰常简单!但是这种方式只能完成一些简单的SQL语句,如果想要实现复杂的功能,需要借助XML文件.

4.1 配置文件&XML文件准备

如果想借助XML实现接口的方法,我们需要先告诉配置文件XML文件的位置.

我们现在resources目录下建一个mapper目录,然后建一个与UserXMLMMapper对应的xml文件.

 

然后在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">
<!--与这个xml文件对应的接口-->
<mapper namespace="com.example.demo.mapper.UserXMLMapper">

</mapper>

细心的同学会发现我的idea界面上有两个魂斗罗图标,这实际上是MyBatisX插件.童靴们自行在Idea上安装即可.

MyBatisX是基于MyBatis的又一层封装.

 

 4.2 <insert>

刚才我们已经准备好了一个接口UserXMLMapper,现在尝试实现一个增加user的方法.

@Mapper
public interface UserXMLMapper {
    int insertUser(User user);
}

在接口中定义好方法后,需要在xml文件中添加一项标签<insert>.

如果我们的操作正确,会发现MyBatisX插件自动给我们添加了一对小鸟,点击它们中任意一个可以跳转到对方的位置.

 接下来在<insert>标签中编写SQL语句实现这个方法,与注解中的SQL语句一样,参数需要使用#{}传递.

    <insert id="insertUser">
        insert into user(name,age) values(#{name},#{age})
    </insert>

接着对这个方法进行单元测试.

@SpringBootTest
@Slf4j
class UserXMLMapperTest {

    @Autowired
    private UserXMLMapper userXMLMapper;//注入UserXMLMapper对象

    @Test
    void insertUser() {
        User user=new User();
        user.setName("欧阳修");
        user.setAge(78);
        int result=userXMLMapper.insertUser(user);
        log.info("增加条目:{}",result);
    }
}

我们可以在日志打印上发现结果.


在讲解@Insert的时候,我们提到可以使用@Options获取自增主键,那么在xml文件中如何获取呢?

需要给<insert>标签添加额外的参数.

    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        insert into user(name,age) values(#{name},#{age})
    </insert>

 细心的童靴会发现这两个参数与@Options中的参数是一样滴.

这次我们插入对象后打印该对象.

    @Test
    void insertUser() {
        User user=new User();
        user.setName("欧阳修");
        user.setAge(78);
        int result=userXMLMapper.insertUser(user);
        log.info("增加条目:{}",result);
        log.info("插入对象:{}",user);
    }

这样就拿到了自增id

 4.3 <delete>

话不多说,我们直接cue流程.

UserXMLMapper方法定义.

int deleteById(Integer id);

 <delete>标签实现.

    <delete id="deleteById">
        delete from user where id=#{id}
    </delete>

测试方法编写.

    @Test
    void deleteById() {
        int result=userXMLMapper.deleteById(23);
        log.info("删除条目:"+result);
    }

4.4 <update>

 UserXMLMapper方法定义.

int updateById(User user);

<update>标签实现 

    <update id="updateById">
        update user set name=#{name},age=#{age} where id=#{id}
    </update>

单元测试方法实现.

@Test
    void updateById() {
        User user=new User();
        user.setId(13);
        user.setName("西施");
        user.setAge(24);
        int result=userXMLMapper.updateById(user);
        log.info("更新条目:"+result);
    }


上述的update方法,我们是根据user对象中的id找到了这个记录并进行了修改.当然,我们可以额外传递一个id指定某条记录进行更新.

int updateById2(User user,Integer id);
    <update id="updateById2">
        update user set name=#{name},age=#{age} where id=#{id}
    </update>

 编辑并运行下面的测试方法.

    @Test
    void updateById2() {
        User user=new User();
        user.setName("林黛玉");
        user.setAge(19);
        int result=userXMLMapper.updateById2(user,13);
        log.info("更新条目:"+result);
    }

这时候我们发现代码抛出了异常..仔细观察,是不是和使用@Param时没有指定对象名的异常类似?

这时候name和age字段名需要显式指定 对象名.属性名

    <update id="updateById2">
        update user set name=#{user.name},age=#{user.age} where id=#{id}
    </update>

再次运行测试方法,通过日志可发现修改成功.

童靴们会不会这样想,是不是因为传入的参数id与User对象中的id属性名字发生冲突了,所以MyBatis才会找不到这个参数.

于是乎,博主将传入的id改了个名字iid

 但是运行测试方法时,仍然抛出了同样的异常.

如果传入的是多个参数,需要以 对象名.属性名 的方式组织,否则MyBatis会找不到传递的参数.

4.5 <select>

前面方法的实现,标签中只需添加一个属性即可.但是<select>标签至少需要两个属性.

selectAll()方法定义.

List<User> selectAll();

<select>标签实现

<!--    id的值为对应的方法名,resultType指定返回的数据类型-->
    <select id="selectAll" resultType="com.example.demo.entity.User">
        select * from user
    </select>

生成对应的测试方法.

    @Test
    void selectAll() {
        List<User> userList=userXMLMapper.selectAll();
        log.info("查询全部user:{}",userList);
    }


同样地,当数据库中的字段与对象的属性不一致时,有三种办法来实现.

  1. 对数据库中查询的字段重命名
  2. 使用<resultMap>标签
  3. 开启驼峰命名 

这次我们使用的依然是Student表.

第一种,第三种方法我们不再进行演示,与注解的使用是一样的.下文只演示第二种方法. 

先来创建一个StudentXMLMapper类,并定义selectAll方法.

@Mapper
public interface StudentXMLMapper {
    List<Student> selectAll();
}

再来配置xml文件,并生成对应的<select>标签.

<!--    id是这个resultMap标签的唯一标识,type是要映射的类-->
    <resultMap id="map" type="com.example.demo.entity.Student">
<!--        id指定主键及主键对应的属性,result标签中的column指定数据库中的字段,property指定对象的属性名-->
        <id column="id" property="id"></id>
        <result column="create_time" property="createTime"></result>
        <result column="update_time" property="updateTime"></result>
    </resultMap>
<!--    不能继续使用resultType属性了,修改为resultMap属性并指定对应id-->
    <select id="selectAll" resultMap="map">
        select * from student
    </select>

生成对应的测试方法并运行.

@SpringBootTest
@Slf4j
class StudentXMLMapperTest {

    @Autowired
    private StudentXMLMapper mapper;
    @Test
    void selectAll() {
        List<Student> list=mapper.selectAll();
        log.info("查询全部Student:{}",list);
    }
}

 可以在打印结果中看到,createTime和updateTime正确地显示出来了.

五. 多表联合查询

上面的演示中,我们查询的都是单表,现在来演示一下如何查询多个表.

5.1 数据库准备

这次要用到的是user表和article表.

 

实际上,查询多个表和查询单个表是一样的操作,关键在于对应的实体类怎么定义.

我们需要在entity包下定义两个实体类对象.

@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;

}
@Data
public class Article {
    private Integer id;
    private String title;
    private String content;
    private Integer authorId;
    private Date createTime;
    private Date updateTime;
}

现在,我们的要求是-----查询全部Article并且显示与其对应的作者名.

于是我们需要定义一个视图类来建立与查询数据的映射.

@Data
public class ArticleView extends Article{
    private String name;
}

下面创建一个ArticleVIewMapper类,然后用注解的方式编写SQL语句

@Mapper
public interface ArticleViewMapper {
    @Select("select article.*,name from article,user where article.author_id=user.id")
    List<ArticleView> selectAll();
}

创建测试类并生成对应的测试方法.

@SpringBootTest
@Slf4j
class ArticleViewMapperTest {

    @Autowired
    private ArticleViewMapper mapper;
    @Test
    void selectAll() {
        List<ArticleView> viewList=mapper.selectAll();
        log.info("查询结果:{}",viewList);
    }
}

现在来测试一下.

可以看到,打印结果并不是很理想,我们想要的是Article部分的全部信息,因为ArticleView类是Article类的子类,所以@Data帮助我们写的toString()方法并没有打印Article的信息. 

我们可以借助Idea重新生成一个toString()方法,这时代码在运行的时候会以我们写的方法为主.

@Data
public class ArticleView extends Article{
    private String name;

    @Override
    public String toString() {
        return "ArticleView{" +
                "name='" + name + '\'' +
                "} " + super.toString();
    }
}

再次进行测试,就可以显示出全部的信息了.

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

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

相关文章

华为服务器驱动及固件下载步骤

1. 打开官网技术支持页面 https://support.xfusion.com/support/#/zh/home 2.页面往下来&#xff0c; 选择【FusionServer iDriver】 3. 选择最新版本 4. 选择对应的型号及版本

『 MySQL数据库 』插入查询结果

文章目录 &#x1f39f;️ 前言&#x1f39f;️ 创建一张结构相同的表&#x1f39f;️ 表内插入查询结果&#x1f3ab; 对表内数据进行去重&#x1f3ab; 配合ORDER BY排序后以及LIMIT分页对数据进行插入 &#x1f39f;️ 前言 在MySQL数据库中不仅可以直接根据字段类型等对数据…

企业宣传画册用什么工具制作,不用下载软件,在线就能搞定!

企业宣传册是一种常见的营销工具&#xff0c;可以有效地展示企业或产品的特点和优势&#xff0c;吸引客户的注意力。企业宣传画册有这么多优势&#xff0c;如何制作呢&#xff1f;用什么工具制作呢&#xff1f;这可难倒了不少人。 有人可能会说&#xff0c;找专业的设计公司交…

微信小程序如何获取用户手机号码?

需求 在开发一款微信小程序时&#xff0c;通常需要用户进行微信登录&#xff0c;并获取用户的手机号码作为用户的唯一标识&#xff08;userId&#xff09;。虽然可以通过wx.login来获取用户的openid&#xff0c;但有时候需要获取用户的手机号码以提供更完善的个性化服务&#…

常见的6种工业主板盘点

无论您涉及哪种类型的工业环境&#xff0c;主板都是所有电子元件的关键部件之一。可靠且高效的主板是任何功能系统的核心和灵魂。 不同的主板旨在满足不同的需求&#xff0c;如果您希望系统发挥最佳性能&#xff0c;则必须了解这些需求。本文提供了有关当今流行的6种工业主板的…

TDI网络过滤驱动应用(一)

文章目录 TDI网络过滤驱动应用1. 技术概览2. 数据包的抓取3. 应用实例3.1 TrafficShaper(限流)3.2 DnsRedirector(DNS重定向)3.3 TcpRedirector(TCP重定向) 4. 总结与参考 TDI网络过滤驱动应用 在前面的文章中&#xff0c;我们分析了TDI网络过滤驱动的基本开发框架以及TDI网络…

AI视频智能分析识别技术的发展与EasyCVR智慧安防视频监控方案

随着科技的不断进步&#xff0c;基于AI神经网络的视频智能分析技术已经成为了当今社会的一个重要组成部分。这项技术通过利用计算机视觉和深度学习等技术&#xff0c;实现对视频数据的智能分析和处理&#xff0c;从而为各个领域提供了广泛的应用。今天我们就来介绍下视频智能分…

开发知识点-Maven包管理工具

Maven包管理工具 SpringBootSpringSecuritydubbo图书电商后台实战-环境设置&#xff08;JDK8, STS, Maven, Spring IO, Springboot&#xff09;点餐小程序Java版本的选择和maven仓库的配置视频管理系统&&使用maven-tomcat7插件运行web工程SpringTool suite——maven项目…

C#-串口通信入门及进阶扩展

目录 一、串口相关参数介绍 1、端口&#xff08;COM口&#xff09; 2、波特率&#xff08;Baud rate&#xff09; 3、起始位 4、停止位&#xff08;StopBits&#xff09; 5、数据位 6、校验位 7、缓存区 二、串口通信助手 三、虚拟串口工具 四、进阶扩展 1、位运算…

Sui根据资源使用情况,使gas费计量更公平

Sui的大规模并行处理需要新的方式思考gas费&#xff0c;即网络上处理交易的成本。在我们的工作中&#xff0c;我们研究计算成本和指令处理&#xff0c;以设计一种最佳的gas费机制。准确评估gas费不仅可以提供公平的网络分摊成本和健康的运营业务模型&#xff0c;还鼓励开发人员…

算法通关第十七关黄金挑战——透析跳跃问题

大家好&#xff0c;我是怒码少年小码。 本篇是贪心思想的跳跃问题专题&#xff0c;跳跃问题出现的频率很高。 跳跃游戏 LeetCode 55&#xff1a;给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标。数组中的每个元素代表你在该位置可以跳跃的最大长度。 …

java第20章节

一.线程简介 二.创建线程 1.继承Thread类 Thread类中常用的两个构造方法如下&#xff1a; public Thread():创建一个新的线程对象。 public Thread(String threadName):创建一个名称为threadName的线程对象。 继承Thread类创建一个新的线程的语法如下&#xff1a; public c…

网关路由器双栈配置中的IPv6相关选项解析

1、引言 讲知识往往是枯燥无味的&#xff0c;我们先从问题入手。家庭网关&#xff08;光猫&#xff09;、路由器是我们每个人或多或少都有所接触的2种设备。现在一般都是光纤入户&#xff0c;通常每个家庭配备一个光猫和一台家用路由器。 目前有许多网络服务已经提供了IPv6支…

视频监控管理平台/智能监测/检测系统EasyCVR设备列表显示不全是什么原因?该如何解决?

GB28181视频监控国标平台/视频云存储/安防监控EasyCVR视频汇聚平台&#xff0c;基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。智慧安防视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视…

java中反射知识点概念

这里写自定义目录标题 1.什么是反射--动态注入&#xff1f;2.反射的诞生背景3.反射的意义4.反射后可以做些什么5.反射相关的主要API6.反射的优缺点7.反射和不反射基础使用8.工厂模式使用反射8.1首先我们来看看不使用反射的情况&#xff1a;8.2使用反射的情况&#xff1a; 9.Jav…

【springboot】idea项目启动端口被占用

问题 idea本地启动springboot项目端口老是被占用 解决 关闭被占用的端口进程 步骤: 1. winR打开程序框 2. 查出被占用端口的进程id netstat -ano | finderstr 端口号 例如 netstat -ano | finderstr 81013.杀死进程 taskkill /pid 进程id -t -f 例如 taskkill /pid 2…

1688 API接口的介绍丨商品详情页接口丨搜索商品列表接口

1688&#xff0c;作为中国领先的B2B电子商务平台&#xff0c;为全球的买家和卖家提供了一站式的采购和销售服务。而它的API接口&#xff0c;更是开放了1688平台的核心功能&#xff0c;让开发者能够根据自己的需求来定制和扩展商业应用。 1688 API接口的介绍 1688 API接口提供…

使用影刀指令+python实现简单的长文本乱序加密

本文意在利用影刀指令python代码&#xff0c;实现一种较为简单的长文本加密和解密&#xff0c;流程结构分为两步&#xff1a; 加密原理–是把字符转为列表&#xff0c;利用列表random模块中的shuffle函数做随机乱序。解密原理–是利用了列表的索引追踪&#xff0c;先前创建字典…

Vue3-目录调整

默认生成的目录结构不满足我们的开发需求&#xff0c;所以这里需要做一些自定义改动。 主要是以下工作&#xff1a; 1.删除一些初始化的默认文件 2.修改剩余代码内容 3.新增调整我们需要的目录结构 在src文件夹下创建两个新文件夹&#xff0c;一个叫api&#xff08;请求模…

re:Invent 2023:PingCAP 荣获亚马逊云科技 2023 年度合作伙伴奖项

2023 年 11 月 27 日 – 12 月 1 日&#xff0c; 2023 亚马逊云科技 re:Invent 在拉斯维加斯举办&#xff0c;亚马逊云科技合作伙伴奖项在合作伙伴颁奖晚会上颁布&#xff0c; PingCAP 荣获亚马逊云科技大中华区 “2023 年度 ISV 合作伙伴” 和 “2023 年度亚马逊云科技 Market…