大家好,我是小帅,今天我们来讲MyBatis xml配置文件。
文章目录
1. MyBatis XML配置⽂件
Mybatis的开发有两种⽅式:
- 注解
- XML
MyBatis XML的⽅式需要以下两步:
- 配置数据库连接字符串和MyBatis
- 写持久层代码
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.写持久层代码
持久层代码分两部分
- ⽅法定义 Interface
- ⽅法实现: 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>
以下是对以上标签的说明:
- 标签:需要指定 namespace 属性,表⽰命名空间,值为 mapper 接⼝的全限定名,包括全包名.类名。
- 查询标签:是⽤来执⾏数据库的查询操作的
- id :是和 Interface (接⼝)中定义的⽅法名称⼀样的,表⽰对接⼝的具体实现⽅法。
- 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,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);
从上⾯两个例⼦可以看出:
- #{} 使⽤的是预编译SQL, 通过 ? 占位的⽅式, 提前对SQL进⾏编译, 然后把参数填充到SQL语句中. #{} 会根据参数类型, ⾃动拼接引号 ‘’ .
- ${} 会直接进⾏字符替换, ⼀起对SQL进⾏编译. 如果参数为字符串, 需要加上引号 ‘’ .
6.#{} 和 ${}区别
- 性能更⾼
编译SQL,编译⼀次之后会将编译后的SQL语句缓存起来,后⾯再次执⾏这条语句时,不会再次编译(只是输⼊的参数不同), 省去了解析优化等过程, 以此来提⾼效率
- 更安全(防⽌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);