insert概述
和 MyBatis-03 MyBatis XML方式之select元素比起来,insert要简单的多。 只有让它返回主键值时,由于不同的数据库的主键生成方式不同,这种情况会复杂一点。
简单的insert用法
1. UserMapper中添加接口方法
/** * * * @Title: insertSysUser * * @Description: 增加SysUser * * @param sysUser * @return * * @return: int 受影响的行数 */ int insertSysUser(SysUser sysUser);
2. UserMapper.xml 添加节点
<!-- 添加SysUser --> <insert id="insertSysUser" > 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>
先看下insert元素标签包含的属性
id:命名空间中的唯一标示符
parameterType:传入的语句参数的全限定类名或者别名,因为 MyBatis可以推断传入语句的具体参数,因此不建议配置该属性
flushCache :默认true,任何时候只要语句被调用,都会清空一级缓存和二级缓存
timeout:设置在抛出异常之前,驱动程序等待数据库返回请求结果的秒数
statementType : 默认PREPARED
useGenerateKeys: 默认false. 如果设置为true , MyBatis会使用JDBC的getGeneratedKeys方法取出由数据库内部生成的主键
keyProperty: MyBatis通过getGeneratedKeys获取组建后要将辅助的属性名。
keyColumn:仅对UPDATE和INSERT又有,通过生成的键值设置表中的列名。
databaseId:如果配置了databaseIdProvider, MyBatis会加载所有的不带databaseId或者匹配当前databaseId的语句。 如果同时存在带databaseId和不带databaseId的语句,后者将被忽略。
此外,insert中的sql语句就是一个简单的insert语句,将所有的列都列举出来,在value中通过#{property}方式从参数中取出属性的值。
为了防止类型错误,对于一些特殊的数据类型,建议指定具体的jdbcType值#{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}
3. 编写单元测试
@Test public void insertSysUserTest() { logger.info("insertSysUserTest"); // 获取SqlSession SqlSession sqlSession = getSqlSession(); try { // 获取UserMapper接口 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); SysUser sysUser = new SysUser(); sysUser.setUserName("artisanTest"); sysUser.setUserPassword("123456"); sysUser.setUserEmail("test@artisan.com"); sysUser.setUserInfo("测试用户"); // 模拟头像 sysUser.setHeadImg(new byte[] { 1, 2, 3 }); sysUser.setCreateTime(new Date()); // 新增用户 ,返回受影响的行数 int result = userMapper.insertSysUser(sysUser); // 只插入一条数据 ,期望是1 Assert.assertEquals(1, result); // id 为null , 因为没有给ID赋值,也没有配置回写id的值 ,期望是null Assert.assertNull(sysUser.getId()); logger.info("受影响的行数:" + result); } catch (Exception e) { e.printStackTrace(); } finally { // 为了保持测试数据的干净,这里选择回滚 // 由于默认的sqlSessionFactory.openSession()是不自动提交的 // 除非显式的commit,否则不会提交到数据库 sqlSession.rollback(); logger.info("为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成"); sqlSession.close(); logger.info("sqlSession close successfully "); } }
日志
2018-04-15 18:32:49,378 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-04-15 18:32:49,383 INFO [main] (BaseMapperTest.java:29) - reader close successfully 2018-04-15 18:32:49,386 INFO [main] (UserMapperTest.java:152) - insertSysUserTest 2018-04-15 18:32:49,970 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Preparing: insert into sys_user( id,user_name, user_password, user_email, user_info, head_img, create_time) values( ?,?, ?, ?, ?, ?, ?) 2018-04-15 18:32:50,060 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Parameters: null, artisanTest(String), 123456(String), test@artisan.com(String), 测试用户(String), java.io.ByteArrayInputStream@50a14c18(ByteArrayInputStream), 2018-04-15 18:32:49.403(Timestamp) 2018-04-15 18:32:50,066 DEBUG [main] (BaseJdbcLogger.java:142) - <== Updates: 1 2018-04-15 18:32:50,067 INFO [main] (UserMapperTest.java:174) - 受影响的行数:1 2018-04-15 18:32:50,078 INFO [main] (UserMapperTest.java:182) - 为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成 2018-04-15 18:32:50,080 INFO [main] (UserMapperTest.java:185) - sqlSession close successfully
使用JDCB方式返回主键自增的值
在使用主键自增(比如MySql 、SQLServer数据库)时,插入数据库后可以需要得到自增的主键值,然后使用这个值进行一些其他的操作。
1.UserMapper接口增加接口方法
// 演示使用JDBC方式返回主键的自增长值 int insertSysUser2(SysUser sysUser);
2.UserMapper.xml 配置
<!-- 添加SysUser 使用JDBC的方式返回自增长的主键的值--> <insert id="insertSysUser2" 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>
和insertSysUser比较, insertSysUser2主要的变化是在insert 标签上配置了两个属性
useGeneratedKeys="true" keyProperty="id"
useGeneratedKeys设置为true后, MyBatis会使用JDBC的getGeneratedKeys方法来取由数据库内部生成的主键。 获取主键值后将其赋值给keyProperty配置的id属性。
当需要设置多个属性时,使用逗号分开,这种情况下通常还需要设置keyColunm属性,按顺序指定数据库的列,这里的列的值会和keyProperty配置的属性一一对应。
由于使用数据库返回的主键值,所以SQL上线两部分中的列去掉了id列和对应的#{id}属性。
3.单元测试
@Test public void insertSysUser2Test() { logger.info("insertSysUser2Test"); // 获取SqlSession SqlSession sqlSession = getSqlSession(); try { // 获取UserMapper接口 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); SysUser sysUser = new SysUser(); sysUser.setUserName("artisanTest"); sysUser.setUserPassword("123456"); sysUser.setUserEmail("test@artisan.com"); sysUser.setUserInfo("测试用户"); // 模拟头像 sysUser.setHeadImg(new byte[] { 1, 2, 3 }); sysUser.setCreateTime(new Date()); // 新增用户 ,返回受影响的行数 int result = userMapper.insertSysUser2(sysUser); // 只插入一条数据 ,期望是1 Assert.assertEquals(1, result); // id不为null ,因为使用了 useGeneratedKeys="true" keyProperty="id" Assert.assertNotNull(sysUser.getId()); logger.info("受影响的行数:" + result); logger.info("userId:" + sysUser.getId()); } catch (Exception e) { e.printStackTrace(); } finally { // 为了保持测试数据的干净,这里选择回滚 // 由于默认的sqlSessionFactory.openSession()是不自动提交的 // 除非显式的commit,否则不会提交到数据库 sqlSession.rollback(); logger.info("为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成"); sqlSession.close(); logger.info("sqlSession close successfully "); } }
日志
2018-04-16 00:36:27,508 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-04-16 00:36:27,511 INFO [main] (BaseMapperTest.java:29) - reader close successfully 2018-04-16 00:36:27,514 INFO [main] (UserMapperTest.java:191) - insertSysUser2Test 2018-04-16 00:36:28,049 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Preparing: insert into sys_user( user_name, user_password, user_email, user_info, head_img, create_time) values( ?, ?, ?, ?, ?, ?) 2018-04-16 00:36:28,112 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Parameters: artisanTest(String), 123456(String), test@artisan.com(String), 测试用户(String), java.io.ByteArrayInputStream@4021065(ByteArrayInputStream), 2018-04-16 00:36:27.526(Timestamp) 2018-04-16 00:36:28,124 DEBUG [main] (BaseJdbcLogger.java:142) - <== Updates: 1 2018-04-16 00:36:28,125 INFO [main] (UserMapperTest.java:213) - 受影响的行数:1 2018-04-16 00:36:28,125 INFO [main] (UserMapperTest.java:214) - userId:1002 2018-04-16 00:36:28,127 INFO [main] (UserMapperTest.java:222) - 为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成 2018-04-16 00:36:28,129 INFO [main] (UserMapperTest.java:225) - sqlSession close successfully
使用selectKey返回主键的值
上面这种写法只适用于支持组件自增的数据库,有些数据库比如Oracle不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给id ,然后再插入数据库。
对应这种情况,可以使用 selectKey标签来获取主键的值,这种方式不仅使用不提供主键自增功能的数据库,同时也适用于提供主键自增功能的数据库
1.UserMapper接口增加接口方法
// 演示使用selectKey的方式返回主键的自增长值 int insertSysUser3(SysUser sysUser);
2.UserMapper.xml 配置
<!-- 添加SysUser 使用selectKey的方式返回自增长的主键的值--> <insert id="insertSysUser3"> 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>
- selectKey标签的keyColum、keyProperty
和上面useGeneratedKeys的用法含义相同。 - resultType用于设置返回值的类型。
- order属性的设置和数据库有关。
Mysql中,order属性设置为AFTER。因为当前记录的主键值是在insert语句执行成功后才获取到的。
Oracle数据库中,order的值设置为BEFORE,这是因为ORCLE数据库需要先从序列中获取中,然后将值作为主键插入数据库中
ORACLE的写法如下
<insert id="insertUser" > <selectKey resultType="java.lang.Integer" order="BEFORE" keyProperty="id"> SELECT 自定义序列.NEXTVAL FROM DUAL </selectKey> insert into ******* </insert> 注意这里使用的order是“BEFORE”
3.单元测试
@Test public void insertSysUser3Test() { logger.info("insertSysUser3Test"); // 获取SqlSession SqlSession sqlSession = getSqlSession(); try { // 获取UserMapper接口 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); SysUser sysUser = new SysUser(); sysUser.setUserName("artisanTest"); sysUser.setUserPassword("123456"); sysUser.setUserEmail("test@artisan.com"); sysUser.setUserInfo("测试用户"); // 模拟头像 sysUser.setHeadImg(new byte[] { 1, 2, 3 }); sysUser.setCreateTime(new Date()); // 新增用户 ,返回受影响的行数 int result = userMapper.insertSysUser3(sysUser); // 只插入一条数据 ,期望是1 Assert.assertEquals(1, result); // id不为null ,因为使用了 useGeneratedKeys="true" keyProperty="id" Assert.assertNotNull(sysUser.getId()); logger.info("受影响的行数:" + result); logger.info("userId:" + sysUser.getId()); } catch (Exception e) { e.printStackTrace(); } finally { // 为了保持测试数据的干净,这里选择回滚 // 由于默认的sqlSessionFactory.openSession()是不自动提交的 // 除非显式的commit,否则不会提交到数据库 sqlSession.rollback(); logger.info("为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成"); sqlSession.close(); logger.info("sqlSession close successfully "); } }
日志
2018-04-16 00:44:17,807 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-04-16 00:44:17,811 INFO [main] (BaseMapperTest.java:29) - reader close successfully 2018-04-16 00:44:17,814 INFO [main] (UserMapperTest.java:231) - insertSysUser3Test 2018-04-16 00:44:18,278 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Preparing: insert into sys_user( user_name, user_password, user_email, user_info, head_img, create_time) values( ?, ?, ?, ?, ?, ?) 2018-04-16 00:44:18,353 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Parameters: artisanTest(String), 123456(String), test@artisan.com(String), 测试用户(String), java.io.ByteArrayInputStream@18a52c57(ByteArrayInputStream), 2018-04-16 00:44:17.833(Timestamp) 2018-04-16 00:44:18,359 DEBUG [main] (BaseJdbcLogger.java:142) - <== Updates: 1 2018-04-16 00:44:18,361 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Preparing: select last_insert_id() 2018-04-16 00:44:18,362 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Parameters: 2018-04-16 00:44:18,386 TRACE [main] (BaseJdbcLogger.java:148) - <== Columns: last_insert_id() 2018-04-16 00:44:18,386 TRACE [main] (BaseJdbcLogger.java:148) - <== Row: 1003 2018-04-16 00:44:18,389 DEBUG [main] (BaseJdbcLogger.java:142) - <== Total: 1 2018-04-16 00:44:18,391 INFO [main] (UserMapperTest.java:253) - 受影响的行数:1 2018-04-16 00:44:18,391 INFO [main] (UserMapperTest.java:254) - userId:1003 2018-04-16 00:44:18,396 INFO [main] (UserMapperTest.java:262) - 为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成 2018-04-16 00:44:18,398 INFO [main] (UserMapperTest.java:265) - sqlSession close successfully
Mysql使用 uuid实现主键
需要增加通过select uuid()得到uuid值
<insert id="insertUser"> <selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id"> select uuid() </selectKey> 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>
注意这里使用的order是“BEFORE” , 比较简单就不再测试了。