【MyBatis】MyBatis操作数据库

news2024/12/27 10:30:00

MyBatis操作数据库

文章目录

  • MyBatis操作数据库
    • :one:什么是MyBatis
    • :two:创建SSM项目
      • 引入依赖
      • 配置文件设置
      • MyBatis底层逻辑
    • :three:实现CRUD功能
      • 查询
        • 全列查询
        • 带参数的查询
      • 新增
        • 获取自增主键
      • 删除
      • 更新
    • :four:参数占位符:#{}和${}
      • 不支持String参数问题
      • ${}使用场景:
      • sql注入问题
    • :five:ResultMap的用处
    • :six:多表查询
    • :seven:动态sql

1️⃣什么是MyBatis

MyBatis是一个持久层框架(用于实现数据持久化的框架),它的底层也是基于JDBC的,不过用MyBatis比直接用JDBC操作数据库要方便很多。

MyBatis是一个ORM(Object Relational Mapping)框架,即对象关系映射框架,映射关系:

数据表–>>映射成一个类

一条记录–>>映射成一个对象

表中的字段–>>映射成类中的属性

由于MyBatis实现了这层映射关系,我们可以像操作对象一样来操作数据表。

2️⃣创建SSM项目

SSM项目:SpringBoot+SpringMVC+MyBatis

引入依赖

image-20221207224752067

  • MyBatis Framework 和 MySQL Driver这两个依赖是为了操作数据库
  • SpringWeb即SpringMVC
  • Lombok是一个工具,提供了很多好用的注解

当添加了MyBatis Framework 和 MySQL Driver 以及 SpringWeb这三个依赖后就构成了一个SSM项目

配置文件设置

配置文件需要设置两项内容:

  • 数据库的连接信息
  • MyBatis的xml文件的存放位置(xml文件中是sql语句)
# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/myblog?characterEncoding=utf8&useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.cj.jdbc.Driver

# 配置myBatis的xml文件路径
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

MyBatis底层逻辑

当引入依赖,且配置好配置文件后,就可以使用MyBatis来做增删改查等功能了。在使用MyBatis之前,先了解MyBatis在整个后端中的定位:

image-20221208124707913

数据持久层MyBatis是由Service层去调用的,然后我们知道MyBatis是基于JDBC的,MyBatis是对JDBC做了一个封装,不过封装后供Service层调用的接口不是纯的java类,而是接口和.xml文件的组合。

接口可以代表一张表,接口中是方法的声明,接口对应着有一个xml文件,xml文件中是方法的具体实现,方法的具体实现就是sql语句,比如查询,新增等语句。所以MyBatis相当于是把sql语句从类中分离出来了(JDBC时代sql语句是在类中的),分离到了.xml文件中。

接口搭配上接口的具体实现就可以去调用JDBC,进而操作数据库。所以MyBatis对于JDBC封装后,给开发者提供的不再是一些类,而是接口+xml文件。开发者使用接口+xml的组合就能实现相应的数据库操作。

3️⃣实现CRUD功能

查询

全列查询

使用MyBatis实现全列查询:

1️⃣先往数据库user表中添加两条记录,用于MyBatis查询:

image-20221208154046576

2️⃣添加实体类:因为MyBatis是一个ORM框架,实现了数据库中的数据与对象之间的一个映射,所以当查询出了数据之后,可以自动创建出实体类对象,并给对象的属性赋值。但前提是先有一个实体类:

package com.example.demo.model;

import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private int age;
}
  • 需要注意的是这里的类中的属性需要和数据表的字段名对应上,如果某一属性名和数据表中的字段名不对应,是没法赋值的。
  • user表中的一条记录将来就会映射出一个User实例

3️⃣定义UserMapper接口:这个接口中有对于User表的增删改查的方法的定义

package com.example.demo.mapper;

import com.example.demo.model.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserMapper {
    //getAll()来实现全列查询
    public List<User> getAll();
}
  • 该接口需要添加@Mapper注解,该注解代表这个接口是用于MaBatis的,

4️⃣实现接口:即创建对应的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">
<mapper namespace="com.example.demo.mapper.UserMapper" >
    <select id="getAll" resultType="com.example.demo.model.User">
        select * from user;
    </select>
