12. MyBatis(二)

源码位置:MyBatis_demo

上篇文章我们学习了MyBatis的定义以及增删查改操作,并且学习了如何在xml文件中编写SQL时使用#{}的方式将参数和对象的属性映射到SQL语句中,上篇的内容已经足以应对大部分场景,本篇文章我们就要学习一下MyBatis的进阶操作,拿捏MyBatis实战。

1. 参数占位符 —— #{} 和 ${}

MyBatis中有两种参数占位符,分别是"#{}""${}",上节课我们学习了"#{}"的使用,以上节课根据id查询用户的业务为例:

接口以及xml文件中的SQL实现如下:

public UserInfo getUserById(@Param("uid") Integer id);

把xml文件中的"#{}"改为"${}"

<select id="getUserById" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where id = ${uid}
</select>

调用测试方法后成功查到数据:

image.png

我们发现将"#{}"改为"${}"后同样能够查出数据,那不是玩我呢吗?

不要着急,这时我们再编写一个通过username查询的业务,接口以及xml文件中的SQL实现如下:

public List<UserInfo> getUserByUsername(@Param("username") String username);
<select id="getUserByUsername" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where username = #{username}
</select>

单元测试:

@Test
void getUserByUsername() {
    List<UserInfo> userInfoList = userMapper.getUserByUsername("zhangsan");
    System.out.println(userInfoList);
}

在使用"#{}"参数占位符的情况下成功取到数据:

image.png

改为"${}"后居然报错了,报错信息:在where子句中有未知的列’zhangsan’

image.png

为什么呢会这样呢?我明明是想要查询usernamezhangsan的列呀,他为什么说没找到名字为"zhangsan"的列呢?原因很简单,两种占位符的区别如下:

1.1 #{}:预编译处理

#{}是预编译处理,等同于JDBC中的"?"占位符,预编译的SQL语句不是有具体数值的语句,而是用(?)来代替具体数据,然后在执行的时候再调用setXXX()方法把具体的数据传入。

<select id="getUserByUsername" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where username = #{username}
</select>

预编译的处理下,在数据库中执行的SQL语句为:select * from userinfo where username = "zhangsan";也就是查询usernamezhangsan的数据。

1.2 ${}:字符直接替换

${}是字符直接替换,会直接将传入参数的值放入SQL语句中。

<select id="getUserByUsername" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where username = ${username}
</select>

在数据库中执行的SQL语句为:select * from userinfo where username = zhangsan;,这时就变成了在表中查找出所有userinfozhangsan这两个字段值相同的数据;

了解后了两者的差异后,我们直接将xml中的SQL改为下面的形式:

<select id="getUserByUsername" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where username = '${username}'
</select>

也成功查询到了数据:

image.png

1.3 ${}的缺陷:SQL注入

以登录功能为例,正常情况下,用户在前端需要传一个账号和密码给后端,后端再把账号和密码放到where子句中查询数据库,如果查到对应的数据,就证明用户名和密码输入正确,登录成功,SQL语句如下:

select * from userinfo where username = 'zhangsan' and password = '123';

输入正确就能查询到数据:

image.png

否则就查不到数据:

image.png

这时我们来使用${}实现一下登录功能:

接口:

public UserInfo userLogin(@Param("username") String username, @Param("password") String password);

xml编写SQL:

<select id="userLogin" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where username = '${username}' and password = '${password}'
</select>

单元测试:

@Test
void userLogin() {
    UserInfo userInfo = userMapper.userLogin("zhangsan", "123");
    if (userInfo == null) {
        System.out.println("用户名或密码错误,请重新登录!");
    } else {
        System.out.println("登录成功!");
        System.out.println(userInfo);
    }
}

在输入正确的账号和密码后,打印了下面信息:

image.png

输入错误的密码后,打印了下面信息:

image.png

1.3.1 SQL注入

当有别有用心之人在其不知道密码的情况下,恶意利用SQL语句的特性登录成功,就是SQL注入,下面给大家举个例子:

SQL注入代码:“’ or 1='1”

将传入的密码改为上面的SQL注入语句:

@Test
void userLogin() {
    UserInfo userInfo = userMapper.userLogin("zhangsan", "' or 1='1");
    if (userInfo == null) {
        System.out.println("用户名或密码错误,请重新登录!");
    } else {
        System.out.println("登录成功!");
        System.out.println(userInfo);
    }
}

