MyBatis使用教程详解<上>

一. 什么是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();
    }
}

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

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

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

相关文章

vue select选择下拉组织树,解决不出现横向滚动条

背景&#xff1a;由于项目需求需要使用下拉选择框的组织架构树 实现代码如下&#xff1a; <el-row><el-col :span"18"><el-form-item label"所属组织:" prop"groupName"><el-select v-model"dataForm.groupName"…

TDA4VM LInux SDK编译

文章目录 前言编译步骤前言 上篇TDA4VM EVM开发板调试笔记我们尝试把EVM开发板跑起来了,本篇主要记录,Linux SDK 的编译过程。 编译步骤 安装依赖: $ sudo apt-get update $ # Install packages required for builds $ sudo apt-get -f -y install \

净利下滑、市值缩水,“特卖电商第一股”唯品会夹缝求生

作者 | 艺馨 鸠白 排版 | Cathy 监制 | Yoda 出品 | 不二研究 刚刚过去的“黑色星期五”&#xff0c;跨境电商似乎“静悄悄”。 根据Adobe Analytics的数据&#xff0c;今年美国黑五线上销售额预计同比增长7.5%&#xff0c;达到98亿美元。 作为“特卖电商第一股”&#x…

竞赛选题 题目:基于深度学习卷积神经网络的花卉识别 - 深度学习 机器视觉

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基…

c语言-希尔排序

目录 一、插入排序 1、插入排序的概念 2、插入排序的逻辑实现 3、插入排序的实现 二、希尔排序 1、希尔排序概念 2、希尔排序逻辑实现 3、间隔值&#xff08;gap&#xff09;对排序的影响 4、希尔排序的实现 三、插入排序与希尔排序性能对比测试 结语&#xff1a; 前言…

Appscan安装详解

一、下载方式 方式一&#xff1a; 百度网盘链接:https://pan.baidu.com/s/1yV9nL78JEABxMTa7eHpPug 提取码:97 fm 方式二&#xff1a; 链接&#xff1a; https://pan.baidu.com/s/19TAHl8lYGmE0O753ULyzYA 密码&#xff1a;yvle 方式三&#xff1a; 链接&#xff1a;https://p…

ROC及曲线面积汇总学习

目录 ROC基础 生成模拟数据 率的计算 R语言计算测试 ROCR&#xff1a; pROC ROC绘制 单个ROC 两个ROC Logistic回归的ROC曲线 timeROC ROC基础 ROC曲线的横坐标是假阳性率&#xff0c;纵坐标是真阳性率&#xff0c;需要的结果是这个率表示疾病阳性的率&#xff08;…

采用NTC进行温度测量典型电路

本文介绍采用NTC进行温度测量典型电路。 采用NTC进行温度测量的电路有多种&#xff0c;典型的有恒流法和恒压法。在一般要求不高的应用场合&#xff0c;恒压法用的比较多&#xff0c;本文介绍一种采用恒压法进行NTC温度测量电路。 1.原理图 原理图如下图所示&#xff1a; 此…

springboot云HIS医院信息综合管理平台源码

满足基层医院机构各类业务需要的健康云HIS系统。该系统能帮助基层医院机构完成日常各类业务&#xff0c;提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等一系列常规功能&#xff0c;能与公卫、PACS等各类外部系统融合&#xff0c;实现多…

QT linux下应用程序打包

一、应用程序app 1、应用程序的pro文件 2、 程序工作函数 3、app的UI界面 二、动态库lib 1、Lib类头文件 2、.cpp文件 三、对应用程序和动态库进行构建 1、对动态库进行qmake,然后进行构建 2、对应用程序进行qmake&#xff0c;然后进行构建 3、查看构建目录 四、编写脚本 …

RPA机器人如何解决非银企直联网银账户的数据自动采集?

数字时代来临&#xff0c;随着全球信息化水平的不断提升&#xff0c;企业们纷纷向自动化办公、数字化转型靠拢。财务部门作为一个企业的重要部门&#xff0c;承担着管理和监控公司所有项目的重要职责&#xff0c;因而一直被视为企业数字化转型的重要突破口。 由于企业经营理念和…

局部内部类(内部类) - Java

局部内部类 说明&#xff1a;局部内部类是定义在外部类的局部位置&#xff0c;比如方法中&#xff0c;并且有类名。 LocalInnerClass.java 非常重要的几点&#xff01;&#xff01; 局部内部类本质还是一个类&#xff0c;该有的属性方法也都可以有。【举例a.见下文】可以直接…

传奇手游白日门【纵横天下】win服务端+双端+GM后台+详细架设教程

搭建资源下载地址&#xff1a;传奇手游白日门【纵横天下】win服务端双端GM后台详细架设教程-海盗空间

C++: String类接口学习

文章目录 STL简介一. 为什么要有string类二. STL 中的 string 类介绍1. string 类描述2. 关于 basic_string 三. string 类的常用接口1. string 类的常见构造2. string 类的容量操作size 和 lengthcapacitymax_sizereserveresize 3. string 类对象的访问及遍历操作operator[] 和…

centos服务器扩容

centos服务器扩容 我的情况是&#xff0c;原服务器是一个80g磁盘&#xff0c;管理员又追加了120G到这块磁盘上&#xff0c;需要把这120G重新追加使用。 请确认你遇到的情况是否和我初始截图一致&#xff0c;再往下看&#xff0c;免得浪费时间与精力 服务器中有120G尚未使用&…

典型的SAST支持检测标准

这里我们列举了Coverity、Cobot、代码卫士、Klocwork、QAC、C test几款典型的SAST工具&#xff0c;看看他们都是支持那些C、C标准&#xff08;主要是C、C标准&#xff0c;其它语言较少&#xff09;呢&#xff1f; 这可以作为厂商研发的方向标。 &#xff08;结束&#xff09;

更高效的图片预览方案

传统的图片预览方式是什么样子的呢&#xff1f; 首先是用户选择一张图片&#xff0c;通过ajax上传到服务器&#xff0c;然后服务器返回一个访问url 然后给img标签的src属性设置这个访问url。 那这就会有一个问题&#xff0c;用户为什么要先网络上传上去再预览呢&#xff0c;我…

docker容器的生命周期管理常用命令

容器的生命周期管理命令 docker create &#xff1a;创建一个新的容器但不启动它 docker create nginx docker run :创建一个新的容器并运行一个命令 常用选项&#xff1a; 常用选项1. --add-host&#xff1a;容器中hosts文件添加 host:ip 映射记录 2. -a, --attach&#…

银行各类计算公式汇总

一、存款准备金 存款准备金&#xff0c;分为法定存款准备金和超额存款准备金&#xff08;主要构成是存放央行及现金&#xff0c;不包括存放同业资金&#xff09;。下表为目前最新的各类银行业金融机构存款准备金水平。 法定存款准备金率是指中央银行规定的&#xff0c;存款性…

python如何抓取携程酒店的价格,让工作更简单点

有时候老板没事安排点事&#xff0c;为了偷懒&#xff0c;只能使出大招&#xff0c;毕竟自己不是那么老老实实干活的人&#xff0c;整理数据这类累和繁琐的活&#xff0c;我怎么能轻易动&#xff0c;好在gpt可以帮我来实现&#xff0c;有人可能会说&#xff0c;这么点内容你还不…