JavaEE初学07

news2024/11/25 17:48:17

JavaEE初学07

    • Mybatis
        • ORM
        • Mybatis
            • 一对一结果映射
            • 一对多结果映射
        • Mybatis动态sql
            • if标签
            • trim标签
            • where标签
            • set标签
            • foreach标签
            • 补充

Mybatis

Mybatis是一款优秀的持久层框架,他支持自定义SQL、存储过程以及高级映射。Mybatis几乎免除了所有的JDBC代码以及设置参数和获取结果集的工作。Mybatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO(Plain Old Java Object,普通老式Java对象)为数据库中的记录。

获取数据库连接有两种方式:(1)DriveManager(2)数据库连接池
区别:
DriveManager每次都创建物理连接,关闭物理连接
数据库连接池在每次初始化时就创建一定数量的数据库连接,每次都从连接池获取连接,每次关闭不关闭物理连接,只是放回连接池(复用提高效率)

项目中,使用双中校检锁的单例模式,创建的是数据库连接池

操作命令对象:(1)简单的 (2)预编译 (3)存储过程
预编译可以提高性能,并且可以防止sql注入(替换占位符,字符串替换会进行转义)

使用Mybatis封装jdbc后,只需要提供: 要执行的SQL语句、要替换占位符的数据(一般为Java对象)、处理结果集(一般转化为Java对象)(查询时返回结果集、增删改时返回更新数量)其它如执行SQL、返回结果集、返回更新数量的步骤由框架来提供

ORM

ORM(Object Relational Mapping)即对象关系映射,将关系型数据库中的数据和对象建立起映射关系,进而自动的完成数据与对象的互相转换
ORM把数据库映射为对象:

	数据库表(table)                --->         类(class)
	记录(record,行数据)            --->         对象(object)
	字段(field)                     --->         对象的属性(attribute)

一般的ORM框架,会将数据库模型中每张表都映射为一个类

常见的ORM框架:Mybatis、Hibernate
Mybatis:半自动框架,自己写sql,更方便做sql的性能维护和优化,对关系型数据库模型要求不高,做调整时影响不会很大
缺点:不能跨数据库

Hibernate:全自动框架,自动组装sql语句,可以跨数据库,框架提供了多套主流数据库sql语句生成规则
缺点:学习成本高、对数据库模型依赖很大,需求频繁变更会很难维护和修改、很难定位问题、很难进行性能优化

Mybatis

Mybatis操作配置步骤
创建Maven项目,配置pom.xml文件
准备数据库初始化sql

pom.xml配置

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 默认使用的Spring Framework版本为5.2.10.RELEASE -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>mybatis-study</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <!-- spring-boot-starter-web: 基于SpringBoot开发的依赖包,
                                 会再次依赖spring-framework中基本依赖包,aop相关依赖包,web相关依赖包,
                                 还会引入其他如json,tomcat,validation等依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 排除tomcat依赖 -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 添加 Undertow 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>

        <!--引入AOP依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <!-- mybatis-spring-boot-starter: Mybatis框架在SpringBoot中集成的依赖包,
                                Mybatis是一种数据库对象关系映射Object-Relationl Mapping(ORM)框架,
                                其他还有如Hibernate等 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!-- Mybatis代码生成工具 -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>

        <!-- druid-spring-boot-starter: 阿里Druid数据库连接池,同样的运行时需要 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>

        <!-- JDBC:mysql驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
            <scope>runtime</scope>
        </dependency>

        <!-- spring-boot-devtools: SpringBoot的热部署依赖包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <!-- 不能被其它模块继承,如果多个子模块可以去掉 -->
            <optional>true</optional>
        </dependency>

        <!-- lombok: 简化bean代码的框架 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- spring-boot-starter-test: SpringBoot测试框架 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- SpringBoot的maven打包插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- 明确指定一些插件的版本,以免受到 maven 版本的影响 -->
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
            </plugin>
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
            <plugin>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.3</version>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>

        </plugins>
    </build>