居然真的查询到相应字段了,该用户也就登录成功了:

image.png

为什么会出现这种情况呢?

原因是将密码写为' or 1='1传入数据库查询时,语句就变成了下面这样:

image.png

此时不管你输入的密码是什么,都会查询出表中的所有数据,这就是SQL注入。

如果是预编译的话,数据库就只会把' or 1='1当作一整个字符串去处理,而不会把它当作SQL脚本去处理,也就不会出现SQL注入的问题,我们现在将xml文件中的SQL改写为#{}的形式:

<select id="userLogin" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where username = '${username}' and password = #{password}
</select>

查不到任何数据,登录失败!

image.png

1.4 ${}的使用场景

1.4.1 排序查询

既然预处理这么好用,为什么会存在两种占位符呢?存在即合理,有些特殊情况就是需要使用"${}"来处理的。

当后端需要传一些关键字,比如专栏中给用户提供了选择通过数据库的某一列进行排序文章的功能,实现这个功能就需要使用${}来完成

image.png

这时我们在数据库中就需要使用order by xxx作为排序的依据,如果使用"#{}"的方式,由于后端传入了一个String,就会预编译order by 'xxx'

因此此时需要使用${}来实现排序查询,具体的接口与SQL实现如下:

public List<ArticleInfo> sortArticle(@Param("sort") String sort);
<select id="sortArticle" resultType="com.chenshu.mybatis_demo.model.ArticleInfo">
    select * from articleinfo order by ${sort}
</select>

单元测试:根据createtime字段排序

@Test
void sortArticle() {
    List<ArticleInfo> articleList= articleMapper.sortArticle("createtime");
    for (ArticleInfo articleInfo : articleList) {
        System.out.println(articleInfo);
    }
}

运行结果:成功根据createtime字段的升序打印所有文章列表

image.png

1.4.2 like 模糊查询

a) 使用${}

like 使用 #{} 会报错,因为预编译后的SQL如下:

image.png

这时我们就可以使用${},接口以及实现如下:

public List<ArticleInfo> searchArticle(@Param("title") String title);
<select id="searchArticle" resultType="com.chenshu.mybatis_demo.model.ArticleInfo">
    select * from articleinfo where title like '%${title}%'
</select>

单元测试:

@Test
void searchArticle() {
    List<ArticleInfo> articleList = articleMapper.searchArticle("MyBatis");
    for (ArticleInfo articleInfo : articleList) {
        System.out.println(articleInfo);
    }
}

成功查询到 title 中带 ‘MyBatis’ 的数据:

image.png

b) 使用concat()

concat()是mysql内置函数,可以用作字符串的拼接:

image.png

修改xml中的SQL语句:

<select id="userLogin" resultType="com.chenshu.mybatis_demo.model.UserInfo">
    select * from userinfo where username = '${username}' and password = #{password}
</select>

再次进行单元测试:

image.png

2. resultMap的使用

上一篇文章我们提到过resultType的使用,作用是将数据库返回的记录和类映射起来,但是当类的属性名与数据库中的列名不同时,就会出现无法映射的问题,这里我来举个例子:

将UserInfo原来的属性名username修改为name:

@Data
public class UserInfo {
    private int id;
    private String username;
    private String password;
    private String photo;
    private Timestamp createTime;
    private Timestamp updateTime;
    private int state;
}

此时再调用一下单元测试的getAll()方法,发现name的值为null:

image.png

这里我们就需要使用resultMap定义一个映射规则来解决字段名和属性名不同的情况:

<resultMap id="userInfoMap" type="com.chenshu.mybatis_demo.model.UserInfo">
    <id column="id" property="id"/>
    <result column="username" property="name"/>
</resultMap>

解释下上面的标签和属性分别代表什么:

  • resultMap标签中的id就是你给该映射规则自定义的名称;
  • resultMap标签中的type就对应着你需要映射的类;
  • id标签是用来映射主键的,使用上推荐不管表中主键字段名和映射类的的属性是否相同,都配置这一项,否则多表查询的时候会出问题;
  • result标签是用来映射普通字段和映射类的属性的
  • idresult标签中都有一个columnproperty属性,是用来配置映射的,分别对应表的字段名类的属性名

