7、JavaWeb-Mybatis基础操作

P123 Mybatis-基础操作-删除

点击删除,前端传入选中内容的唯一标识,即主键ID,然后后端根据主键进行删除。

delete from emp where id = 17

假设还是使用注解执行SQL语句,则有:

@Mapper
public interface EmpMapper {
    // 根据id删除数据
    @Delete("delete from emp where id = 17")
    public void delete();

}

如何将需要删除的id动态的传递到sql语句中呢?

可以在调用mapper接口方法的时候传递参数,mybatis中提供的占位符为#{},如果mapper接口方法形参只有一个普通类型的参数,#{}里面的属性名可以随便写

进行单元测试:


    // 声明mapper
    @Autowired
    private EmpMapper empMapper; // 使用bean

    @Test
    public void testDelete(){
        empMapper.delete(17);
        System.out.println("删除成功");
    }

运行单元测试,可以成功删除。

注意Delete操作有返回值,返回影响的记录数,其余增加修改也是。

P124 Mybatis-基础操作-删除(预编译SQL)

可以在application.properties中打开mybatis的日志,并指定输出到控制台。

#配置mybatis的日志信息,指定输出到控制台,通过关键字联想
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

再执行单元测试,可以看到日志中:

在这里插入图片描述

上图中所示的SQL语句称为预编译SQL,

优势

  • 性能更高

  • 更安全,防止SQL注入

下面图理解预编译SQL优势,性能更高
在这里插入图片描述

SQL注入:通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

例如用户登录输账号密码,则在数据库执行查找的sql语句为:

select count(*) from emp where username = ' ' and password = ' ',直接将输入的账号和密码拼接在sql语句当中,
在这里插入图片描述

sql注入则类似下图所示,账号随便写,然后密码写'or'1'='1

在这里插入图片描述

这样的sql语句造成的情况就是1=1永远是True的,所以用户可以登录成功。

所以解决SQL注入就不能通过这种直接拼接的形式,而是采用预编译的形式,使用java -jar 名称运行jar包。采用预编译是使用?进行占位的,这样就避免了sql注入问题。

在这里插入图片描述

使用Mybatis框架,怎么选择我们采用sql预编译的操作呢?使用#{}的占位符,生成的就是预编译sql语句。

参数占位符:

  • #{},执行sql的时候会将其替换为?,生成预编译SQL,会自动设置参数值,使用场景:参数传递都是用#{}

  • ${},拼接SQL,直接将参数拼接在SQL语句中,存在SQL注入问题,使用场景:如果对表名、列表进行动态设置时使用。

P125 Mybatis-基础操作-新增

插入的sql示例:insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) value('Tom', '汤姆', 1, '1.jpg', 1, '2005-10-01', 1, now(), now())

在参数传递中,多个参数推荐直接封装到对象当中,调用insert方法只需要传递一个对象即可,

所以mapper中Insert如下所示:用的?占位,避免了sql注入,

 // 新增员工的操作
    @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) value(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
    public Integer insert(Emp emp);

然后进行单元测试,

  // 新增员工测试
    @Test
    public void testInsert(){
        // 构建员工对象
        Emp emp = new Emp();
        emp.setUsername("Joke");
        emp.setName("爵克");
        emp.setImage("1.jpg");
        emp.setGender(1);
        emp.setJob((short)1);
        emp.setEntryDate(LocalDate.of(2000, 12, 21));
        emp.setDeptId(1);
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());

        Integer num = empMapper.insert(emp);
        System.out.println("新增成功: " + num);
    }

P126 Mybatis-基础操作-新增(主键返回)

主键返回:意思就是在数据添加成功后,需要获取插入数据库数据的主键,例如添加套餐数据时,还要维护套餐菜品关系表结构。

如果执行insert操作后,获取主键,返回为null,说明没有拿到

 Integer num = empMapper.insert(emp);

 // 保存后尝试获取保存的主键值
 System.out.println(emp.getId());

如果要拿到主键值,可以再在insert方法上加上一个注解@options(keyProperty="id", useGeneratedKeys=true)useGeneratedKeys为true代表需要拿到生成的主键值,keyProperty="id"代表最终获取主键会封装到id中。

然后进行单元测试,可以获取到返回的主键值。

P127 Mybatis-基础操作-更新

编辑操作:先查询某条数据,用于页面回显展示,然后编辑数据更新数据库

一般都是根据主键修改员工信息。

mapper部分:

  // 更新操作
    @Update("update emp set username= #{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entryDate}, dept_id=#{deptId},update_time=#{updateTime} where id = #{id}")
    public Integer update(Emp emp);

进行测试可以实现更新操作。

P128 Mybatis-基础操作-查询(根据id查询)

同样的原理即可。

数据封装:

  • 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装

  • 如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装

例如执行Emp emp = empMapper.getById(21);这个操作后字段名和实体类属性名不一致则不能自动封装,所以进行解决:

  • 方法一:为字段名起别名,例如select dept_id deptId

  • 方法二:通过@Result注解手动映射封装,column是数据库字段名,property是类中的属性名,

// 方式二:result注解
    @Results({
            @Result(column = "dept_id", property = "deptId"),
            @Result(column = "create_time", property = "createTime"),
            @Result(column = "update_time", property = "updateTime")
    })
    @Select("select * from emp where id = #{id}")
    public Emp getById(Integer id);
  • (推荐)方法三:开启mybatis的驼峰命名自动映射开关,在properties中进行配置,

