增删查改
增删查改算是十分重要且基础的部分,这里来跟着文档来实现一下如何进行增删改查。
Mybatis连接数据库
需要我们在application.properties下配置好对应的内容
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 | #驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisEmp
# 数据库用户名称
spring.datasource.username=root
# 登录密码
spring.datasource.password=123456
 | 
 
删除
在Mapper层实现删除的接口,对于删除语句来说,其选择的注释就是@Delete,其中编写对应的删除语句即可。我们需要实现一个根据ID来删除的一个操作。
参数传递
在Mapper层中我们可以编写EmpMapper接口,其中,为了更加灵活,我们可以根据传进来的ID来实现删除逻辑
| 1
2
3
4
5
6
 | @Mapper
public interface EmpMapper {
    // 删除
    @Delete("DELETE from emp where id = #{id}")
    public int deleteEmpById(Integer id);
}
 | 
 
使用Mapper注释可以将后续实例化的对象通过容器进行管理,后续我们只需要使用AutoWired注释即可。可以在test文件下进行测试。在测试时,每个测试都要写成一个函数,并且要加上@Test注释。
| 1
2
3
4
5
 | @Test
public void deleteByPrimaryKey() {
    int i = empMapper.deleteEmpById(17);
    System.out.println("Return Val Of Delete is " + i);
}
 | 
 
sql注入问题
当使用拼接sql语句去进行某些验证业务时,精心构造的参数会跳过验证,从而起到sql注入攻击的效果。假设我们使用的是sql拼接的方式进行验证,例如,我们要做登录验证。
一般,数据库会存储用户名和加密后的密码(应该不是明文密码),当我们进行登录是时,假设是在进行查询操作。
| 1
 | select count(*) where userName = 'xxx' and password = 'xxx';
 | 
 
当使用拼接sql时,我们可以构造出来count(*)永远大于0的操作,即password在传递时为' or '1' = '1,这样,拼接后的sql语句就是
| 1
 | select count(*) from emp where userName = 'xxx' and password = '' or '1' = '1';
 | 
 
而1 = 1永远成立,所以这条sql相当于
| 1
 | select count(*) from emp;
 | 
 
sql预编译
解决sql注入可以通过预编译的方式去避免。在预编译时,传递的关键参数都是利用占位符去占用,例如上面这条sql语句就会变为
| 1
 | select count(*) from emp where userName = ? and password = ?;
 | 
 
当有参数传递时,就会将?替换为对应的参数,从而避免了sql拼接的问题。在上面传递参数的sql语句中,一共有两种传递参数的办法
这两种方式都可以起到参数传递的作用,不过#{id}的方式是预编译sql,可以解决sql注入的问题。
插入数据
在mysql中,插入数据的sql语句一般是
| 1
 | insert into xxx(字段名) values (xxxx);
 | 
 
使用的注解也是@Insert,当插入的值过多,就可以把这些值封装到一个对象里面,把需要插入的参数使用#{xx}的方式插入即可,这样可以防止sql注入,同时预编译还可以提高查询效率。
当需要进行模糊搜索时,一般会用到通配符搜索,在使用通配符的时候,有些通配符符号是无法通过#{xx}的形式去拼接的,例如,我想要搜索所有包含张的姓名
| 1
 | select name from user where name like '%张%';
 | 
 
那么在传递参数的时候,需要把%也传递进去,就像下面一样
| 1
2
3
4
5
6
7
8
9
 | @Mapper