</mapper>
  • namespace=“com.example.demo.mapper.UserMapper”:对应到某个上面的接口:包名+接口名
  • select 标签代表查询,id="getAll"对应到接口中的getAll()方法,所以这个select标签即为接口中getAll()方法的具体实现。
  • resultType=“com.example.demo.model.User”>:select操作的返回结果赋值给哪个类

至此MyBatis的代码就写完了,也实现了这个全列查询功能,那接下来就来验证一下该功能:

使用单元测试的方式来验证:

UserMapperTest测试类:

package com.example.demo.mapper;

import com.example.demo.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class UserMapperTest {

    @Autowired
    UserMapper userMapper;

    @Test
    void getAll() {
        List<User> list = userMapper.getAll();
        for (User user:list) {
            System.out.println(user.toString());
        }
    }
}
  • 类上加@SpringBootTest注解,代表当前测试的环境是SpringBoot
  • 注入UserMapper

⭕️执行单元测试,最终就可以从数据库中拿到数据,并赋值给User实例

带参数的查询

UserMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface UserMapper {
    //getAll()来实现全列查询
    public List<User> getAll();

    //根据user表的id字段来查询
    public User getById(@Param("id") int id);
}
  • @Param注解中的"id"用来和对应的xml文件中的#{id}对应
  • 这个@Param注解加上保证不出错,不加在linux平台可能会出错

UserMapper.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">
<mapper namespace="com.example.demo.mapper.UserMapper" >
    <select id="getAll" resultType="com.example.demo.model.User">
        select * from user;
    </select>

    <select id="getById" resultType="com.example.demo.model.User">
        select * from user where id=#{id};
    </select>

</mapper>
  • 使用#{id},来对应UserMapper接口中getById()方法中的@Param(“id”)

新增

给article表添加记录

1️⃣article表:

image-20221208174224877

2️⃣实体类:article类:

package com.example.demo.model;

import lombok.Data;

@Data
public class Article {
    private int id;
    private String title;
    private String content;
}

3️⃣ArticleMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ArticleMapper {

    //添加一条记录到article表
    public int add(Article article);
}