getAll()方法对应的SQL中的resultType改为resultMap

<select id="getAll" resultMap="userInfoMap">
    select * from userinfo
</select>

再次测试,成功拿到了name(对应数据库中的username)的值:

image.png

3. 多表查询

  1. 连接表需要查询的字段添加到实体类

image.png

  1. 编写接口的getAll()方法以及xml文件中的SQL
public List<ArticleInfo> getAll();
<select id="getAll" resultType="com.chenshu.mybatis_demo.model.ArticleInfo">
    select a.*, u.username from articleinfo as a
    left join userinfo as u
    on a.uid = u.id
</select>
  1. 单元测试并得到结果
@Test
void getAll() {
    List<ArticleInfo> list = articleMapper.getAll();
    for (ArticleInfo articleInfo : list) {
        System.out.println(articleInfo);
    }
}

image.png

4. 动态SQL

动态SQL是MyBatis的强大特性之一,能够完成不同条件下不同的SQL拼接。
为什么要使用动态SQL呢?给大家引入一个案例:

在注册用户的时候,可能分为必填字段非必填字段,如果添加用户的时候有不确定的字段传入,程序应该如何实现呢?

这时候就有小伙伴提到:大不了多写几个方法让他们重载呗。

这种方式十分不优雅:如果是一个选填字段的话,就需要去写两个方法,两个选填字段的话就要写四个方法,如果有n个选填字段,那么就需要写2^n个方法…

因此我们就需要要使用MyBatis的重要特性 —— 动态SQL,接下来我们就来讲解一下常用的动态SQL标签的使用。

在讲解动态SQL标签之前可以在配置文件中添加一下log-impl用于打印SQL语句,以便对比:

image.png

4.1 <if>标签

前面提到的案例就要使用<if>动态标签来判断了。

这里我们来具体使用下<if>标签,比如用户在注册的时候,必填字段为usernamepassword,选填字段为photo

表结构如下:photo字段默认值为'';

image.png

4.1.1 不使用<if>标签