public interface EmpMapper {
    @Select("select * from emp " +
            "where name like '%${name}%' " +
            "and gender = #{gender} " +
            "and entrydate between #{begin} and #{end} " +
            "order by update_time desc")
    public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
 | 
 
如果要使用占位参数来编写sql,那么这个句子就变成了
| 1
 | select name from user where name like '%?%'
 | 
 
这样就会出现编译错误,而使用直接拼接的${}话,又会引发sql注入问题,所以可以使用sql的库函数即concat函数来拼接。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 | @Mapper
public interface EmpMapper {
    @Select("select * from emp " +
            "where name like concat('%',#{name},'%') " +
            "and gender = #{gender} " +
            "and entrydate between #{begin} and #{end} " +
            "order by update_time desc")
    public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
 | 
 
这样也可以实现预编译,把中间的#{name}替换掉,在预编译后就变成了
| 1
 | select name from user where name like concat('%', ?, '%');
 | 
 
XML编写
可以直接把用到的sql语句写到XML文件里面,这样当sql语句开始变得复杂的时候,就可以方便的管理一些sql语句,从而避免将sql语句直接写在java代码里面。
书写规范
其书写格式一般是
| 1
2
3
 | <mapper namespace="xxx.xxx.xxx">
</mapper>
 | 
 
不同的sql语句之间标签不一致,查询语句需要用<select>标签包裹,同理的,例如<insert>、<delete>、<update>
同时,还需要在这些标签中注明方法名和方法的返回值,假设我们要查询
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 | <mapper namespace="com.itheima.mapper.EmpMapper">
    <!--查询操作-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        where name like concat('%',#{name},'%')
              and gender = #{gender}
              and entrydate between #{begin} and #{end}
        order by update_time desc
    </select>
</mapper>
 | 
 
其中id="list"说明这个查询函数的函数名为list,resultType=xxx说明其返回值类型是xxx,然后在标签中间编写sql语句即可。
需要注意,可以直接把简单的sql以注解的形式写道java代码里面,也可以写到xml文件里面。越短越简单的sql语句可以写到java代码里面。
更新数据
同样的,我们可以使用insert来向表里面插入某些数据,也可以使用update来更新一些数据,如果我们不指定所有的字段,那么未指定的字段将会被设置为null,但是这并不是我们希望看到的,有时候只需要修改一两条信息,其它的信息不用做出修改,这个时候我们就可以使用动态sql来避免传递空子段。
动态SQL
动态SQL是指前端传递过来的参数个数是不确定的,这就要求我们不可以将sql语句写死,而是根据传递结果来确定sql语句的书写,这里就用到了if标签。
语法
| 1
2
3
 | <if test="判断语句">
</if>
 | 
 
例如,之前的一条查询语句为
| 1
2
3
4
5
6
7
 | <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        where name like concat('%',#{name},'%')
              and gender = #{gender}
              and entrydate between #{begin} and #{end}
        order by update_time desc
</select>
 | 
 
我们就可以根据name gender entrydate这些字段是否为空来进行查询判断
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 | <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        where
        <if test="name != null">
            name like concat('%',#{name},'%')
        </if>
        <if test="gender != null">
            and gender = #{gender}
        </if>
        <if test="begin!= null and end != null">
        and entrydate between #{begin} and #{end}
        </if>  
        order by update_time desc
</select>
 | 
 
当某些字段为空时,即未通过test测试,那么就不会查询该字段。
问题
但是这样就又会引发一些问题,当name字段为空时,这段SQL语句会变成
| 1
2
3
4
5
6
7
 | <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        where
        and gender = #{gender}
        and entrydate between #{begin} and #{end}
        order by update_time desc
</select>
 | 
 
可以发现,,where后面多跟了一个and导致我们的语法发生了错误,当然也有解决办法,就是去使用<where>标签
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 | <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        <where>
             <!-- if做为where标签的子元素 -->
             <if test="name != null">
                 and name like concat('%',#{name},'%')
             </if>
             <if test="gender != null">
                 and gender = #{gender}
             </if>
             <if test="begin != null and end != null">
                 and entrydate between #{begin} and #{end}
             </if>
        </where>
        order by update_time desc
</select>
 | 
 
更新某些数据
同样的,只有在前端传递管来的值不为null时才对里面的值进行修改
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 | <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--更新操作-->
    <update id="update">
        update emp
        set
            <if test="username != null">
                username=#{username},
            </if>
            <if test="name != null">
                name=#{name},
            </if>
            <if test="gender != null">
                gender=#{gender},
            </if>
            <if test="image != null">
                image=#{image},
            </if>
            <if test="job != null">
                job=#{job},
            </if>
            <if test="entrydate != null">
                entrydate=#{entrydate},
            </if>
            <if test="deptId != null">
                dept_id=#{deptId},
            </if>
            <if test="updateTime != null">
                update_time=#{updateTime}
            </if>
        where id=#{id}
    </update>
</mapper>
 | 
 
可是这样做又会引起sql语句的语法错误,例如当只存在第一个字段而不存在后面那些字段时,下面的语句就是
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 | <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--更新操作-->
    <update id="update">
        update emp
        set
            username=#{username},
        where id=#{id}
    </update>
</mapper>
 | 
 
也就是后面多加了一个逗号,同样的,我们也可以使用<set>标签来修改
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 | <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--更新操作-->
    <update id="update">
        update emp
        <!-- 使用set标签,代替update语句中的set关键字 -->
        <set>
            <if test="username != null">
                username=#{username},
            </if>
            <if test="name != null">
                name=#{name},
            </if>
            <if test="gender != null">
                gender=#{gender},
            </if>
            <if test="image != null">
                image=#{image},
            </if>
            <if test="job != null">
                job=#{job},
            </if>
            <if test="entrydate != null">
                entrydate=#{entrydate},
            </if>
            <if test="deptId != null">
                dept_id=#{deptId},
            </if>
            <if test="updateTime != null">
                update_time=#{updateTime}
            </if>
        </set>
        where id=#{id}
    </update>
</mapper>
 | 
 
sql引用
对于一些重复的sql片段,我们可以使用片段包裹的方式来进行引入
| 1
2
3
4
5
 | <sql id="name">
    select
    name, age, gender
    from user
</sql>
 | 
 
这个时候,如果想要引用上面这个sql语句,就可以使用include标签来进行引用
| 1
2
3
 | <include refid="name">
	where id = 1
</include>
 | 
 
这样就可以把重复的语句选出来。
总结
这就是Mybatis连接数据库的所有操作,加油~