MyBatis入门-insert标签介绍及使用

insert用法

本篇介绍了

  • insert标签属性及作用
  • 属性列#{xxx,jdbcType=nnnn}中jdbcType的作用
  • 实现主键自增的两种方式

介绍-insert标签

insert标签包含的属性:

  • id:命名空间中的唯一标识符,可用来代表这条语句
  • parameterType:即将传入语句参数的完全限定类别或别名。因为MyBatis可以推断出传入语句的具体参数,因此不建议配置
  • flushCache:默认值为true,任何时候只要语句被调用,都会清空一级缓存和二级缓存
  • timeout:设置在抛出异常之前,驱动程序等待数据库返回请求结果的秒数
  • statementType:对于STATEMENT、PREPARED、CALLABLE,MyBatis会分别使用对应得Statement、PreparedStatement、CallableStatement,默认值为PREPARED
  • useGeneratedKeys:默认值为false。如果设置为true,MyBatis会使用JDBC的getGeneratedKeys方法取出由数据库内部生成的主键
  • keyProperty:MyBatis会使用JDBC的getGeneratedKeys方法获取主键值后将要赋值的属性名。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表
  • keyColumn:仅对INSERT和UPDATE有用。通过生成的键值设置表中的列名,这个设置仅在某些数据库(如PostgreSQL)中是必须的,当主键列不是表中的第一列时需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
  • databaseId:如果配置了databaseIdProvider,MyBatis会加载所有的不带databaseId的或匹配当前databaseId的语句。如果同时存在带databaseId和不带databaseId的语句,后者会被忽略

提示:为了防止类型错误,例如BLOB类型或者TIMESTAMP类型建议指定具体的jdbcType值。

BLOB对应的类型是ByteArrayInputStream二进制数据流。

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

实践-插入一条记录

mapper中接口

/**
     * 插入用户
     * @param user 用户
     * @return 执行的SQL影响的行数
     */
    int insert(SysUser user);

xml中添加如下的sql

    <!--新增所有列-->
    <insert id="insert">
        insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time)
        values (#{id},#{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg}, #{createTime})
    </insert>

测试方法

@Test
    public void testInsert(){
        SqlSession sqlSession = getSqlSession();

        try {
            // 初始化一个sysUser对象
            SysUser sysUser = new SysUser();
            sysUser.setUserName("test1");
            sysUser.setUserPassword("123456");
            sysUser.setUserEmail("test@mybatis.tk");
            sysUser.setUserInfo("test info");
            sysUser.setHeadImg(new byte[]{1,2,3});
            sysUser.setCreateTime(new Date());

            SysUserMapper mapper = sqlSession.getMapper(SysUserMapper.class);
            //将新建的对象插入数据库中,这里的返回值是执行的SQL影响的行数
            int insert = mapper.insert(sysUser);
            //只插入一条记录
            Assert.assertEquals(1,insert);
            LOGGER.info("插入的记录:{}",sysUser.toString());
        } finally {
            //由于默认的sqlSessionFactory.openSession()是不自动提交的,因此不手动执行commit也不会提交到数据库
            sqlSession.rollback();
            //关闭sqlSession
            sqlSession.close();
        }

    }

执行结果:

==>  Preparing: insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time) values (?,?, ?, ?, ?, ?, ?) 
==> Parameters: null, test1(String), 123456(String), test@mybatis.tk(String), test info(String), [B@3b7d3a38(byte[]), 2021-03-17 21:40:22.772(Timestamp)
<==    Updates: 1
插入的记录:SysUser{id=null, userName='test1', userPassword='123456', userEmail='test@mybatis.tk', userInfo='test info', headImg=[1, 2, 3], createTime=Wed Mar 17 21:40:22 CST 2021}
  1. 我们不给对象的主键字段值,构造插入语句时插入的是null。

  2. insert的结果是1

  3. 日期的格式是2021-03-17 21:40:22.772(Timestamp)

实践-jdbcType值的作用

1.修改上面的insert语句,给createTime指定jdbcType

 #{createTime,jdbcType=DATE})

执行上面的测试方法,结果如下,能发现create_time字段插入的值变为了2021-03-17(Date)

==>  Preparing: insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time) values (?,?, ?, ?, ?, ?, ?) 
==> Parameters: null, test1(String), 123456(String), test@mybatis.tk(String), test info(String), [B@3b7d3a38(byte[]), 2021-03-17(Date)
<==    Updates: 1
插入的记录:SysUser{id=null, userName='test1', userPassword='123456', userEmail='test@mybatis.tk', userInfo='test info', headImg=[1, 2, 3], createTime=Wed Mar 17 21:48:05 CST 2021}

2.修改上面的insert语句,给createTime指定jdbcType

 #{createTime,jdbcType=TIME})

执行上面的测试方法,出现了异常Incorrect datetime value: '21:49:59' for column 'create_time',表示数据库中的字段类型为datetime,但是这里只有time部分的值。

==>  Preparing: insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time) values (?,?, ?, ?, ?, ?, ?) 
==> Parameters: null, test1(String), 123456(String), test@mybatis.tk(String), test info(String), [B@27216cd(byte[]), 21:49:59(Time)
Disconnected from the target VM, address: 'javadebug', transport: 'shared memory'

org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect datetime value: '21:49:59' for column 'create_time' at row 1
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time)         values (?,?, ?, ?, ?, ?, ?)
### Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect datetime value: '21:49:59' for column 'create_time' at row 1

通过实践可知:mysql数据库中datetime可以存储DATE和TIMESTAMP这两种类型的时间,不能存储TIME类型的时间。将数据库的字段类型修改为time就可以存储TIME了。