public int add(UserInfo userInfo);
<insert id="add">
    insert into userinfo(username, photo, password)
    values (
            #{name},
            #{photo},
            #{password})
</insert>

单元测试代码:

@Test
void add() {
    UserInfo userInfo = new UserInfo();
    userInfo.setName("zhangsan");
    userInfo.setPassword("123");
    userMapper.add(userInfo);
}

日志信息如下:我们发现SQL语句被预编译成了Preparing: insert into userinfo(username, photo, password) values ( ?, ?, ?),并且photo字段传入了一个null

==>  Preparing: insert into userinfo(username, photo, password) values ( ?, ?, ?)
==>  Parameters: zhangsan(String), null, 123(String)
<==  Updates: 1

表中插入了如下字段:

image.png


4.1.2 使用<if>标签

需要在test属性内写判断的语句,如果"photo != null",那么就拼接if标签里面的内容,否则就不拼接:

<insert id="add">
    insert into userinfo(
                    username,
                    <if test="photo != null">
                        photo,
                    </if>
                    password
                    )
    values (
        #{name},
        <if test="photo != null">
            #{photo},
        </if>
        #{password}
    )
</insert>

插入一条"lisi"的数据(不带photo值):

@Test
void add() {
    UserInfo userInfo = new UserInfo();
    userInfo.setName("lisi");
    userInfo.setPassword("123");
    userMapper.add(userInfo);
}

日志信息如下:由于没有传入photo参数,因此SQL语句此时被编译成了insert into userinfo( username, password ) values ( ?, ? ),并且只传入了usernamepassword两个参数

==>  Preparing: insert into userinfo( username, password ) values ( ?, ? )
==>  Parameters: lisi(String), 123(String)
<==  Updates: 1

对比表中的两条数据,我们发现在不使用if标签的时候photo插入的值为null,使用if标签的时候photo的值为默认值''

image.png

使用if标签的意义: 由于NULL''在MySQL中是不同的,因此你要使用一个查询语句select * from userinfo where photo = '';,就无法查询到zhangsan这条记录:

image.png

甚至当photo标签的字段上加了nou null约束的话,在不使用if标签的情况下会直接报错

4.2 <trim>标签

前面我们在使用if标签的时候选择了使用一种取巧的方式,把使用if标签的地方放在参数的中间位置,如果位于最后面的话,会出现问题,像下面这样:

<insert id="add">
    insert into userinfo(
                    username,
                    password,
                    <if test="photo != null">
                        photo
                    </if>
                    )
    values (
        #{name},
        #{password},
        <if test="photo != null">
            #{photo}
        </if>
    )
</insert>

如果photo=null的话,不拼接photo的内容,此时的SQL语句就变成了insert into userinfo( username, password, ) values ( ?, ?, ),由于最后一个参数不能以逗号结尾,因此SQL会报语法错误:

image.png

这时候我们就需要去使用一个trim标签去操作,

<trim>标签中有如下属性:

  • prefix:表示整个语句块,以prefix的值为前缀
  • suffix:表示整个语句块,以suffix的值作为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀

假设我们三个参数(username, password, photo)都是可选参数,如何巧妙地使用trim标签来处理呢?

改造xml文件中的SQL:使用trim标签的prefixsuffix以及suffixOverrides参数

<insert id="add">
    insert into userinfo
                    <trim prefix="(" suffix=")" suffixOverrides=",">
                        <if test="name != null">
                            username,
                        </if>
                        <if test="password != null">
                            password,
                        </if>
                        <if test="photo != null">
                            photo
                        </if>
                    </trim>
    values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="name != null">
                #{name},
            </if>
            <if test="password != null">
                #{password},
            </if>
            <if test="photo != null">
                #{photo}
            </if>
        </trim>
</insert>

这里我需要多提一嘴,如果trim标签里的所有if语句都不生效,就不会添加前后缀,而是直接编译成:insert into userinfo values,因此在使用时至少传入一个参数

单元测试:

@Test
void add() {
    UserInfo userInfo = new UserInfo();
    userInfo.setName("wangwu");
    userInfo.setPassword("123");
    userMapper.add(userInfo);
}

日志信息如下:此时就算把可选字段作为最后一个参数,trim标签会帮我们吧最后一个','删掉,并且在开头和结尾分别添加上'('')'

==> Preparing: insert into userinfo ( username, password ) values ( ?, ? )
==> Parameters: wangwu(String), 123(String)
<== Updates: 1

4.3 <where>标签

where标签自然是为了where子句而设计的,当where子句中只有一个条件并且不确定传不传入的时候,可以使用一个if标签把整个where子句包裹起来。

但是当通过多个参数组合查询的时候就需要用到where标签了,比如用户根据uid+title来查询文章的操作时,又不确定传不传入的情况下:

select * from articleinfo where title = 'MyBatis入门' and uid = 1;
public List<ArticleInfo> selectByCondition(ArticleInfo articleInfo);

where标签的写法十分简单,作用如下:

  • 根据where标签的内容,决定要不要拼接where
  • 去掉最首个参数的and关键字,让sql符合数据库的执行标准

也可以使用<trim prefix = "where" prefixOverrides = "and">标签替换

<select id="selectByCondition" resultType="com.chenshu.mybatis_demo.model.ArticleInfo">
    select * from articleinfo
    <where>
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="uid != null">
            and uid = #{uid}
        </if>
    </where>
</select>

使用多种组合查询进行测试,首先要先把实体类中所有int类型的属性的类型改为Integer,否则在不传入参数的时候默认为0,而不是null

@Data
public class ArticleInfo {
    private Integer id;
    private String title;
    private String content;
    private Timestamp createtime;
    private Timestamp updatetime;
    private Integer uid;
    private Integer rcount;
    private Integer state;
    private String username;
}

接下来我将传入不同的参数进行测试。


1. 什么参数也不传:

@Test
void selectByCondition() {
    ArticleInfo articleInfo = new ArticleInfo();
    List<ArticleInfo> list = articleMapper.selectByCondition(articleInfo);
    for (ArticleInfo article : list) {
        System.out.println(article);
    }
}

打印SQL日志如下:

==>  Preparing: select * from articleinfo
==> Parameters: 
<==    Columns: id, title, content, createtime, updatetime, uid, rcount, state
<==        Row: 1, Spring Boot入门, <<BLOB>>, 2024-04-15 01:21:43, 2024-04-15 01:21:43, 1, 1, 1
<==        Row: 2, MyBatis入门, <<BLOB>>, 2024-04-15 01:21:45, 2024-04-15 01:21:45, 1, 1, 1
<==        Row: 3, MyBatis的插入操作, <<BLOB>>, 2024-04-16 01:07:49, 2024-04-16 01:07:49, 1, 1, 1
<==        Row: 4, 修改标题, <<BLOB>>, 2024-04-16 01:29:37, 2024-04-16 01:29:37, 1, 1, 1
<==        Row: 6, MyBatis添加并返回自增id, <<BLOB>>, 2024-04-16 01:53:53, 2024-04-16 01:53:53, 1, 1, 1
<==      Total: 5

2. 只传uid:

@Test
void selectByCondition() {
    ArticleInfo articleInfo = new ArticleInfo();
    articleInfo.setUid(1);
    List<ArticleInfo> list = articleMapper.selectByCondition(articleInfo);
    for (ArticleInfo article : list) {
        System.out.println(article);
    }
}

打印SQL日志如下:

==>  Preparing: select * from articleinfo WHERE uid = ?
==> Parameters: 1(Integer)
<==    Columns: id, title, content, createtime, updatetime, uid, rcount, state
<==        Row: 1, Spring Boot入门, <<BLOB>>, 2024-04-15 01:21:43, 2024-04-15 01:21:43, 1, 1, 1
<==        Row: 2, MyBatis入门, <<BLOB>>, 2024-04-15 01:21:45, 2024-04-15 01:21:45, 1, 1, 1
<==        Row: 3, MyBatis的插入操作, <<BLOB>>, 2024-04-16 01:07:49, 2024-04-16 01:07:49, 1, 1, 1
<==        Row: 4, 修改标题, <<BLOB>>, 2024-04-16 01:29:37, 2024-04-16 01:29:37, 1, 1, 1
<==        Row: 6, MyBatis添加并返回自增id, <<BLOB>>, 2024-04-16 01:53:53, 2024-04-16 01:53:53, 1, 1, 1
<==      Total: 5

3. 传多个参数:

@Test
void selectByCondition() {
    ArticleInfo articleInfo = new ArticleInfo();
    articleInfo.setUid(1);
    articleInfo.setTitle("MyBatis入门");
    List<ArticleInfo> list = articleMapper.selectByCondition(articleInfo);
    for (ArticleInfo article : list) {
        System.out.println(article);
    }
}

打印SQL日志如下:

==>  Preparing: select * from articleinfo WHERE title = ? and uid = ?
==> Parameters: MyBatis入门(String), 1(Integer)
<==    Columns: id, title, content, createtime, updatetime, uid, rcount, state
<==        Row: 2, MyBatis入门, <<BLOB>>, 2024-04-15 01:21:45, 2024-04-15 01:21:45, 1, 1, 1
<==      Total: 1

4.4 <set>标签

其实set标签与update标签很像,作用是:

  • 根据set标签里的内容决定要不要拼接"set"
  • 去掉最后一个参数的',',让sql符合数据库的执行标准

可以使用<trim prefix="set" suffixOverrides=",">替换。

具体使用:

public void updateUserInfo(UserInfo userInfo);
<update id="updateUserInfo">
    update userinfo
        <set>
            <if test="name != null">
                username=#{name},
            </if>
            <if test="password != null">
                password=#{password},
            </if>
            <if test="photo != null">
                photo=#{photo},
            </if>
            <if test="createtime != null">
                createtime = #{createtime},
            </if>
            <if test="updatetime != null">
                updatetime = #{updatetime},
            </if>
        </set>
    where id = #{id}
</update>

单元测试代码如下,修改字段为1的用户的usernamepassword以及photo字段:

@Test
void updateUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(1);
    userInfo.setName("zhang");
    userInfo.setPassword("12345");
    userInfo.setPhoto("doge.png");
    userMapper.updateUserInfo(userInfo);
}