4️⃣ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >
    <insert id="add">
        insert into article values(#{id},#{title},#{content})
    </insert>

</mapper>
  • insert标签不需要添加ResultType,因为insert操作返回的是影响的行数
  • 对于参数是对象的情况:#{id},#{title},#{content} ,#{}的括号中直接写属性就可以了。
  • 如果在接口的方法中加了@Param(“article”)这个注解,那在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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >
    <insert id="add">
        insert into article values(#{article.id},#{article.title},#					{article.content})
    </insert>

</mapper>

5️⃣单元测试:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleMapperTest {

    @Autowired
    private ArticleMapper articleMapper;

    @Test
    void add() {
        Article article = new Article();
//        article.setId(10);
        article.setTitle("第一条记录");
        article.setContent("今天嘻嘻哈哈");
        int result = articleMapper.add(article);
        System.out.println(result);
    }
}
  • 因为article表的id字段是自增主键,所以是不应该给article对象的id属性赋值的,不赋值的时候id属性默认是0,在插入的时候id主键就会实现自增:从1开始,然后2,3,4,5,6…

获取自增主键

当添加一条记录的时候,我们是可以通过代码获取到该记录的自增主键的值的:

ArticleMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleMapper {

    //添加一条记录,并返回article表的自增id
    public int addGetId(@Param("article") Article article);
}

ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >
 
    <insert id="addGetId" useGeneratedKeys="true" keyProperty="id">
        insert into article values(#{article.id},#{article.title},#{article.content})
    </insert>
</mapper>

在insert标签中,要添加两个属性:useGeneratedKeys=“true” keyProperty=“id”(id为自增主键的名称)。

单元测试:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleMapperTest {

    @Autowired
    private ArticleMapper articleMapper;

    @Test
    void addGetId() {
        Article article = new Article();
        article.setTitle("一条新的记录");
        article.setContent("实现新增记录并返回该记录的自增id");
        int result = articleMapper.addGetId(article);
        System.out.println(result);
        System.out.println(article.getId());
    }
}
  • 当成功插入一条记录后,就会将该记录的id返回给article对象的id属性,通过article.getId()就可以获取到新增记录的自增主键id的值
  • 通过获取自增主键id的值,可以了解到article对象不仅可以作为待插入数据库的原始数据,还可以用来接收从数据库返回的数据。

删除

根据文章的id删除一篇文章

ArticleMapple接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleMapper {
    //添加一条记录到article表
    public int add( @Param("article") Article article);

    //根据id删除一条记录
    public int deleteById(@Param("id") int id);
}

ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >
    <insert id="add">
        insert into article values(#{article.id},#{article.title},#{article.content})
    </insert>
    <delete id="deleteById">
        delete from article where id=#{id}
    </delete>
</mapper>

更新

根据文章id修改文章标题:

ArticleMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleMapper {
    //添加一条记录到article表
    public int add( @Param("article") Article article);

    //根据id删除一条记录
    public int deleteById(@Param("id") int id);

    //根据文章id修改文章标题
    public int updateTitle(@Param("id") Integer id,@Param("title") String title);
}

ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >
    <insert id="add">
        insert into article values(#{article.id},#{article.title},#{article.content})
    </insert>
    <delete id="deleteById">
        delete from article where id=#{id}
    </delete>
    <update id="updateTitle">
        update article set title=#{title} where id=#{id}
    </update>
</mapper>

4️⃣参数占位符:#{}和${}

  • #{}:预编译处理:会使用JDBC的那种方式,使用?作为占位符,然后调用setInt()方法或者setString()方法来替换掉占位符
  • ${}:直接替换

不支持String参数问题

举个栗子:

1️⃣传递int类型的参数:

ArticleMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleMapper {

    //查询出id为3的这条记录
    public Article selectById(@Param("id") int id);
}

ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >

    <select id="selectById" resultType="com.example.demo.model.Article">
        select * from article where id=${id}
    </select>
</mapper>
  • 当传递的参数是int类型的时候,使用#{}和使用${}是都可以运行的

2️⃣传递String类型的参数:

ArticleMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleMapper {

    //查询出title为"你好,世界"的这条记录
    public Article selectByTitle(@Param("title") String title);
}

ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >
    
    <select id="selectByTitle" resultType="com.example.demo.model.Article">
        select * from article where title=#{title}
    </select>
</mapper>
  • 当传递的参数是String类型时,就必须使用#{},不能使用${}。

因为#{}使用的是?作为占位符,然后再调用preparedStatement.setString()方法替换掉占位符,最终执行的sql语句是:

select * from article where title=‘你好,世界’;(有单引号)

而使用${}这种方式,是直接替换的方式,直接替换的方式,最终执行的sql语句是:

select * from article where title=你好,世界;(无引号),无引号的方式会把:你好,世界作为字段名称去数据库查询,会报错:

报错提示:Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘你好,世界’ in ‘where clause’

那要想使用 ,就必须手动加单引号: s e l e c t ∗ f r o m a r t i c l e w h e r e t i t l e = ′ {},就必须手动加单引号:select * from article where title=' ,就必须手动加单引号:selectfromarticlewheretitle={title}'。


${}使用场景:

通过上面的对比,我们发现,使用#{}比使用 的方式要好,所以 99.9 {}的方式要好,所以99.9%的场景使用#{}就OK了,但是有一种场景,必须使用 的方式要好,所以99.9{},就是传递的参数是一个系统参数,比如用于升序的 asc以及用于降序的desc

当传递的是个String类型的字段时是应该加引号的,但是如果传asc 以及desc,就会出错

ArticleMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface ArticleMapper {

    //按照id升序或者降序查询、
    public List<Article> selectOrderById(@Param("order") String order);
}

ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >

    <select id="selectOrderById" resultType="com.example.demo.model.Article">
        select * from article order by id ${order}
    </select>
</mapper>

单元测试:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleMapperTest {

    @Autowired
    private ArticleMapper articleMapper;

    @Test
    void selectOrderById() {
        List<Article> list = articleMapper.selectOrderById("desc");
        for (Article article:list) {
            System.out.println(article);
        }
    }
}

当使用#{}的时候,实际执行的sql语句为: select * from article order by id ‘desc’(有引号)

当使用${}的时候,实际执行的sql语句为:select * from article order by id desc(无引号)

当传递的参数是系统参数,asc,desc的时候,使用#{}就会出错,这种情况应该使用${}

这是${}的使用场景。

sql注入问题

#{}和 除了上面的使用场景上的差别外,还存在另一比较大的区别,就是 {}除了上面的使用场景上的差别外,还存在另一比较大的区别,就是 除了上面的使用场景上的差别外,还存在另一比较大的区别,就是{}可能引发sql注入问题,而#{}则不会引发sql注入问题。

UserMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface UserMapper {

    //根据name查询出用户
    public User getUserByName(@Param("name") String name);
}

UserMapper.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">
<mapper namespace="com.example.demo.mapper.UserMapper" >
    
    <select id="getUserByName" resultType="com.example.demo.model.User">
        select * from user where name = '${name}'
    </select>

</mapper>

单元测试:

package com.example.demo.mapper;

import com.example.demo.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class UserMapperTest {

    @Autowired
    UserMapper userMapper;

    @Test
    void getUserByName() {
        User user = userMapper.getUserByName("' or 1='1");
        System.out.println(user);
    }
}
  • 当使用${}时:

单元测试中传递的参数是:’ or 1='1,xml文件中使用${}来接收参数,最终执行的sql语句为:

select * from user where name = ‘’ or 1=‘1’ (1='1’是恒成立的,因为Mysql会隐式类型转换),所以即使前端传递的参数在数据库中并没有,在这里也能查询出结果。这就是sql注入问题,要解决问题,可以在controller层验证参数的合法性,比如:如果传递的参数中有引号,就直接不往后执行,直接返回给前端一个结果:参数不合法。

  • 当使用#{}时:

当使用#{}就不会出现上面的sql注入问题,因为使用#{},就不是${}的字符串直接替换的方式了,而是调用的JDBC中的:PreparedStatement的setString()来给参数赋值,如果参数中有单引号,会给单引号加一个转义字符:\ ,让单引号仅仅表示一个普通的字符,就能避免sql注入问题。

⭕️通过博客系统的登录功能来演示一下:

image-20221209163557510

前端输入的用户名会传给这个方法:

image-20221209163542753

打印一下待执行的sql语句:

image-20221209163742850

  • 可以发现通过setString的这种方式会给单引号加上转义字符,以此来避免了sql注入问题。

而#{}底层使用的就是使用JDBC的setString()这种方式,所以不会出现sql注入问题。

总结:

  • #{}的方式更安全,大部分情况下应该使用#{},除了asc,desc那中情况
  • 如果${},就要在controller层验证一下参数的合法性

5️⃣ResultMap的用处

一般来说,实体类的属性名要和数据表的字段名一样,如果不一样的话,那在做查询操作的时候,对象的属性就可能不会被赋值。但是有的时候,我们不希望有这种限制,因为可能数据表的字段名不是很合理,但是类的属性名又想合理起名,那这时候就需要给实体类的属性和数据表的字段设置一个映射关系了。这时候ResultMap就登场了,ResultMap就是用来实现这种对应关系的。

1️⃣Article实体类:

package com.example.demo.model;

import lombok.Data;

@Data
public class Article {
    private int id;
    private String titles;
    private String content;
}

2️⃣Article数据表:

image-20221209182632810

3️⃣ArticleMapper接口:

package com.example.demo.mapper;

import com.example.demo.model.Article;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface ArticleMapper {

    //查询出id为3的这条记录
    public Article selectById(@Param("id") Integer id);
}

4️⃣ArticleMapper.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">
<mapper namespace="com.example.demo.mapper.ArticleMapper" >
    //类属性和表字段的映射关系 
    //id可以任意取,type为要映射的类
    <resultMap id="baseMap" type="com.example.demo.model.Article">
        //id标签用于主键映射,不过使用result映射主键也是可行的
        <id column="id" property="id"></id>
        //result标签用于普通字段映射
        <result column="title" property="titles"></result>
        <result column="content" property="content"></result>
    </resultMap>

	//resultMap为上面的resultMap标签中的id
    <select id="selectById" resultMap="baseMap">
        select * from article where id=#{id}
    </select>
</mapper>
  • 当按上面配置好xml文件后,就可以实现映射关系
  • 如果类中有的属性名和数据报的字段名一样,当使用了ResultMap映射后,最好也在resultMap标签中映射一下

6️⃣多表查询

多表查询和单表查询类似,都是写接口,然后实现接口。

但是有一点区别,比如说,一个文章表,一个作者表,对这两张表进行联合查询,文章表作为主表,如果想要查询出文章表的所有列,以及每篇文章对应的作者姓名,就可以对这两张表进行笛卡尔积,然后筛选条件为文章表中的作者id=作者表中的id。由于我们多查询了一列:作者姓名,所以可以在文章表对应的实体类中加一个属性用来表示文章的作者姓名。最终将查询结果依次赋值给文章表实体类的每个属性。

唯一一点区别就是需要多查询其他表中的哪些列,就在当前主表中加上哪些与之对应的属性。

7️⃣动态sql

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

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

相关文章

javascript的ajax

学什么Ajax基础JSON跨域XHR对象Ajax进阶Ajax应用Ajax扩展Ajax基础初识 AjaxAjax的基本用法GET请求POST请求JSON初识JSONJSON的3种形式JSON的常用方法跨域初识跨域CORS跨域资源共享JSONPXHR 对象XHR的属性XHR的方法XHR的事件Ajax进阶FormData封装Ajax使用Promise改造封装好的Aja…

Linux 进程:进程退出返回值的获取

目录一、对输出参数status的理解二、获取进程退出返回值1.位运算(1)异常退出码(2)进程返回值2.宏函数我们常使用函数 wait 和 waitpid 来执行进程等待的功能&#xff1a;处理退出的子进程并释放资源&#xff0c;防止子进程变成僵尸进程。而这两个函数都有一个输出参数status&am…

【LeetCode】第 99 场双周赛

1. 最小和分割 给你一个二维整数数组 ranges &#xff0c;其中 ranges[i] [starti, endi] 表示 starti 到 endi 之间&#xff08;包括二者&#xff09;的所有整数都包含在第 i 个区间中。 你需要将 ranges 分成 两个 组&#xff08;可以为空&#xff09;&#xff0c;满足&am…

单板TVS接地不当造成辐射骚扰超标问题分析-EMC

【摘要】 某产品EMC辐射骚扰测试超标&#xff0c;通过近远场扫描配合定位分析&#xff0c;逐步找出骚扰源、传播路径&#xff0c;最终通过修改 PCB 走线切断传播路径解决此问题。 1 故障现象 某产品在进行 EMC 研发摸底测试时发现&#xff0c;整机辐射骚扰垂直方向测试超标&a…

Cesium实现的光柱效果

Cesium实现的光柱效果 效果展示: 可以通过拼接两个entity来实现这个效果: 全部代码; index.html <!DOCTYPE html> <html><head><meta charset

HBase写入流程详解

HBase采用LSM树架构&#xff0c;天生适用于写多读少的应用场景。在真实生产线环境中&#xff0c;也正是因为HBase集群出色的写入能力&#xff0c;才能支持当下很多数据激增的业务。需要说明的是&#xff0c;HBase服务端并没有提供update、delete接口&#xff0c;HBase中对数据的…

C++实战md5、base64算法实现(附源码)

C++常用功能源码系列 文章目录 C++常用功能源码系列前言一、常用加密算法1. md5是什么二、源码1. md52. base64、decode总结前言 本文是C/C++常用功能代码封装专栏的导航贴。部分来源于实战项目中的部分功能提炼,希望能够达到你在自己的项目中拿来就用的效果,这样更好的服务…

WebStorm + JetBrains IDE Support 实现自动刷新功能

找了半天&#xff0c;还借了朋友一个vpn,然后发现&#xff1a; JetBrains IDE Support已经下架&#xff1a; 关于插件JetBrains IDE Support在chrome商店中消失_webstorm启动chrome没有插件_kesin_lee的博客-CSDN博客 在写Html网页时&#xff0c;参考WebStrom说明文档&#xf…

【MySQL】P1 数据库基础以及MySQL下载安装

MySQL数据库基本概念MySQLSQL 简介前言 本篇博文为 MySQL 系列博文第一弹&#xff0c;主要围绕数据库基本概念&#xff0c;MySQL数据库下载安装以及SQL分类进行介绍。 下一篇博文将围绕 DDL 进行学习记录。 链接&#xff1a; 正文 数据库基本概念 数据库&#xff1a;存储数据…

华为OD机试用Python实现 -【垃圾信息拦截】 |2023.Q1 A卷

华为OD机试题 最近更新的博客华为 OD 机试 300 题大纲本篇题目:垃圾信息拦截题目描述输入描述输出描述示例一输入输出说明示例二输入输出编码思路和算法逻辑Python 代码实现最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单

python智能停车场车牌识别计费系统百度ai

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;python停车场 获取完整源码源文件说明文档可执行文件等 在PyCharm中运行《智能停车场车牌识别计费系统》即可进入如图1所示的系统主界面。 说明&#xff1a;在运行程序前&#xff0c;先将当前的计算机连接互联网&#xff0…

Windows+VS2019用vcpkg编译colmap

WindowsVS2019用vcpkg编译colmap Window下官方建议用vcpkg安装。这里我已经安装好了VS2019以及cuda11.7。 1.安装vcpkg git clone https://github.com/microsoft/vcpkg cd vcpkg .\bootstrap-vcpkg.bat2. 使用vcpkg编译colmap .\vcpkg install colmap[cuda,tests]:x64-wind…

cuda调试(一)vs2019-windows-Nsight system--nvtx使用,添加nvToolsExt.h文件

cuda调试 由于在编程过程中发现不同的网格块的结构&#xff0c;对最后的代码结果有影响&#xff0c;所以想记录一下解决办法。 CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid cuda context (上下文) context类似于CPU进程上下&#xff0c;表示由管理层 Drive …

信息系统项目管理师——OSI模型、协议

OSI七层网络模型&#xff08;掌握&#xff09; 应用层&#xff1a;对软件提供接口以使程序能使用网络服务&#xff0c;如事务处理程序、文件传送协议和网络管理等。&#xff08;HTTP、Telnet、FTP、SMTP&#xff09;表示层&#xff1a;程序和网络之间的翻译官&#xff0c;管理…

可选链运算符(?.)与空值合并运算符(??)

1. 可选链运算符Optional chaining(?.) MDN定义 可选链运算符&#xff08;?.&#xff09;允许读取位于连接对象链深处的属性的值&#xff0c;而不必明确验证链中的每个引用是否有效。?. 运算符的功能类似于 . 链式运算符&#xff0c;不同之处在于&#xff0c;在引用为空 (n…

JavaScript事件循环及任务处理

JavaScript事件循环及任务处理## 浏览器中 JavaScript 的执行流程和 Node.js 中的流程都是基于 事件循环 的。 理解事件循环的工作方式对于代码优化、性能优化很重要&#xff0c;有时对于正确的架构也很重要。 我们首先介绍事件循环工作方式的理论细节&#xff0c;然后介绍该知…

【数据库】MySQL数据库基础

目录 1.数据库&#xff1a; 2.数据库基本操作 2.1 MySQL的运行原理 2.2显示数据库&#xff1a; 2.3创建数据库 2.4使用数据库 2.5删除数据库 3.常见的数据类型 3.1数值类型&#xff1a; 3.2字符型类型 3.3日期类型 4.表的操作 4.1创建表 4.2查看表 4.3删除表 5.汇总…

【蓝桥杯PythonB组备赛】【Acwing周赛】第93场 4867. 整除数 4868. 数字替换 python解

目录 A AcWing 4867. 整除数 1.题目描述 2.思路分析 3.代码实现 B AcWing 4868. 数字替换 1.题目描述 2.思路分析 3.代码实现 A AcWing 4867. 整除数 1.题目描述 2.思路分析 为什么不能直接暴力&#xff1f; 数据&#xff1a;1 ≤ n, k ≤ 10 ** 9 1s内最多…

openpnp - 设备开机后, 吸嘴校验失败的解决方法

文章目录openpnp - 设备开机后, 吸嘴校验失败的解决方法概述重新校验吸嘴ENDopenpnp - 设备开机后, 吸嘴校验失败的解决方法 概述 设备开机后, 默认会校验吸嘴座上已经安装的2个吸嘴. 如果开机校验吸嘴失败, 就需要用向导重新校验失败的吸嘴. 具体是哪个吸嘴校验失败, 可以看…

C++的双端队列

双端队列介绍1.双端队列知识需知2.大试牛刀1.双端队列知识需知 由于队列是一种先进先出&#xff08;FIFO&#xff09;的数据结构&#xff0c;因此无法直接从队列的底部删除元素。如果希望从队列的底部删除元素&#xff0c;可以考虑使用双端队列&#xff08;deque&#xff09;。…