</project>

sql创建

drop database if exists mybatis_study;
create database mybatis_study character set utf8mb4;

use mybatis_study;

drop table if exists user;
create table user(
                     id int primary key auto_increment,
                     username varchar(20) not null unique comment '账号',
                     password varchar(20) not null comment '密码',
                     nickname varchar(20) comment '用户昵称',
                     sex bit default 0 comment '性别,0/false为女,1/true为男',
                     birthday date comment '生日',
                     head varchar(50) comment '头像地址',
                     create_time timestamp default now() comment '创建日期,默认为插入时的日期'
) comment '用户表';

drop table if exists article;
create table article(
                        id int primary key auto_increment,
                        title varchar(20) not null comment '文章标题',
                        content mediumtext not null comment '文章内容',
                        view_count int default 0 comment '文章浏览量',
                        user_id int comment '外键:用户id',
                        create_time timestamp default now() comment '创建日期,默认为插入时的日期',
                        foreign key(user_id) references user(id)
) comment '文章表';

insert into user(username, password) values ('a1', '11');
insert into user(username, password) values ('a2', '12');
insert into user(username, password) values ('b', '2');
insert into user(username, password) values ('c', '3');

insert into article(title, content, user_id) value ('快速排序', 'public ...', 1);
insert into article(title, content, user_id) value ('冒泡排序', 'private ...', 1);
insert into article(title, content, user_id) value ('选择排序', 'private ...', 1);
insert into article(title, content, user_id) value ('归并排序', 'public ...', 2);
insert into article(title, content, user_id) value ('插入排序', 'protected ...', 2);
insert into article(title, content, user_id) value ('希尔排序', 'protected ...', 3);
insert into article(title, content, user_id) value ('List', 'public ...', 4);
insert into article(title, content, user_id) value ('Set', 'public ...', 4);
insert into article(title, content, user_id) value ('Map', 'public ...', 4);

创建启动类

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

配置文件