修改前表的数据为以下记录:

image.png

运行代码后,日志打印信息如下:

==>  Preparing: update userinfo SET username=?, password=?, photo=? where id = ?
==> Parameters: zhang(String), 12345(String), doge.png(String), 1(Integer)
<==    Updates: 1

成功修改了下面三个字段:

image.png

4.5 <foreach>标签

当后端传入参数为集合(如List,Set,MapArray)并需要进行遍历时可以使用该标签,foreach标签有以下属性:

  • collection:绑定方法中用@Param定义的别名
  • item:用于给遍历时的每一个对象取一个名字
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

示例:根据多个文章id来删除文章数据

原SQL语句:

delete from articleinfo where id in(3,4,5)

具体实现:

public int deleteByIds(@Param("ids") List<Integer> ids);

注意事项:foreach标签中的collection中的值对应接口方法中定义的别名

<delete id="deleteByIds">
    delete from articleinfo
    where id in
    <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</delete>

此时表数据如下,我想要删除id字段为7,8,9文章:

image.png

单元测试:

@Test
void deleteByIds() {
    List<Integer> list = new ArrayList<>();
    list.add(7);
    list.add(8);
    list.add(9);
    int ret = articleMapper.deleteByIds(list);
    System.out.println("删除了:" + ret);
}

