一、Mybatis XML配置文件
Mybatis开发有两种方式:
- 注解
- XML
之前讲解了注解的方式,接下来学习XML的方式
1.1 配置数据库连接和Mybatis
直接在配置文件中配置即可:
java
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:mapper/**Mapper.xml #配置xml文件的路径
UserInfoXMLMapper.xml的固定格式(以查询所有用户为例:
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.UserInfoXMLMapper">
<select id="queryAllUser" resultType="com.example.demo.model.UserInfo">
select username,`password`, age, gender, phone from userinfo
</select>
</mapper>
测试代码:
java
@Test
void queryAllUser() {
userInfoMapper.queryAllUser();
}
1.2 增(Insert)
xml文件:
XML
<insert id="insertUser">
insert into userinfo (username, `password`, age, gender, phone)
values (#{username}, #{password}, #{age},#{gender},#{phone})
</insert>
UserInfoXMLMapper接口:
java
Integer insertUser(UserInfo userInfo);
返回结果是影响的行数
返回自增id:
XML
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into userinfo (username, `password`, age, gender, phone)
values (#{username}, #{password}, #{age},#{gender},#{phone})
</insert>
1.3 删(Delete)
xml文件:
XML
<delete id="deleteUser">
delete from userinfo where id = #{id}
</delete>
1.4 改(Update)
xml文件:
XML
<update id="updateUser">
update userinfo set username=#{username} where id=#{id}
</update>
1.5 查(Select)
在使用注解查询所有用户时,会遇到有属性没有被赋值的情况,我们的解决方案分别为:起别名、结果映射、 列名驼峰式命名
现在使用xml文件,解决方案仍然是这三个,其中第1个和第3个和注解的方式一样,这里主要讲解以下结果映射
XML
<resultMap id="BaseMap" type="com.example.demo.model.UserInfo">
<id column="id" property="id"></id>
<result column="delete_flag" property="deleteFlag"></result>
<result column="create_time" property="createTime"></result>
<result column="update_time" property="updateTime"></result>
</resultMap>
<select id="queryAllUser" resultType="com.example.demo.model.UserInfo" resultMap="BaseMap">
select id, username,`password`, age, gender, phone, delete_flag, create_time, update_time from userinfo
</select>
二、#{} 和 ${}的区别
#{}和${}都可以用来赋值,我们之前都用的#{},接下来看以下这两个的区别
1. 赋值的是Integer类型
首先是#{}
XML
<select id="selectUserById" resultType="com.example.demo.model.UserInfo">
select username, password, age, gender, phone from userinfo where id = #{id}
</select>
观察日志:
我们输入的参数并没有拼接到SQL语句中,而是用?作为占位符,我们称这种SQL为预编译型SQL
现在改成${}
XML
<select id="selectUserById" resultType="com.example.demo.model.UserInfo">
select username, password, age, gender, phone from userinfo where id = ${id}
</select>
此时我们输入的参数拼接到了SQL语句中
2. 赋值的是String类型
首先是#{}
XML
<select id="selectUserByName" resultType="com.example.demo.model.UserInfo">
select username, password, age, gender, phone from userinfo where username = #{username}
</select>
改为${}
XML
<select id="selectUserByName" resultType="com.example.demo.model.UserInfo">
select username, password, age, gender, phone from userinfo where username = ${username}
</select>
由于SQL语法中,字符串类型需要加上单引号,将参数直接拼接到SQL语句中是没有加单引号的,因此会报错
所以要在xml中手动加上单引号
${}存在SQL注入问题
SQL注入:通过输入的数据来修改事先定义好的SQL语句,以达到执行代码共计服务器的方式
举例:查询名字为 lisi 的用户信息,正常情况要手动加上单引号
我们输入lisi后,就可查到他的信息,但如果将输入改为**'or 1 = '1** ,将该参数拼接到SQL语句后:
可以看到通过这个查询条件可以查询到所有用户的信息
如果将密码验证的代码简单的写成 password = '${password}',此时如果密码写 'or 1 = '1,就可以直接登录成功
2.1 排序功能
{}存在SQL注入问题,但也不是一点没用,其中排序就需要用到{}
XML
<select id="selectAllUserBySort" resultType="com.example.demo.model.UserInfo">
select username, password, age, gender, phone from userinfo order by id ${sort}
</select>
执行测试代码
java
@Test
void selectAllUserBySort() {
userInfoXMLMapper.selectAllUserBySort("desc");
}
如果使用#{},由于参数类型为String,在查询时,desc前后会自动加上单引号,但排序并不需要单引号,所以会出错
2.2 like 查询
like 使用#{}报错
java
@Select("select id, username, age, gender, phone, delete_flag, create_time,
update_time from userinfo where username like '%#{key}%' ")
List<UserInfo> queryAllUserByLike(String key);
把 #{} 改成 ${} 可以正确查出来,但是 ${} 存在SQL注⼊的问题,所以不能直接使⽤ ${}
解决方法:使⽤ mysql的内置函数concat()来处理,实现代码如下:
java
@Select("select id, username, age, gender, phone, delete_flag, create_time,
update_time from userinfo where username like concat('%',#{key},'%')")
List<UserInfo> queryAllUserByLike(String key);
三、动态SQL
1.1 <if>标签
<if>标签的作用:动态拼接
XML
<insert id="insertUserByCondition">
insert into userinfo (
username,
`password`,
age,
<if test="gender != null">
gender,
</if>
phone)
values (
#{username},
#{age},
<if test="gender != null">
#{gender},
</if>
#{phone})
</insert>
上述代码:如果gender不为空,则会将其拼接到SQL语句中(也就是我们在传参时,传了gender这个参数)
1.2 <trim>标签
<trim>标签的作用:添加或删除前缀和后缀
刚才我们只有一个选填字段,事实上可能有多个:
XML
<insert id="insertUserByCondition">
INSERT INTO userinfo
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username !=null">
username,
</if>
<if test="password !=null">
`password`,
</if>
<if test="age != null">
age,
</if>
<if test="gender != null">
gender,
</if>
<if test="phone != null">
phone,
</if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username !=null">
#{username},
</if>
<if test="password !=null">
#{password},
</if>
<if test="age != null">
#{age},
</if>
<if test="gender != null">
#{gender},
</if>
<if test="phone != null">
#{phone}
</if>
</trim>
</insert>
trim标签中:
- prefix:以prefix的值作为整个语句块的前缀
- suffix:以suffix的值作为整个语句块的后缀
- prefixOverrides:表示整个语句块要去除的前缀
- suffixOverrides:表示整个语句块要去除的后缀,在上述代码中最后拼接的字段可能结尾带有逗号,所以加上suffixOverrides
1.3 <where>标签
看下图,有时条件也需要动态拼接:
<where>标签的主要作用:动态拼接条件
XML
<select id="queryByCondition" resultType="com.example.demo.model.UserInfo">
select id, username, age, gender, phone, delete_flag, create_time, update_time from userinfo
<where>
<if test="age != null">
and age = #{age}
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="deleteFlag != null">
and delete_flag = #{deleteFlag}
</if>
</where>
</select>
<where>标签还有两个作用:
- 如果没有判断条件,where会自动去除
- 如果第一个条件有前缀and或or,<where>标签也会自动去除
1.4 <set>标签
<set>标签的作用:动态指定更新的内容
XML
<update id="updateUserByCondition">
update userinfo
<set>
<if test="username != null">
username = #{username},
</if>
<if test="age != null">
age = #{age},
</if>
<if test="deleteFlag != null">
delete_flag = #{deleteFlag},
</if>
</set>
where id = #{id}
</update>
<set>标签可以自动删除额外的逗号
1.5 <foreach>标签
<foreach>标签的作用:对集合进行遍历
批量删除:
java
Integer deleteByIds(List<Integer> ids);
XML
<delete id="deleteByIds">
delete from userinfo
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
- collection:绑定方法参数中的集合,也就是要遍历的集合
- item:遍历的每一个对象
- separator:每次遍历之间间隔的字符串
- open:整个语句块开头的字符串
- close:整个语句块结尾的字符串
1.6 <include>标签
在xml文件中配置的SQL有许多重复的片段
解决方法:将重复的sql片段提取出来放在<sql>标签,然后通过<include>标签复用
XML
<sql id="allColumn">
username, password, age, gender, phone
</sql>
XML
<select id="selectUserById" resultType="com.example.demo.model.UserInfo">
select
<include refid="allColumn"></include>
from userinfo where id = ${id}
</select>
🙉本篇文章到此结束