logging.level.root=debug
logging.level.druid.sql.Statement=DEBUG
logging.level.org.example=DEBUG
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_study?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:mapper/**Mapper.xml

创建数据库实体类

@Getter
@Setter
@ToString
public class User {
    private Integer id;
    private String username;
    private String password;
    private String nickname;
    private boolean sex;
    private Date birthday;
    private String head;
    private Date create_time;
}
@Getter
@Setter
@ToString
public class Article {
    private Integer id;
    private String title;
    private String content;
    private Integer view_count;
    private Integer user_id;
    private Date create_time;
}

创建mapper接口方法
在这个接口方法里,返回值就是jdbc操作后的返回:
查询时:如果结果集是一行数据,则返回一个对象,若查不到则返回null
如果结果集是多行数据,则返回一个List<类型>,查不到则返回一个空的List<类型>
更新时:返回int,更新多少条就返回多少
方法参数:要替换占位符的值

@Mapper
@Component
public interface ArticleMapple {
    Article selectById(Integer id);
}
@Mapper
@Component
public interface UserMapper {
    User selectById(Integer id);
}

配置实体映射文件
application.properties配置文件中配置的文件mybatis.mapper-locations=classpath:mapper/**Mapper.xml
在这里插入图片描述
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="org.example.mapper.ArticleMapper">
    <resultMap id="BaseResultMap" type="org.example.model.Article">
        <id column="id" property="id"/><!--主键字段-->
        <result column="title" property="title"/><!--普通字段-->
        <result column="content" property="content"/>
        <result column="view_count" property="view_count"/>
        <result column="user_id" property="user_id"/>
        <result column="creat_time" property="creat_time"/>
    </resultMap>
</mapper>

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="org.example.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="org.example.model.User">
        <id column="id" property="id"/><!--主键字段-->
        <result column="username" property="username"/><!--普通字段-->
        <result column="password" property="password"/>
        <result column="nickname" property="nickname"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <result column="head" property="head"/>
        <result column="creat_time" property="creat_time"/>
    </resultMap>
</mapper>

在实体映射文件添加接口中方法对映的增删改查字段,如:

<?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="org.example.mapper.ArticleMapper">
    <resultMap id="BaseResultMap" type="org.example.model.Article">
        <id column="id" property="id"/><!--主键字段-->
        <result column="title" property="title"/><!--普通字段-->
        <result column="content" property="content"/>
        <result column="view_count" property="view_count"/>
        <result column="user_id" property="user_id"/>
        <result column="creat_time" property="creat_time"/>
    </resultMap>


    <!--增删改查对应 <insert>、<delete>、<update>、<select>。方法名和id一致-->
    <select id="selectById" resultMap="BaseResultMap">
        select * from article where id = #{id}
    </select>


</mapper>

UserMapper.xml 同理,添加对应select标签
当sql操作为更新操作时,标签内容应变为:

    <update id="updateContentById" parameterType="org.example.model.Article">
        update article set content = #{content} where id = #{id}
    </update>

当接口方法的方法参数为多个时,则需要添加@Param注解,如:

    List<Article> selectLikeByTitleAndContent(@Param("title")String title , @Param("content")String content);

传入参数时,有时不需要添加单引号(如排序时desc(倒序)和asc(正序)),则需要使用${}来进行拼接,如:

List<Article> selectLikeByUserIdAndContentOrderBy(@Param("user_id")Integer user_id,@Param("content")String content,@Param("orderBy")String orderBy);
    <select id="selectLikeByUserIdAndContentOrderBy" resultMap="BaseResultMap">
        select * from article where user_id = #{user_id} and content like #{content} order by id ${orderBy}
    </select>
    @Test
    public void selectLikeByUserIdAndContentOrderBy(){
        List<Article> list = articleMapper.selectLikeByUserIdAndContentOrderBy(1,"p%","asc");
        System.out.println(list);
    }

增加数据时获取主键
useGeneratedKeys 这会使用JDBC的getGeneratedKeys 方法来获取由数据库内部生成的主键的值
keyProperty 指定能够唯一识别对象的属性

int insertGetIdKey(Article article);
    <insert id="insertGetIdKey" parameterType="org.example.model.Article" useGeneratedKeys="true" keyProperty="id">
        insert into article(title,content,user_id) values (#{title},#{content},#{user_id})
    </insert>
    @Test
    public void insertGetIdKey(){
        Article article = new Article();
        article.setTitle("123");
        article.setContent("123456");
        article.setUser_id(1);
        articleMapper.insertGetIdKey(article);
        System.out.println(article.gerId());//id有值
    }

查询结果集,包含两张表,对应两个JAVA类型的数据,他们之间产生了一对一,一对多的关系
如:
select * from user u join article a on u.id = a.user_id
在这里插入图片描述

一对一结果映射

返回List<Article>,以文章返回的主体,就应该表现为一个文章对应一个用户,一对一映射关系

public class Article{
	private User user;
}
public interface ArticleMapper {
	List<Article> selectAll();//查询所有文章信息,并携带用户信息,一对一
}	
	<resultMap>
	<!--把Article类中的user属性,建立一对一映射关系 property选择对应属性 columnPrefix前缀匹配(查找后哪个信息是user属性的属性) resultMap结果集映射-->
    <association property="user" columnPrefix="u_" resultMap="org.example.mapper.UserMapper.BaseResultMap"/>
    </resultMap>
    <select id="selectAll" resultMap="BaseResultMap">
        select a.*,u.id u_id,u.username u_username,u.password u_password,u.nickname u_nickname,u.sex u_sex,u.birthday u_birthday,u.head u_head,u.create_time u_create_time from user u join article a on u.id = a.user_id
    </select>
    @Test
    public void selectAll(){
        List<Article> articles = articleMapper.selectAll();
        articles.forEach(System.out::println);
    }
一对多结果映射

因为一个用户对应多个文章,所以返回的类型应该为List<User>,

public class User{
	List<Article> articles;
}
    List<User> selectAll1();
<mapper namespace="org.example.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="org.example.model.User">
    	<!--一对多映射(此处标签名与一对一映射标签名不一致  注意)-->
        <collection property="article" columnPrefix="a_" resultMap="org.example.mapper.ArticleMapper.BaseResultMap"/>
    </resultMap>
    <select id="selectAll1" resultMap="BaseResultMap">
        select u.*,a.id a_id,a.title a_title,a.content a_content,a.view_count a_view_count,a.user_id a_user_id,a.create_time a_create_time from article a join user u on a.user_id = u.id
    </select>
    @Test
    public void selectAll1(){
        List<User> users = userMapper.selectAll1();
        users.forEach(System.out::println);
    }

association 一对一标签 对象中包含另一个对象
collection 一对多标签 对象中包换List<另一个对象>


框架本质上是在运行期基于接口生成代理类,把接口方法生成具体的实现。找到sql,执行sql前替换占位符,执行完转换为java对象。

Mybatis动态sql

本质上就是根据不同条件,循环来动态的拼接sql语句

if标签

在插入一条数据时,有时会存在空的属性,此时如果插入为null,则不能自动插入为默认值,如果需要自动变为默认值,则不应该插入。此时就可以使用<if>
如:

    <insert id="insertIf" useGeneratedKeys="true" keyProperty="id">
        insert into article(
        title,content,user_id
        <if test="view_count!=null">
        ,view_count
        </if>
        ) values (
        #{title},#{content},#{user_id}
        <if test="view_count!=null">
        ,#{view_count}
        </if>)
    </insert>
trim标签

通常情况下,一个字段玄天时,一般使用if标签,多个字段需要选填时,一般使用trim标签
标签属性如下:
prefix:表示整个语句块外部,以prefix的值作为前缀
suffix:表示整个语句块外部,以suffix的值作为后缀
prefixOverrides:表示整个语句块内部需要去除的前缀
suffixOverrides:表示整个语句块内部需要去除的后缀

    <insert id="insertTrim" useGeneratedKeys="true" keyProperty="id">
        insert into article
        <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="title!=null">title,</if>
        <if test="content!=null">content,</if>
        <if test="user_id!=null">user_id,</if>
        <if test="view_count!=null">view_count,</if>
        </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="title!=null">#{title},</if>
        <if test="content!=null">#{content},</if>
        <if test="user_id!=null">#{user_id},</if>
        <if test="view_count!=null">#{view_count},</if>
        </trim>
    </insert>
where标签

在使用trim标签和if标签时,会存在一种trim标签中全部都是if标签,如果此时if标签全为null,那么就没有对应的条件,这样一来就会出现sql语法错误,此时就可以使用where标签。
where可理解为<trim prefix="where" prefixOverrides="and">
如:

    <select id="selectByCondition" resultMap="BaseResultMap">
        select * from user
        <where>
            <if test="id!=null">
                and id = #{id}
            </if>
            <if test="username!=null">
                and username = #{username}
            </if>
            <if test="password!=null">
                and password = #{password}
            </if>
            <if test="nickname!=null">
                and nickname = #{nickname}
            </if>
            <if test="sex!=null">
                and sex = #{sex}
            </if>
            <if test="birthday!=null">
                and birthday = #{birthday}
            </if>
            <if test="head!=null">
                and head = #{head}
            </if>
            <if test="create_time!=null">
                and create_time = #{create_time}
            </if>
        </where>
set标签

根据传入的用户对象属性来更新用户数据,可以使用<set>标签来指定动态内容
根据传入的id属性,来修改(更新)其它不为null的属性
具体操作为:

<update id="updateBySet" parameterType="org.example.model.Article">
        update article
        <set>
            <trim suffixOverrides=",">
                <if test="title!=null">
                    title = #{title},
                </if>
                <if test="content!=null">
                    content = #{content},
                </if>
                <if test="view_count!=null">
                    view_count = #{view_count},
                </if>
                <if test="user_id!=null">
                    user_id = #{user_id},
                </if>
                <if test="create_time!=null">
                    create_time = #{create_time},
                </if>
            </trim>
        </set>
        where id = #{id}
    </update>
foreach标签

对集合进行遍历可使用foreach标签,foreach有以下属性
collection:绑定方法参数中的集合,如List、Set、Map或数组对象
item:遍历时的每一个对象
open:语句开头的字符串
close:语句结束的字符串
separator:每次遍历之间间隔的字符串
如:批量删除:

    int deleteByIds(List<Integer> ids);
    <delete id="deleteByIds" >
        delete from article where id in
        <foreach collection="list" item="item" open="(" close="_" separator=",">
            #{item}
        </foreach>
    </delete>

批量插入:

    int insertBatch(List<Article> articles);
    <insert id="insertBatch">
        insert into article (title,content,user_id) values
        <foreach collection="list" item="item" separator=",">
            (#{item.title},#{item.content},#{item.user_id})
        </foreach>
    </insert>
    @Test
    public void insertBatch() {
        Article a1 = new Article();
        a1.setTitle("l");
        a1.setContent("llllll");
        a1.setUser_id(1);
        Article a2 = new Article();
        a2.setTitle("i");
        a2.setContent("iiiiiii");
        a2.setUser_id(2);
        Article a3 = new Article();
        a3.setTitle("t");
        a3.setContent("ttttttt");
        a3.setUser_id(3);
        System.out.println(articleMapper.insertBatch(Arrays.asList(a1,a2,a3)));
        List<Article> articles = articleMapper.selectAll();
        articles.forEach(System.out::println);
    }
补充

JDBC的操作步骤
(1)创建数据库连接池DataSource
(2)通过DataSource获取数据库链接Connection
(3)编写执行带?占位符的SQL语句
(4)通过Connection及SQL创建操作命令对象Statement
(5)替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
(6)使用Statement执行SQL语句
(7)查询操作:返回结果集ResultSet,更新操作:返回更新的数量
(8)处理结果集
(9)释放资源


占位符
占位符要替换的值:传入的java对象:(插入的值、修改的值、条件字段的值)


数据库初始化

打开数据库配置界面
在这里插入图片描述
点击左上角+号 选择Mysql
在这里插入图片描述
选择驱动程序
在这里插入图片描述
下载驱动文件
在这里插入图片描述
输入用户名密码后点击测试链接,出现绿色勾后点击确定建立连接
在这里插入图片描述
右击sql文件,点击RUN
在这里插入图片描述
点击加号 双击刚才建立的连接 点击确定就初始化完成了
在这里插入图片描述


配置启动类
在这里插入图片描述

在这里插入图片描述


配置完映射文件后,如果需要测试相关配置是否正确,可以在test目录下来进行测试
操作如下:
创建测试类
在这里插入图片描述

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@Transactional//使用事务在测试代码,会自动回滚
public class ArticleMapperTest {
    @Autowired
    private ArticleMapper articleMapper;
    @Test
    public void selectById(){
        Article a = articleMapper.selectById(1);
        System.out.println(a);
    }
}

右击运行即可
在这里插入图片描述


特殊查找
若查找为模糊查找可以用下列两种方法,
(1)可直接把字符串写为"select * from user where username like #{username}" 传入参数时username=“a%”
(2)也可在sql语句中进行拼接select * from user where username like concat(${username},'%') 但是,这种方式存在sql注入的风险


如果只有一个参数(类型为包装类型、基本数据类型),xml中变量名不作要求(xml中变量名可以随便写,如:id=#{aaa}也可以直接获取到)
如果只有一个参数,且类型为POJO类型,xml中,占位符变量名为对象中的属性
如果有多个参数,必须在接口方法参数上,使用@Param("变量名")
如果有多个参数(类型为包装类型、基本数据类型),xml中应写为#{变量名}
如果只有多个参数,且类型为POJO类型,xml中应写为#{变量名.属性}

当被Param注解时,注解内容名称就必须跟xml中通配符的名称一致

多个参数且类型为POJO:

List<Article> selectLikeByUserIdAndContent(@Param("user") User user , @Param("content")String content);
    <select id="selectLikeByUserIdAndContent" resultMap="BaseResultMap">
        select * from article where user_id = #{user.id} and content like #{content}
    </select>

占位符
#{变量名} 会先替换为?,再替换值,所以,替换的字符串值,会带上单引号来替换
${变量名} 会以字符串拼接的方式来替换,所以,替换的字符串值,没有单引号,故存在sql注入的风险

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

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

相关文章

【layui】table的switch、edit修改

<title>简单表格数据</title><div class"layui-card layadmin-header"><div class"layui-breadcrumb" lay-filter"breadcrumb"><a>系统设置</a><a>简单表格数据</a></div> </div>&…

工具使用_docker容器_crossbuild

1. 工具简介 2. 工具使用 拉取 multiarch/crossbuild 镜像&#xff1a; docker pull multiarch/crossbuild 创建工作目录和示例代码&#xff1a; mkdir -p ~/crossbuild-test cd ~/crossbuild-test 创建 helloworld.c &#xff1a; #include <stdio.h>int main() …

Android 天气APP(三十七)新版AS编译、更新镜像源、仓库源、修复部分BUG

上一篇&#xff1a;Android 天气APP&#xff08;三十六&#xff09;运行到本地AS、更新项目版本依赖、去掉ButterKnife 新版AS编译、更新镜像源、仓库源、修复部分BUG 前言正文一、更新镜像源① 腾讯源③ 阿里源 二、更新仓库源三、修复城市重名BUG四、地图加载问题五、源码 前…

基于Java Springboot海洋馆预约系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

采用python3.12 +django5.1 结合 RabbitMQ 和发送邮件功能,实现一个简单的告警系统 前后端分离 vue-element

一、开发环境搭建和配置 #mac环境 brew install python3.12 python3.12 --version python3.12 -m pip install --upgrade pip python3.12 -m pip install Django5.1 python3.12 -m django --version #用于检索系统信息和进程管理 python3.12 -m pip install psutil #集成 pika…

STM32的中断(什么是外部中断和其他中断以及中断号是什么)

一、什么是EXTI 和NVIC EXTI&#xff08;External Interrupt/Event Controller&#xff09;EXTI 是外部中断/事件控制器&#xff0c;它负责处理外部信号变化&#xff0c;并将信号传递给中断控制器&#xff08;如 NVIC&#xff09;。主要负责以下功能&#xff1a; 外部事件检测…

【MyBatis】全局配置文件—mybatis.xml 创建xml模板

文章目录 模板文件配置元素typeAliasessettings 模板文件 创建模板 按照顺序打开【File】–>【settings】–>【Editor】–>【File and Code Templates】&#xff08;或直接搜索&#xff09; <?xml version"1.0" encoding"UTF-8" ?> <…

『VUE』34. 异步组件(详细图文注释)

目录 加载速度的优化示例代码总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 加载速度的优化 实际项目中你可能会有几十个组件,如果一开始就加载了全部组件(哪怕其中有些组件你暂时用不到)这无疑大大增加了响应时间,用户体验…

鸿蒙开发-音视频

Media Kit 特点 一般场合的音视频处理&#xff0c;可以直接使用系统集成的Video组件&#xff0c;不过外观和功能自定义程度低Media kit&#xff1a;轻量媒体引擎&#xff0c;系统资源占用低支持音视频播放/录制&#xff0c;pipeline灵活拼装&#xff0c;插件化扩展source/demu…

Spark——安装步骤详细教程

1、安装步骤 1、上传 cd /opt/modules 2、解压 tar -zxf spark-3.1.2-bin-hadoop3.2.tgz -C /opt/installs 3、重命名 cd /opt/installs mv spark-3.1.2-bin-hadoop3.2 spark-local 4、创建软链接 ln -s spark-local spark 5、配置环境变量&#xff1a; vi /etc/prof…

MFC工控项目实例三十一模拟量转化为工程量

实测工程量值&#xff08;变送器量程最大值-变送器量程最小值&#xff09;/&#xff08;数字量最大值-数字量最小值&#xff09;*&#xff08;当前采集工程量值-零点误差值&#xff09;。 相关程序代码 SEAL_PRESSURE.h class CSEAL_PRESSUREApp : public CWinApp { public:C…

svn 崩溃、 cleanup失败 怎么办

在使用svn的过程中&#xff0c;可能出现整个svn崩溃&#xff0c; 例如cleanup 失败的情况&#xff0c;类似于 这时可以下载本贴资源文件并解压。 或者直接访问网站 SQLite Download Page 进行下载 解压后得到 sqlite3.exe 放到发生问题的svn根目录的.svn路径下 右键呼出pow…

Win10系统开启了文件夹管控(文件夹限制访问)导致软件向系统公共文档目录写入失败的问题排查分享

目录 1、问题说明 2、查看系统是否开启了文件夹管控 3、在未安装杀毒软件的Win10电脑上可能会自动打开文件夹管控 4、到微软官网上查看Windows 安全中心的病毒和威胁防护与文件夹管控的详细说明 5、解决办法探讨 6、最后 C++软件异常排查从入门到精通系列教程(专栏文章列…

移远通信推出全新5G RedCap模组RG255AA系列,以更高性价比加速5G轻量化大规模商用

11月20&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;正式推出其全新5G RedCap模组RG255AA系列。该系列模组支持5G NR独立组网&#xff08;SA&#xff09;和LTE Cat 4双模通信&#xff0c;具有高性能高集成度、低功耗、小尺寸、高性价比等优势&#…

传输控制协议(TCP)和用户数据报协议(UDP)

一、传输控制协议&#xff08;TCP&#xff09; 传输控制协议&#xff08;Transmission Control Protocol&#xff0c;TCP&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议&#xff0c;由 IETF 的 RFC 793 定义。 它通过三次握手建立连接&#xff0c;确保数…

C++初阶(十五)--STL--list 的深度解析与全面应用

文章目录 一、头文件与基本概念 二、构造函数和析构函数 1.构造函数 2.析构函数 三、元素访问 front back 四、迭代器相关函数 begin end rebegin&#xff08;反向迭代器&#xff09; rend&#xff08;反向迭代器&#xff09; 五、容量相关函数 empty size max…

企业数智化新纪元,安全体系保驾护航

随着云计算、大数据、人工智能等技术的不断发展成熟&#xff0c;企业数智化建设进入到了深水区&#xff0c;网络安全已经成为企业发展最重要的基石。企业如何更好地拥抱先进生产力、构建强大的安全体系、重塑企业核心竞争力&#xff0c;是每一位技术决策者需要认真思考和解决的…

学Linux的第九天--磁盘管理

目录 一、磁盘简介 &#xff08;一&#xff09;、认知磁盘 &#xff08;1&#xff09;结构 &#xff08;2&#xff09;物理设备的命名规则 &#xff08;二&#xff09;、磁盘分区方式 MBR分区 MBR分区类型 扩展 GPT格式 lsblk命令 使用fdisk管理分区 使用gdisk管理分…

QT实现拷贝复制文件操作 QT5.12.3环境 C++实现

案例需求&#xff1a;利用QT线程操作&#xff0c;实现拷贝复制文件操作 代码&#xff1a; myfile.h #ifndef MYFILE_H #define MYFILE_H#include <QObject> #include <QDebug> #include <QThread> #include <QFile> #include <QtWidgets> class…

IDEA 2024安装指南(含安装包以及使用说明 cannot collect jvm options 问题 四)

汉化 setting 中选择插件 完成 安装出现问题 1.可能是因为之前下载过的idea&#xff0c;找到连接中 文件&#xff0c;卸载即可。