运行后打印日志信息如下:

==>  Preparing: delete from articleinfo where id in ( ? , ? , ? )
==> Parameters: 7(Integer), 8(Integer), 9(Integer)
<==    Updates: 3

成功删除了三条记录:

image.png

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

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

相关文章

测绘管理与法律法规 | 测绘资质管理办法 | 学习笔记

目录 一、测绘资质概述 二、测绘资质分类与等级 三、审批与管理 四、申请条件 五、审批程序 六、测绘资质证书 七、监督管理 八、违规处理 九、特殊规定 十、审批受理时间要点补充 1. 审批机关决定是否受理的时间 2. 审批机关作出批准与否的决定时间 3. 颁发测绘资…

linux /proc进程文件目录介绍

参考&#xff1a;https://zhuanlan.zhihu.com/p/619966043 有时候想只查出来进程号&#xff0c;可以通过/proc/下查出该进程的运行及执行脚本情况信息 /proc/pid子目录 记录了进程的相关信息cmdline文件&#xff1a;包含了进程启动时使用的完整命令行参数。 cwd符号链接&#x…

29. 【Android教程】折叠列表 ExpandableListView

本节学习一个可折叠的 ListView&#xff0c;可以用在一些需要分类的场景下。通过 ExpandableListView 我们可以首先在 ListView 上展示大的分类&#xff0c;当点击某个类别的时候再将 ListView 做一个展开&#xff0c;展示该类下的所有子类供用户选择。它与 ListView 的不同主要…

考研数学|武忠祥VS张宇,谁讲得更全面❓

张宇和武忠祥都是很好的老师&#xff0c;你肯定也是这么觉得的&#xff0c;你自己也说了&#xff0c;跟着张宇看了几章&#xff0c;感觉不错&#xff0c;那就继续跟着啊&#xff0c;为什么听到同学说武忠祥好&#xff0c;你就动摇了呢。我们对于任何事情都要有自己的思考和规划…

SQL注入简单总结

一、SQL注入是什么 SQL注入即&#xff1a;是指web应用程序对用户输入数据的合法性没有判断或过滤不严&#xff0c;攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句&#xff0c;在管理员不知情的情况下实现非法操作&#xff0c;以此来实现欺骗数据库服…

prompt问题【中间不好】

问题1:longchain 关键词在中间容易被忽略掉 Found in the Middle: How Language Models Use Long Contexts Better via Plug-and-Play Positional Encoding 论文对大模型在长文本情况下的性能做了一系列实验研究&#xff0c;发现了一个有趣的“Lost in the middle”现象&#x…

我与C++的爱恋:隐式类型转换

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 朋友们大家好&#xff0c;本篇内容我们来介绍初始化列表&#xff0c;隐式类型转换以及explicit的内容 一、初始化列表 1.1 构造函数体赋值 在创建对象时&#xff0c;编译器…

【笔试强训】Day3 --- 简写单词 + dd爱框框 + 除2!

文章目录 1. 简写单词2. dd爱框框3. 除2&#xff01; 1. 简写单词 【链接】&#xff1a;简写单词 解题思路&#xff1a;简单模拟题&#xff0c;主要是处理⼀下输⼊的问题。&#xff08;也可以利用string类中的find函数&#xff0c;但时间复杂度会偏高&#xff09; #include …

