MyBatis XML基础操作

大家好,我是小帅,今天我们来讲MyBatis xml配置文件。


1. MyBatis XML配置⽂件

Mybatis的开发有两种⽅式:

  1. 注解
  2. XML

MyBatis XML的⽅式需要以下两步:

  1. 配置数据库连接字符串和MyBatis
  2. 写持久层代码

2. 配置连接字符串和MyBatis

此步骤需要进⾏两项设置,数据库连接字符串设置和 MyBatis 的 XML ⽂件配置。

如果是application.yml⽂件, 配置内容如下:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/db_study?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

如果是application.properties⽂件, 配置内容如下:

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?
characterEncoding=utf8&useSSL=false
#连接数据库的⽤⼾名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=root
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件 **是通配符
mybatis.mapper-locations=classpath:mapper/**Mapper.xml

3.写持久层代码

持久层代码分两部分

  1. ⽅法定义 Interface
  2. ⽅法实现: XXX.xml
    在这里插入图片描述

3.1添加 mapper 接⼝

数据持久层的接⼝定义:

import com.cdm.java_web_2025_1_23.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserInfoXMlMapper {
    List<UserInfo> queryAllUser();
}

3.2添加 UserInfoXMLMapper.xml

数据持久成的实现,MyBatis 的固定 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.cdm.java_web_2025_1_23.mapper.UserInfoMapper">

</mapper>

在这里插入图片描述
创建UserInfoXMLMapper.xml, 路径参考yml中的配置

在这里插入图片描述
查询所有⽤⼾的具体实现 :

<?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.cdm.java_web_2025_1_23.mapper.UserInfoXMlMapper">
    <select id="queryAllUser" resultType="com.cdm.java_web_2025_1_23.model.UserInfo">
        select * from user_info
    </select>
</mapper>

以下是对以上标签的说明:

  1. 标签:需要指定 namespace 属性,表⽰命名空间,值为 mapper 接⼝的全限定名,包括全包名.类名。
  2. 查询标签:是⽤来执⾏数据库的查询操作的
  3. id :是和 Interface (接⼝)中定义的⽅法名称⼀样的,表⽰对接⼝的具体实现⽅法。
  4. resultType :是返回的数据类型,也就是开头我们定义的实体类.
    在这里插入图片描述

3.4 单元测试

import com.cdm.java_web_2025_1_23.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class UserInfoXMlMapperTest {

    @Autowired
    private UserInfoXMlMapper userInfoXMlMapper;

    @Test
    void queryAllUser() {
        List<UserInfo> list = userInfoXMlMapper.queryAllUser();
        System.out.println(list);
    }
}

运⾏结果如下:
在这里插入图片描述

4.4 增删改查操作

接下来,我们来实现⼀下⽤⼾的增加、删除和修改的操作

4.4.1增(Insert)

UserInfoXMlMapper接⼝:

    Integer insertUser(UserInfo userInfo);

UserInfoXMlMapper.xml实现:

    <insert id="insertUser">
        insert into user_info (user_name, user_password, phone) values (#{userName}, #{userPassword},#{phone})
    </insert>

如果使⽤@Param设置参数名称的话, 使⽤⽅法和注解类似

UserInfoXMlMapper接⼝:

Integer insertUser(@Param("userInfo") UserInfo userInfo);

UserInfoXMlMapper.xml实现:

    <insert id="insertUser">
        insert into user_info (user_name, user_password, phone) 
        values (#{userInfo.userName},#{userInfo.userPassword},#{userInfo.phone})
    </insert>

4.4.2 返回⾃增 id

接⼝定义不变, Mapper.xml 实现 设置useGeneratedKeys 和keyProperty属性

    <insert id="insertUser3" useGeneratedKeys="true" keyProperty="id">
        insert into user_info (user_name, user_password, phone)
        values (#{userInfo.userName},#{userInfo.userPassword},#{userInfo.phone})
    </insert>

4.4.3 删(Delete)

UserInfoXMlMapper接⼝:

Integer deleteUser(Integer id);

UserInfoXMlMapper.xml实现:

<delete id="deleteUser">
 delete from user_info where id = #{id}
</delete>

4.4.4 改(Update)

UserInfoXMlMapper接⼝:

Integer updateUser(UserInfo userInfo);

UserInfoXMlMapper.xml实现:

<update id="updateUser">
 update user_info set username=#{username} where id=#{id}
</update>

4.4.5 查(Select)

同样的, 使⽤XML 的⽅式进⾏查询, 也存在数据封装的问题
我们把SQL语句进⾏简单修改, 查询更多的字段内容

    <select id="queryAllUser" resultType="com.cdm.java_web_2025_1_23.model.UserInfo">
        select * from user_info
    </select>

运⾏结果:
在这里插入图片描述
结果显⽰: deleteFlag, createTime, updateTime 也没有进⾏赋值.
解决办法和注解类似:

  1. 起别名
  2. 结果映射
  3. 开启驼峰命名

其中1,3的解决办法和注解⼀样,不再多说, 接下来看下xml如果来写结果映射

    <resultMap id="BaseMap" type="com.cdm.java_web_2025_1_23.model.UserInfo">
        <result column = "user_name" property = "userName"></result>
        <result column="user_password" property="userPassword"></result>
    </resultMap>

    <select id="queryAllUser" resultMap="BaseMap">
        select * from user_info
    </select>

在这里插入图片描述

5. #{} 和 ${}

MyBatis 参数赋值有两种⽅式, 咱们前⾯使⽤了 #{} 进⾏赋值, 接下来我们看下⼆者的区别

1. 先看Interger类型的参数

    @Select("select * from user_info where id= #{userId} ")
    public UserInfo queryById(@Param("userId") Integer id);

观察我们打印的⽇志
在这里插入图片描述
发现我们输出的SQL语句,id的值是使⽤ ? 进⾏占位. 这种SQL 我们称之为"预编译SQL"

我们把 #{} 改成 ${} 再观察打印的⽇志:
在这里插入图片描述
可以看到, 这次的参数是直接拼接在SQL语句中了.

2. 接下来我们再看String类型的参数

    @Select("select * from user_info where user_name= #{userName} ")
    UserInfo queryByName(String name);

观察我们打印的⽇志, 结果正常返回
在这里插入图片描述
我们把 #{} 改成 ${} 再观察打印的⽇志:
在这里插入图片描述
可以看到, 这次的参数依然是直接拼接在SQL语句中了, 但是字符串作为参数时, 需要添加引号 ‘’ , 使⽤ ${} 不会拼接引号 ‘’ , 导致程序报错.

修改代码如下:

    @Select("select * from user_info where user_name= '${userName}' ")
    UserInfo queryByName(String name);

在这里插入图片描述
从上⾯两个例⼦可以看出:

  1. #{} 使⽤的是预编译SQL, 通过 ? 占位的⽅式, 提前对SQL进⾏编译, 然后把参数填充到SQL语句中. #{} 会根据参数类型, ⾃动拼接引号 ‘’ .
  2. ${} 会直接进⾏字符替换, ⼀起对SQL进⾏编译. 如果参数为字符串, 需要加上引号 ‘’ .

6.#{} 和 ${}区别

  1. 性能更⾼

编译SQL,编译⼀次之后会将编译后的SQL语句缓存起来,后⾯再次执⾏这条语句时,不会再次编译(只是输⼊的参数不同), 省去了解析优化等过程, 以此来提⾼效率

  1. 更安全(防⽌SQL注⼊)
    SQL注⼊:是通过操作输⼊的数据来修改事先定义好的SQL语句,以达到执⾏代码对服务器进⾏攻击的⽅法。

由于没有对⽤⼾输⼊进⾏充分检查,⽽SQL⼜是拼接⽽成,在⽤⼾输⼊参数时,在参数中添加⼀些SQL关键字,达到改变SQL运⾏结果的⽬的,也可以完成恶意攻击。

sql 注⼊代码: ’ or 1='1
SQL注⼊的例⼦

    @Select("select * from user_info where user_name= '${userName}' ")
    UserInfo queryByName(String name);

测试案例:

    @Test
    void queryByName() {
        UserInfo userInfo = userInfoMapper.queryByName("' or 1='1");
        System.out.println(userInfo);
    }
}

结果依然被正确查询出来了, 其中参数 or被当做了SQL语句的⼀部分
在这里插入图片描述

6.1 ${}排序功能

从上⾯的例⼦中, 可以得出结论: ${} 会有SQL注⼊的⻛险, 所以我们尽量使⽤#{}完成查询既然如此, 是不是 ${} 就没有存在的必要性了呢?
当然不是

下来我们看下${}的使⽤场景
排序查询结果

    @Select("select * from user_info order by id ${sort}")
    List<UserInfo> queryAllUserBySort(String sort);

正常
在这里插入图片描述
改成#{}
在这里插入图片描述

6.2 like 查询(like 使⽤ #{} 报错)

@Select("select * from user_info where username like '%#{key}%' ")
List<UserInfo> queryAllUserByLike(String key);

把 #{} 改成 $ {} 可以正确查出来, 但是${}存在SQL注⼊的问题, 所以不能直接使⽤ ${}.

解决办法: 使⽤ mysql 的内置函数 concat() 来处理,实现代码如下:

@Select("select * from user_info where username like concat('%',#{key},'%')" ")
List<UserInfo> queryAllUserByLike(String key);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆浆粉牛奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值