zoukankan      html  css  js  c++  java
  • MyBatis系列(四):MyBatis XML方式的基本用法之增删改

    1. insert用法

    1.1 简单的insert方法

    假如现在我们想新增一个用户,该如何操作呢?

    首先,在接口SysUserMapper中添加如下方法。

    /**
     * 新增用户
     *
     * @param sysUser
     * @return
     */
    int insert(SysUser sysUser);
    

    然后打开对应的SysUserMapper.xml文件,添加如下语句。

    <insert id="insert">
        INSERT INTO sys_user(id, user_name, user_password, user_email, user_info, head_img, create_time)
        VALUES (#{id},#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
    </insert>
    

    特别说明:

    1)为了防止类型错误,对于一些特殊的数据类型,建议指定具体的jdbcType值。例如headImg指定BLOB类型,createTime指定TIMESTAMP类型。

    2)BLOB对应的类型是ByteArrayInputStream,就是二进制数据流。

    3)由于数据库区分date、time、datetime类型,但是在Java中一般都使用java.util.Date类型。因此为了保证数据类型的正确,需要手动指定日期类型。date、time、datetime对应的JDBC类型分别为DATE、TIME、TIMESTAMP。

    在SysUserMapperTest测试类中添加如下代码,测试下insert()方法。

    @Test
    public void testInsert() {
        SqlSession sqlSession = getSqlSession();
    
        try {
            SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
    
            SysUser sysUser = new SysUser();
            sysUser.setUserName("test1");
            sysUser.setUserPassword("123456");
            sysUser.setUserEmail("test@mybatis.tk");
            sysUser.setUserInfo("test info");
            // 正常情况下应该读入一张图片保存到byte数组中
            sysUser.setHeadImg(new byte[]{1, 2, 3});
            sysUser.setCreateTime(new Date());
    
            // 这里的返回值result是执行的SQL影响的行数
            int result = sysUserMapper.insert(sysUser);
            // 只插入1条数据
            Assert.assertEquals(1, result);
            // id为null,没有给id赋值,并且没有配置回写id的值
            Assert.assertNull(sysUser.getId());
        } finally {
            // 为了不影响其他测试,这里选择回滚
            // 默认的sqlSessionFactory.openSession()是不自动提交的
            // 因此不手动执行commit也不会提交到数据库
            sqlSession.rollback();
            sqlSession.close();
        }
    }
    

    运行该测试方法,输出日志如下。

    DEBUG [main] - ==> Preparing: INSERT INTO sys_user(id, user_name, user_password, user_email, user_info, head_img, create_time) VALUES (?,?,?,?,?,?,?)

    DEBUG [main] - ==> Parameters: null, test1(String), 123456(String), test@mybatis.tk(String), test info(String), java.io.ByteArrayInputStream@544a2ea6(ByteArrayInputStream), 2019-07-02 13:09:07.822(Timestamp)

    DEBUG [main] - <== Updates: 1

    现在我们修改下createTime指定的jdbcType类型,直观的理解下jdbcType值的作用。

    createTime,jdbcType=DATE

    再次运行测试方法,日志中createTime字段的值如下。

    2019-07-02(Date)

    再次修改createTime指定的jdbcType类型为TIME。

    createTime,jdbcType=TIME

    再次运行测试方法,发现报如下错误:

    报错的原因是,数据库中的字段类型为datetime,但是这里只有time部分的值。

    通过上面的测试,说明数据库的datetime类型可以存储DATE(时间部分默认为00:00:00)和TIMESTAMP这两种类型的时间,不能存储TIME类型的时间。

    1.2 返回主键值(JDBC方式)

    在1.1的例子中,新增完数据,我们并没有拿到数据库中自增的id值,但有些场景中,我们需要先拿到数据库中自增的值,然后再处理其余的逻辑,那么如何拿到数据库中的自增的id值呢?

    首先,在接口SysUserMapper中添加方法如下。

    /**
     * 新增用户-使用useGeneratedKeys方式
     *
     * @param sysUser
     * @return
     */
    int insertUseGeneratedKeys(SysUser sysUser);
    

    然后打开对应的SysUserMapper.xml,添加如下代码。

    <insert id="insertUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time)
        VALUES (#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
    </insert>
    

    useGeneratedKeys设置为ture后,MyBatis会使用JDBC的getGeneratedKeys()方法来取出由数据库内部生成的主键。获取到主键后将其赋值给keyProperty配置的id属性。

    在SysUserMapperTest测试类中添加如下代码,测试新增的insertUseGeneratedKeys()方法。

    @Test
    public void testInsertUseGeneratedKeys() {
        SqlSession sqlSession = getSqlSession();
    
        try {
            SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
    
            SysUser sysUser = new SysUser();
            sysUser.setUserName("test1");
            sysUser.setUserPassword("123456");
            sysUser.setUserEmail("test@mybatis.tk");
            sysUser.setUserInfo("test info");
            // 正常情况下应该读入一张图片保存到byte数组中
            sysUser.setHeadImg(new byte[]{1, 2, 3});
            sysUser.setCreateTime(new Date());
    
            // 这里的返回值result是执行的SQL影响的行数
            int result = sysUserMapper.insertUseGeneratedKeys(sysUser);
            // 只插入1条数据
            Assert.assertEquals(1, result);
            // 因为id回写,所以id不为null
            Assert.assertNotNull(sysUser.getId());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }
    

    运行该测试方法,测试通过,输出日志如下。

    DEBUG [main] - ==> Preparing: INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time) VALUES (?,?,?,?,?,?)

    DEBUG [main] - ==> Parameters: test1(String), 123456(String), test@mybatis.tk(String), test info(String), java.io.ByteArrayInputStream@544a2ea6(ByteArrayInputStream), 2019-07-02 14:02:22.506(Timestamp)

    DEBUG [main] - <== Updates: 1

    1.3 返回主键值(selectKey方式)

    1.2中回写主键的方法只适用于支持主键自增的数据库。

    但有些数据库(比如Oracle)不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给id,再将数据插入到数据库。

    对于这种情况,就可以采用selectKey方式,因为selectKey方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。

    我们先来看下MySql的例子。

    首先,在接口SysUserMapper中添加如下方法。

    /**
     * 新增用户-使用selectKey方式
     *
     * @param sysUser
     * @return
     */
    int insertUseSelectKey(SysUser sysUser);
    

    然后打开对应的SysUserMapper.xml文件,添加如下代码。

    <insert id="insertUseSelectKey">
        INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time)
        VALUES (#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
        <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
    </insert>
    

    和1.2相比,这里的语句多了selectKey标签,其中:

    • keyColumn:主键的数据库列名。
    • resultType:返回值类型。
    • keyProperty:主键对应的属性名。
    • order:该属性的设置和使用的数据库有关,如果使用的是MySql数据库,设置的值是AFTER,因为当前记录的主键值在insert语句执行成功后才能获取到。如果使用的是Oracle数据库,设置的值是BEFORE,因为Oracle中需要先从序列获取值,然后将值作为主键插入到数据库中。

    如果数据库是Oracle的话,语句如下(因为环境问题,以下代码我并未验证,有兴趣的同学可以自己试下)。

    <insert id="insertUseSelectKey">
        <selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE">
            SELECT SEQ_ID.nextval from dual
        </selectKey>
        INSERT INTO sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time)
        VALUES (#{id},#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
    </insert>
    

    2. update用法

    假如我们现在希望通过主键id来更新用户信息,该如何操作呢?

    首先,在接口SysUserMapper中添加如下方法。

    /**
     * 根据主键更新
     *
     * @param sysUser
     * @return
     */
    int updateById(SysUser sysUser);
    

    然后,打开对应的SysUserMapper.xml文件,添加如下代码。

    <update id="updateById">
        UPDATE sys_user
        SET user_name = #{userName},
            user_password = #{userPassword},
            user_email = #{userEmail},
            user_info = #{userInfo},
            head_img = #{headImg,jdbcType=BLOB},
            create_time = #{createTime,jdbcType=TIMESTAMP}
        WHERE id = #{id}
    </update>
    

    最后在SysUserMapperTest测试类中,添加如下测试方法。

    @Test
    public void testUpdateById() {
        SqlSession sqlSession = getSqlSession();
    
        try {
            SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
            SysUser sysUser = sysUserMapper.selectById(1L);
    
            Assert.assertEquals("admin", sysUser.getUserName());
    
            sysUser.setUserName("admin_test");
            sysUser.setUserEmail("admin_test@mybatis.tk");
            sysUser.setUserInfo("test info");
            // 正常情况下应该读入一张图片保存到byte数组中
            sysUser.setHeadImg(new byte[]{1, 2, 3});
            sysUser.setCreateTime(new Date());
    
            // 这里的返回值result是执行的SQL影响的行数
            int result = sysUserMapper.updateById(sysUser);
            // 只更新1条数据
            Assert.assertEquals(1, result);
    
            sysUser = sysUserMapper.selectById(1L);
            Assert.assertEquals("admin_test", sysUser.getUserName());
            Assert.assertEquals("admin_test@mybatis.tk", sysUser.getUserEmail());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }
    

    运行测试方法,测试通过,输出的部分日志如下。

    DEBUG [main] - ==> Preparing: UPDATE sys_user SET user_name = ?, user_password = ?, user_email = ?, user_info = ?, head_img = ?, create_time = ? WHERE id = ?

    DEBUG [main] - ==> Parameters: admin_test(String), 123456(String), admin_test@mybatis.tk(String), test info(String), java.io.ByteArrayInputStream@78186a70(ByteArrayInputStream), 2019-07-02 14:57:34.792(Timestamp), 1(Long)

    DEBUG [main] - <== Updates: 1

    3. delete用法

    假如我们现在希望通过主键id来删除用户信息,该如何操作呢?

    首先,在接口SysUserMapper中添加如下方法。

    /**
    * 根据主键删除
    *
    * @param id
    * @return
    */
    int deleteById(Long id);
    
    /**
    * 根据对象的主键删除
    *
    * @param sysUser
    * @return
    */
    int deleteBySysUser(SysUser sysUser);
    

    然后,打开对应的SysUserMapper.xml文件,添加如下代码。

    <delete id="deleteById">
        DELETE FROM sys_user WHERE id = #{id}
    </delete>
    <delete id="deleteBySysUser">
        DELETE FROM sys_user WHERE id = #{id}
    </delete>
    

    最后在SysUserMapperTest测试类中,添加如下测试方法。

    @Test
    public void testDeleteById() {
        SqlSession sqlSession = getSqlSession();
    
        try {
            SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
            SysUser sysUser = sysUserMapper.selectById(1L);
            Assert.assertNotNull(sysUser);
    
            // 这里是直接根据id删除
            int result = sysUserMapper.deleteById(1L);
            // 只删除1条数据
            Assert.assertEquals(1, result);
    
            Assert.assertNull(sysUserMapper.selectById(1L));
    
            SysUser sysUser2 = sysUserMapper.selectById(1001L);
            Assert.assertNotNull(sysUser2);
    
            // 这里是根据对象的id属性删除
            Assert.assertEquals(1, sysUserMapper.deleteBySysUser(sysUser2));
    
            Assert.assertNull(sysUserMapper.selectById(1001L));
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }
    

    运行测试方法,测试通过,输出的部分日志如下。

    DEBUG [main] - ==> Preparing: DELETE FROM sys_user WHERE id = ?

    DEBUG [main] - ==> Parameters: 1(Long)

    DEBUG [main] - <== Updates: 1

    4. 源码及参考

    源码地址:https://github.com/zwwhnly/mybatis-action.git,欢迎下载。

    刘增辉《MyBatis从入门到精通》

    原创不易,如果觉得文章能学到东西的话,欢迎点个赞、评个论、关个注,这是我坚持写作的最大动力。

    如果有兴趣,欢迎添加我的微信:zwwhnly,等你来聊技术、职场、工作等话题(PS:我是一名奋斗在上海的程序员)。

  • 相关阅读:
    Myeclipse 10.7 android(安卓) 开发环境搭建
    matplotlib
    tophat cufflinks cuffcompare cuffmerge 的使用
    shell 随机从文件中抽取若干行
    liftover的使用/用法
    命令行运行R语言脚本(代码)
    R: NULL, NA, and NaN
    SOME USEFUL MACHINE LEARNING LIBRARIES.
    Flutter实战:手把手教你写Flutter Plugin
    Flutter学习笔记(五)
  • 原文地址:https://www.cnblogs.com/zwwhnly/p/11130649.html
Copyright © 2011-2022 走看看