一套全院级PACS系统源码,实现影像检查的电子预约申请、电子诊断报告、 临床科室设立影像浏览终端等功能

一套全院级PACS系统源码&#xff0c;实现影像检查的电子预约申请、电子诊断报告、 临床科室设立影像浏览终端等功能 一套全院级PACS系统源码&#xff0c;包括放射、CT、超声、内镜、病理等科室影像及信息管理系统的建设&#xff0c;解决医学影像的采集、诊断、传输、存储&#…

电感与磁珠

电感是什么&#xff1f; 电感会通过产生感应电动势的方式来阻碍电流的变化&#xff0c;电流变化率越大&#xff0c;产生的感应电动势越大阻碍电流效果越明显。 [一]品质因数Q: 电感的品质因数Q值定义&#xff1a;电感的Q值也叫作品质因数&#xff0c;其为无功功率除以有功功率…

永恒之蓝复现

目录 一、原理 二、实验环境 三、实验步骤 \1. 查询ip \2. 测试两台主机的连通性 \3. 查询指kali数据库的状态 \4. 此时就可以进行永恒之蓝漏洞扫描&#xff0c;&#xff08;永恒之蓝利用的是ms17_010漏洞&#xff0c;因此到这一步之后的任务就是在kali 里寻找ms17_010漏…

比特币减半倒计时:NFT 生态将受到怎样的影响?

BTC 减半倒计时仅剩不到 1 天&#xff0c;预计在 4 月 20 日迎来减半。当前区块奖励为 6.25 BTC&#xff0c;减半后区块奖励为 3.125 BTC&#xff0c;剩余区块为 253。比特币减半无疑是比特币发展史上最重要的事件之一&#xff0c;每当这一事件临近&#xff0c;整个加密社区都充…

从零开始搭建网站(第二天)

今天把之前的htmlcssjs项目迁移过来&#xff0c;直接使用tspiniavue3vite组合&#xff0c;搭建过程可以看从零开始搭建性能完备的网站-思路过程&#xff08;1&#xff09;_自己架设一个芯参数网站-CSDN博客。之后安装一下volar扩展。迁移过来使用Vue重构时发现之前使用的左右两…

《深入浅出多模态》: 多模态经典模型:BLIP

🎉AI学习星球推荐: GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料,配有全面而有深度的专栏内容,包括不限于 前沿论文解读、资料共享、行业最新动态以、实践教程、求职…

计算机网络——GBN协议实现

实验目的 编程模拟实现GBN可靠传输软件 实验内容 C 程序模拟实现Go-Back-N可靠数据传输&#xff0c;需要编写一个发送端程序和一个测试端程序来模拟传输过程 具体流程 1. 编写发送端程序&#xff0c;调用库实现socket连接&#xff0c;然后主要实现滑动窗口&#xff0c;接收…

IDEA开启自动导包,自动删包

找到file----------->Settings选项 找到Editor-------->General------------>Auto Import选项 勾选两个选项&#xff0c;在点击Apply,在点击ok 最后就ok了

详解数据结构:栈

一、顺序栈 顺序栈的存储方式如下&#xff1a; 从图中可以看出&#xff0c;顺序栈需要两个指针&#xff0c;base指向栈底&#xff0c;top指向栈顶。 typedef struct SqStack {ElemType *base; //栈底指针ElemType *top; //栈顶指针}SqStack; 说明&#xff1a; ElemType是元…

8款不同的404页面(网站404页面必备)

第1款 部分代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>404</title><link rel"stylesheet" href"css/style.css"></head> <body><div cla…

C语言转型之路:从C到C++的类与对象初探

欢迎来CILMY23的博客 本篇主题为 C语言转型之路&#xff1a;从C到C的类与对象初探 个人主页&#xff1a;CILMY23-CSDN博客 个人专栏系列&#xff1a; Python | C语言 | 数据结构与算法 | C 感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 写在前头…

hive搭建完整教学

目录 简介准备工作安装步骤&#xff08;一&#xff09;、下载hive包并解压到指定目录下&#xff08;二&#xff09;、设置环境变量&#xff08;三&#xff09;、下载MySQL驱动包到hive的lib目录下&#xff08;四&#xff09;、将hadoop的guava包拷贝到hive&#xff08;五&#…