使用Mybatis时需要注意的小细节

1. Mapper.xml与Mapper接口中返回值的对应关系

  • 在Mapper.xml文件中,虽然这条sql语句查询出来的结果可能会有多条,但是这里的resuleType依然写Student就行,不用写List
<select id="findStudentByUsername" parameterType="String" resultType="cn.ykf.domain.Student">
    SELECT * FROM student WHERE username LIKE #{key};
</select>
  • 在不使用Mapper接口的情况下,应该使用selectList()方法,该方法会自动将查询的多条记录封装成对应类型的List集合
List<Student> students = sqlSession.selectList("test.findStudentByUsername", "%测试%");
  • 如果使用Mapper接口,那么在Mapper接口中应该这样定义对应的方法,这里的返回值应该定义为List,那么调用的时候就会返回一个封装了多条Student的集合
/**
 * 根据用户名模糊查询
 *
 * @param key 用户名模糊查询关键字
 * @return 全部符合条件的Student集合
 */
List<Student> findStudentByUsername(String key);
  • 如果像上面那个定义sql语句的话,调用的时候应该是这样的。就是说传参的时候需要自己在参数前后加上’%'
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.findStudentByUsername("%测试%");
  • 如果想传参的时候只传入关键字,那么就可以将sql语句修改为
<select id="findStudentByUsername" parameterType="String" resultType="cn.ykf.domain.Student">
	SELECT * FROM student WHERE username LIKE "%"#{key}"%";
</select>

或者

<select id="findStudentByUsername" parameterType="String" resultType="cn.ykf.domain.Student">
    SELECT * FROM student WHERE username LIKE '%${value}%';
</select>
  • 推荐第一种方案,因为第二种方案的 . . . s q l S t r i n g {...}存在sql注入问题,而且由于传入参数类型为String,所以只能写 {value},不能乱写,否则会报错在这里插入图片描述

    • 还有,使用第一种方案的时候,参数应该写 “%”#{key}"%"。就是 %两侧需要加上双引号,不能单引号。因为#{…}解析成sql语句时候,会在变量外侧自动加单引号,所以这里 % 需要使用双引号,不能使用单引号,不然会查不到任何结果
    • 第一种方案sql的参数名称可以随便写
  • 参考资料

2. 关于增删查改的返回值

  • 只有查询<select></select>标签才有resultType属性,其他增删改<insert></insert>、<delete></delete>、<update></update>都没有resultType属性,默认返回影响条数,int类型

3. 关于修改数据时的坑

3.1. 修改时参数为NULL覆盖了原本存在的字段值

  • 首先在Mapper.xml中定义的修改sql语句如下,该sql语句会修改记录中除去id的所有字段值
<update id="updateStudent" parameterType="cn.ykf.domain.Student">
    UPDATE student SET username = #{username}, password = #{password}, birthday = #{birthday}, chinese = #{chinese}, math = #{math}, english = #{english} WHERE id = #{id}
</update>
  • 然后有以下测试代码,其中创建一个id为5,只有username和password属性不为空的Student对象,然后使用该对象作为参数进行修改
@Test
public void testUpdateStudent() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    // 测试数据,如果对象只有一个属性被赋值,那么写入数据库后,数据库中原本有值的字段是否会变成NULL?
    Student stu = new Student();
    stu.setId(5);
    stu.setUsername("test");
    stu.setPassword("test");

    int flag = mapper.updateStudent(stu);
    // 提交事务
    sqlSession.commit();
    System.out.println(flag);

    // 释放资源
    MybatisUtils.close(sqlSession);
}
  • 查看日志,传入方法的参数中含有NULL
    • 在这里插入图片描述
  • 原本的数据库中id为5的记录如下图
    • 在这里插入图片描述
  • 修改结束后,该记录变为
    -在这里插入图片描述
  • 结论
    • 在修改数据时,如果sql语句修改了多个字段,那么应该要小心传入参数中某个属性为NULL,避免将数据库中某条记录原本存在的值更改为NULL

3.2. 传入不存在的id值

  • 如果将上面代码中的测试数据的id改为一个数据库中不存在的值,比如stu.setId(1000);,那么会发生什么?
  • 经过测试发现,如果传入一个不存在的id值,那么在数据库中找不到对应的记录存在,就不会发生修改,因此不会对数据库中的数据造成影响
    • 在这里插入图片描述

3.3. 修改/删除/插入记录时调用错方法

  • 假如我们想要更新某一条记录,在Mapper.xml文件中定义的sql语句是正确的,但是在代码中,我们不小心调用错了方法,会发生什么?比如下列代码
<mapper namespace="test">
    <!-- 修改 -->
    <update id="updateStudent" parameterType="cn.ykf.domain.Student">
        UPDATE student SET username = #{username}, password = #{password}, birthday = #{birthday}, chinese = #{chinese}, math = #{math}, english = #{english} WHERE id = #{id}
    </update>
</mapper>
@Test
    public void testUpdateStudent() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        Student stu = new Student();
        stu.setId(5);
        stu.setUsername("test");
        stu.setPassword("test");

        // 比如在这里想要修改数据,结果调用了delete()或者insert()
        int flag = sqlSession.delete("test.updateStudent", stu);
        // 提交事务
        sqlSession.commit();
        System.out.println(flag);

        // 释放资源
        MybatisUtils.close(sqlSession);
    }
  • 在上面代码中,我们想要修改id为5的记录,本来应该使用update(),但是由于我们手误,不小心使用了delete()或者insert()。点击运行后,我们很惊奇地发现,程序没有报错,而且查看数据库后发现,数据修改成功了。为什么?
  • 修改前在这里插入图片描述
  • 修改后在这里插入图片描述
  • 分析
    • 查看Mybatis源码中的org.apache.ibatis.session.defaults.DefaultSqlSession在这里插入图片描述
    • 发现里面有这么一段代码,其中的insert()和delete()方法最后都是调用了update()。所以虽然我们在代码中调用了delete()/insert()来进行update操作,但是最后Mybatis都是使用update()来更新数据的,所以并不影响
    public int insert(String statement) {
      return insert(statement, null);
    }
    
    public int insert(String statement, Object parameter) {
      return update(statement, parameter);
    }
    
    public int update(String statement) {
      return update(statement, null);
    }
    
    public int update(String statement, Object parameter) {
      try {
        dirty = true;
        MappedStatement ms = configuration.getMappedStatement(statement);
        return executor.update(ms, wrapCollection(parameter));
      } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
      } finally {
        ErrorContext.instance().reset();
      }
    }
    
    public int delete(String statement) {
      return update(statement, null);
    }
    
    public int delete(String statement, Object parameter) {
      return update(statement, parameter);
    }
    
  • 参考资料
发布了4 篇原创文章 · 获赞 2 · 访问量 128

猜你喜欢

转载自blog.csdn.net/a1092882580/article/details/103486201