2.3、MyBatis的XML基本用法——insert用法

2.3、MyBatis的XML基本用法——insert用法

insert比较简单,除了需要返回主键时,不同数据库的方式有所不同

1、简单用法

添加接口方法

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

 添加XML设置

<insert id="insert">
    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>
View Code

测试代码

@Test
public void testInsert() {
    SqlSession sqlSession = getSqlSession();
    try {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 创建一个 user 对象
        SysUser user = new SysUser();
        user.setUserName("test1");
        user.setUserPassword("123456");
        user.setUserEmail("test@mybatis.tk");
        user.setUserInfo("test info");
        // 正常情况下应该读入一张图片存到 byte 数组中
        user.setHeadImg(new byte[] { 1, 2, 3 });
        user.setCreateTime(new Date());
        // 将新建的对象插入数据库中,特别注意,这里的返回值 result 是执行的 SQL 影响的行数
        int result = userMapper.insert(user);
        // 只插入 1 条数据
        Assert.assertEquals(1, result);
        // id 为 null,我们没有给 id 赋值,并且没有配置回写 id 的值
        Assert.assertNull(user.getId());
    } finally {
        // 为了不影响数据库中的数据导致其他测试失败,这里选择回滚
        // 由于默认的 sqlSessionFactory.openSession() 是不自动提交的,
        // 因此不手动执行 commit 也不会提交到数据库
        sqlSession.rollback();
        // 不要忘记关闭 sqlSession
        sqlSession.close();
    }
}
View Code

<insert>标签包含如下属性

id:命名空间中的唯一标识符,可用来代表这条语句。

parameterType:即将传入的语句参数的完全限定类名或别名。这个属性是可选的,因为MyBatis可以推断出传入语句的具体参数,因此不建议配置该属性。

flushCache:默认值为true,任何时候只要语句被调用,都会清空一级缓存和二级缓存。

timeout:设置在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。

statementType:对于STATEMENT、PREPARED、CALLABLE,MyBatis会分别使用对应的Statement、PreparedStatement、CallableStatement,默认值为PREPARED。

useGeneratedKeys:默认值为false。如果设置为true,MyBatis会使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键。

keyProperty:MyBatis通过getGeneratedKeys获取主键值后将要赋值的属性名。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表。

keyColumn:仅对INSERT和UPDATE有用。通过生成的键值设置表中的列名,这个设置仅在某些数据库(如PostgreSQL)中是必须的,当主键列不是表中的第一列时需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

databaseId:如果配置了databaseIdProvider(4.6节有详细配置方法),MyBatis会加载所有的不带databaseId的或匹配当前databaseId的语句。如果同时存在带databaseId和不带databaseId的语句,后者会被忽略。

此处<insert>中的SQL就是一个简单的INSERT语句,将所有的列都列举出来,在values中通过#{property}方式从参数中取出属性的值。

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

特别说明!

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

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

2、使用JDBC方式返回主键自增的值

适用于数据库本身可以设置字段为自增的情况

接口方法

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

XML配置,主要和上面例子增加了useGeneratedKeys="true" keyProperty="id"

<insert id="insert2" 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>
View Code

useGeneratedKeys设置为true后,MyBatis会使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键。获得主键值后将其赋值给keyProperty配置的id属性。当需要设置多个属性时,使用逗号隔开,这种情况下通常还需要设置keyColumn属性,按顺序指定数据库的列,这里列的值会和keyProperty配置的属性一一对应

测试代码

@Test
public void testInsert2() {
    SqlSession sqlSession = getSqlSession();
    try {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 创建一个 user 对象
        SysUser user = new SysUser();
        user.setUserName("test1");
        user.setUserPassword("123456");
        user.setUserEmail("test@mybatis.tk");
        user.setUserInfo("test info");
        user.setHeadImg(new byte[] { 1, 2, 3 });
        user.setCreateTime(new Date());
        int result = userMapper.insert2(user);
        // 只插入 1 条数据
        Assert.assertEquals(1, result);
        // 因为 id 回写,所以 id 不为 null
        Assert.assertNotNull(user.getId());

    } finally {
        sqlSession.commit();
        // 不要忘记关闭 sqlSession
        sqlSession.close();
    }
}
View Code

3、使用selectKey返回主键的值

这种方式既适用于2的情况,更适用于数据库不支持自增列,而是通过序列得到一个值,然后赋值给id再插入数据库的情况

接口方法

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

XML配置

MySQL数据库

<insert id="insert3">
    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>
View Code

Oracle数据库

<!-- Oracle 的例子,查询多个列的时候需要 keyColumn -->
<insert id="insertOracle">
    <selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE">
        SELECT SEQ_USER.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>
View Code

selectKey标签的keyColumn、keyProperty和上面useGeneratedKeys的用法含义相同,这里的resultType用于设置返回值类型。order属性的设置和使用的数据库有关。在MySQL数据库中,order属性设置的值是AFTER,因为当前记录的主键值在insert语句执行成功后才能获取到。而在Oracle数据库中,order的值要设置为BEFORE,这是因为Oracle中需要先从序列获取值,然后将值作为主键插入到数据库中

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

而selectKey标签的写法在前后并无所谓,影响执行顺序的只是order

不同数据库生成id的语句不同

DB2使用VALUESIDENTITY_VAL_LOCAL()。
MYSQL使用SELECTLAST_INSERT_ID()。
SQLSERVER使用SELECTSCOPE_IDENTITY()。
CLOUDSCAPE使用VALUESIDENTITY_VAL_LOCAL()。
DERBY使用VALUESIDENTITY_VAL_LOCAL()。
HSQLDB使用CALLIDENTITY()。
SYBASE使用SELECT@@IDENTITY。
DB2_MF使用SELECTIDENTITY_VAL_LOCAL()FROMSYSIBM.SYSDUMMY1。
INFORMIX使用selectdbinfo('sqlca.sqlerrd1')fromsystableswheretabid=1

 

posted @ 2018-02-28 14:35  LiveYourLife  阅读(2250)  评论(0)    收藏  举报