zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    自定义博客园skin
    c++11: <thread>学习
    《明日方舟》Python版公开招募工具
    Python列表
    Python基础
    C#常用修饰符
    C#单例类的实现
    云服务器反黑客入侵攻防实录(一)
    在CentOS7.6上安装自动化运维工具Ansible以及playbook案例实操
    技术漫谈 | 远程访问和控制云端K8S服务器的方法
  • 原文地址:https://www.cnblogs.com/tianhao-luo/p/14552465.html
Copyright © 2011-2022 走看看