介绍-int insert(SysUser user)

insert方法的返回值不是数据库返回的主键值,它其实是执行SQL影响的行数,整个值和日志中的Updates:1是一致的。也就是说,整个INSERT语句影响了数据库中的1行数据。如果是批量插入、批量更新、批量删除,这里的数字回时插入的数据个数、更新的数据个数、删除的数据个数。

实践-JDBC获取主键自增的值

该方法适合MySQL、SQL Server数据库。

mapper中接口

/**
     * 插入用户
     * @param user 用户
     * @return 会返回插入记录的主键
     */
    int insert2(SysUser user);

xml

 <insert id="insert2" useGeneratedKeys="true" keyProperty="id">
        insert into mybatis.sys_user(user_name, user_password, user_email, user_info, head_img, create_time)
        values (#{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg}, #{createTime})
    </insert>

测试方法和上面insert一致,只是修改mapper调用的方法为insert2,测试结果为

==>  Preparing: insert into mybatis.sys_user(user_name, user_password, user_email, user_info, head_img, create_time) values (?, ?, ?, ?, ?, ?) 
==> Parameters: test1(String), 123456(String), test@mybatis.tk(String), test info(String), [B@416c58f5(byte[]), 2021-03-17 22:05:49.828(Timestamp)
<==    Updates: 1
插入的记录:SysUser{id=1004, userName='test1', userPassword='123456', userEmail='test@mybatis.tk', userInfo='test info', headImg=[1, 2, 3], createTime=Wed Mar 17 22:05:49 CST 2021}

insert2相比insert方法,是在insert标签上加了两个属性,useGeneratedKeys="true" keyProperty="id"。可以参考上面得insert标签介绍。

insert语句中id列和#{id}属性可要也可不要,不会影响返回得的主键值。

==>  Preparing: insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time) values (?,?, ?, ?, ?, ?, ?) 
==> Parameters: null, test1(String), 123456(String), test@mybatis.tk(String), test info(String), [B@3b7d3a38(byte[]), 2021-03-17 22:10:51.385(Timestamp)
<==    Updates: 1
插入的记录:SysUser{id=1006, userName='test1', userPassword='123456', userEmail='test@mybatis.tk', userInfo='test info', headImg=[1, 2, 3], createTime=Wed Mar 17 22:10:51 CST 2021}

如需插入该记录,则将 测试方法中sqlSession.rollback();替换为sqlSession.commit();,将结果提交给数据库(否则数据只存在于session中,会随着程序的关闭而消失)

实践-selectKey返回主键值

有些数据库不支持主键自增功能,而是使用序列得到一个值,例如Oracle,然后将这个值赋给id,再将数据插入数据库。

使用<selectKey>标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。

mapper接口定义

    /**
     * 插入用户,使用selectKey方式获取主键
     * @param user 用户
     * @return 会返回插入记录的主键
     */
    int insert3(SysUser user);

xml定义

 <insert id="insert3">
        insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time)
        values (#{id},#{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg}, #{createTime})
        <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
            select LAST_INSERT_ID()
        </selectKey>
    </insert>

测试方法和上面insert一致,只是修改mapper调用的方法为insert3,测试结果为

==>  Preparing: insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time) values (?,?, ?, ?, ?, ?, ?) 
==> Parameters: null, test1(String), 123456(String), test@mybatis.tk(String), test info(String), [B@21337f7b(byte[]), 2021-03-17 22:20:46.047(Timestamp)
<==    Updates: 1
==>  Preparing: select LAST_INSERT_ID() 
==> Parameters: 
<==    Columns: LAST_INSERT_ID()
<==        Row: 1009
<==      Total: 1
插入的记录:SysUser{id=1009, userName='test1', userPassword='123456', userEmail='test@mybatis.tk', userInfo='test info', headImg=[1, 2, 3], createTime=Wed Mar 17 22:20:46 CST 2021}

和insert插入的xml相比,本此多了selectKey标签,其中keyProperty表示java对象中主键的属性名keyColumn表示数据库中主键字段名,resultType用于设置返回值的类型。order的值和数据库有关,MySQL中为AFTER,Oracle中为BEFORE,这是因为Oracle中需要先从序列获取值,然后将值作为主键插入到数据库中

<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
            select LAST_INSERT_ID()
        </selectKey>

在Oracle中写法如下,INSERT语句中明确写出了id列和值#{id},因为执行selectKey中的语句后id就有值了,需要把这个序列值作为主键值插入到数据库中,所以必须指定id列,如果不指定这一列,数据库就会因为主键不能为空抛出异常。

 <insert id="insert3">
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFOR">
            select SEQ_ID.nextval from dual
        </selectKey>
insert into mybatis.sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time)
        values (#{id},#{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg}, #{createTime})
</insert>

以下是其他一些支持主键自增的数据库配置selectKey中诙谐主键的SQL

  • DB2:VALUES IDENTITY_VAL_LOCAL()
  • MYSQL:SELECT LAST_INSERT_ID()
  • SQLSERVER:SELECT SCOPE_IDENTITY()
  • CLOUDSCAPE:VALUES IDENTITY_VAL_LOCAL()
  • DERBY:VALUES IDENTITY_VAL_LOCAL()
  • HSQLDB:CALL IDENTITY()
  • SYBASE:SELECT @@IDENTITY
  • DB2_MF:SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1
  • INFORMIX:select dbinfo('sqlca.sqlerrd1') from systables where tabid=1
原文地址:https://www.cnblogs.com/tianhao-luo/p/14552465.html