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}
-
我们不给对象的主键字段值,构造插入语句时插入的是null。
-
insert的结果是1
-
日期的格式是
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