# mybatis驼峰命名映射 mybatis.configuration.map-underscore-to-camel-case=true

使用第三方法,应该遵守数据表中字段名是_分隔的,类中属性名是驼峰命名的,才能自动映射

P129 Mybatis-基础操作-查询(条件查询)

按条件查询,支持模糊查询,则sql语句可以是:注意模糊匹配使用%%

 // 条件查询员工信息,多条员工信息需要进行封装
    @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, Integer gender, LocalDate begin, LocalDate end);

而模糊匹配那里由于?不能在引号内,使用了${},但是这样会有sql注入的影响,因此解决办法是使用concat方法进行拼接,就变为了like concat('%', #{},'%')

P130 Mybatis-XML映射文件

回顾mybatis配置sql语句的两种方式

  • 注解

  • xml

xml映射文件的名称:

  • xml映射文件的名称要与mapper接口名称一致,并且将xml映射文件和mapper接口放置在相同包下面
    在这里插入图片描述

  • Xml映射文件的namespace属性为mapper接口全类名一致

  • xml映射文件中sql语句的id与mapper接口中的方法名一致,并保持返回类型一致。

在这里插入图片描述

在resource中创建包结构,要按照目录层级进行创建,com/it/heima。

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.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

根标签mapper,mapper标签有一个唯一的属性namespace,需要与mapper接口的全类名保持一致,获取全类名,在接口类名中选择copy reference即可。

在这里插入图片描述

然后在映射文件中定义sql语句,而在mapper中就可以只定义方法,可以不用注解了。

注意sql的id与方法名一致。

resultType为单条记录所封装的类型。

现在理解一下调用mapper的方法是怎么实现sql的,实际上就是依据与当前mapper相同的xml文件,然后又找到与当前方法相同的sql的id,然后就可以执行sql语句了,完成了功能。

插件:mybatisx,提高mybatis的开发效率,安装成功后可以看到,empmapper和对应的xml文件都有了小鸟一样,可以实现两者的快速定位。

最后,简单一点的使用注解映射会使代码简洁,但是复杂一点的操作,建议使用XML映射。

P131 Mybatis-动态SQL-if

动态SQL:随着用户的输入或外部条件的变化而变化的SQL语句

例如多条件查询,有些条件不传入有些条件传入,这个时候就不能把sql写死了,需要动态sql

更改后的xml内容:其中里面写的是sql语句,使用了判断条件,条件符合则将其拼接到sql语句中,反之则不。

  <select id="list" resultType="com.hongdou.entity.Emp">
        select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time 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>
    </select>

注意test里面的判断的是类属性名,#{}中也是类属性名

动态sql中又提供了一个标签,替代sql语句中的where关键字。

使用将所有的查询包裹起来,有两个作用:

  • 根据里面的指标动态判断条件,如果都不成立则不会生成where

  • 会自动去除掉条件前面多余的and 或者or,避免了where and gender = 1的情况发生。

P132 Mybatis-动态SQL-if-案例

分析:采用之前的注解来更新某一条信息,则下面写的固定的字段每一次都要进行更新,如果有些字段没有传入更新的值则会被更新为null。

@Update("update emp set username= #{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entryDate}, dept_id=#{deptId},update_time=#{updateTime} where id = #{id}")
    public Integer update(Emp emp);

因此动态传递更新,即更新时传递有值,则动态更新,没有值则不更新,用到动态SQL。

例如mapper中定义了方法update2,点击alt+enter,选择generate statement回车,就可以在xml中直接生成了标签。

在update语句中使用标签可以将所有字段进行包裹,同时也会去除掉sql中多余的逗号。

 <!--    完成动态更新操作-->
    <update id="update2">

        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>
        </set>
        where id = #{id}
    </update>

P133 Mybatis-动态SQL-foreach

假设是批量删除的操作,则sql语句为:delete from emp where id in(18,19,20);

先在mapper中定义批量删除方法,可用集合存储批量删除的ids,如下所示:

public void deleteByIds(List<Integer> ids);

而在xml中需要遍历集合中的id,然后进行拼接,

介绍一下标签循环遍历操作,其中常见属性:

  • collection:要遍历的集合

  • item:遍历的元素

  • separator:分隔符

  • open:遍历开始前拼接的sql片段

  • close:遍历结束后拼接的sql片段

示例:

    <!--    完成批量删除信息的sql, 例如集合id in (18,19,20),所以分隔符是,-->
    <delete id="deleteByIds">
        delete from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

删除的单元测试如下所示:

  // 批量删除的测试类
    @Test
    public void testDeleteByIds(){
        List<Integer> ids = Arrays.asList(13, 14, 15);
        empMapper.deleteByIds(ids);
        
    }

P134 Mybatis-动态SQL-sql&include

使用select * 性能比较低并不推荐。假设是下面的两个查询,查询的字段都是相同的,如果多个这种情况,怎么提高代码的复用性呢?
在这里插入图片描述

标签,可以抽取出查询字段并定义一个唯一标识id属性,则可以将这个片段引入进来。

例如:

 <sql id="commonSelect">
        select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
    </sql>


// 在使用的地点
<include refid="commonSelect"></include>
  • 44
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值