2.4  insert 用法

2.4.1  简单的 insert方法

在接口 UserMapper.java 中添加如下方法。

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

然后打开对应的 UserMapper.xml 文件,添加如下代码。

    <insert id="insert">
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 :对于 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 的语句,后者会被忽略。

在values中通过  #{ property } 方式从(实体类对象的)参数中取出属性的值。为了防止类型错误,对于一些特殊的数据类型,建议指定具体的 jdbcType 值。例如 headImg 指定 BLOB 类型, createTime 指定 TIMESTAMP 类型。

特别说明:

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

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

BaseMapperTest

import java.io.IOException;
import java.io.Reader; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.BeforeClass; /**
* 基础测试类
*/ public class BaseMapperTest {
private static SqlSessionFactory sqlSessionFactory; @BeforeClass
public static void init() {
try {
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException ignore) {
ignore.printStackTrace();
}
} public SqlSession getSqlSession(){
return sqlSessionFactory.openSession(); }
}

基础测试类

现在在 UserMapperTest 测试类中增加一个方法来测试这个 insert 方法,代码如下。现在在 UserMapperTest 测试类中增加一个方法来测试这个 insert 方法,代码如下。

    @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()); //引用数据类型未赋值默认为null
} finally {
//为了不影响数据库中的数据导致其他测试失败,这里选择回滚
//由于默认的 sqlSessionFactory.openSession() 是不自动提交的,
//因此不手动执行 commit 也不会提交到数据库
sqlSession.rollback();
//不要忘记关闭 sqlSession
sqlSession.close();
} }

public void testInsert()

数据库的datatime类型可以存储DATE(时间部分默认为00:00:00)和 TIMESTAMP两种类型的时间。

上面接口中对应的方法   int  insert( SysUser sysUser)   ,这个int类型返回值是执行的SQL影响的行数,这个值和日志中的 Updatas:1 是一致的。


如何获得主键的值呢?下面提供两种方法,基本上可以涵盖所有数据库的不同情况。

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

在使用主键自增(如 MySQL、 SQL Server 数据库)时,插入数据库后可能需要得到自增的主键值,然后使用这个值进行一些其他的操作。

现在添加一个insert2方法,首先在UserMapper接口中增加insert2方法。

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

然后在XML映射文件中新增一个 insert2 方法。

    <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>
useGeneratedKeys="true" 后,当需要设置多个属性值时,使用逗号隔开,还需要设置 keyColumn属性,按顺序指定数据库的列 ,这里列的值会和 keyProperty配置的属性一一对应。
由于要使用数据库返回的主键值,所以 SQL 上下两部分的列中去掉了 id 列和对应的#{id}属性。 下面写一个测试,验证是否返回了SysUser的主键值,在测试类 UserMapperTest中添加如下代码。
    @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.setCreateTime(new Date());
int result = userMapper.insert2(user);
//只插入1条数据
Assert.assertEquals(1,result);
//因为id回写,所以id不为null
Assert.assertNotNull(user.getId());
} finally {
sqlSession.rollback();
//不要忘记关闭 sqlSession
sqlSession.close();
}
}

public void testInsert2()


2.4.3 使用 selectKey 返回主键的值

有些数据库(如 Oracle)不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给 id,再将数据插入数据库。对于这种情况,可以采用另外一种方式:使用 <selectKey> 标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。

先来看一下MySQL的例子。

在接口和XML中再新增一个insert3方法, UserMapper接口的代码如下。

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

不同之处在 UserMapper.xml 文件中的代码:新添加了<selectKey>标签。

    <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>

注意看下面这段代码,和 insert2 相比增加了 selectKey 标签。

这里的 resultType 用于设置返回值类型。order 属性的设置和使用的数据库有关。在 MySQL 数据库中,order 属性设置的值是 AFTER,因为当前记录的主键值在 insert 语句执行成功后才能获取到。

而在 Oracle 数据库中,order 的值要设置为 BEFORE,这是因为 Oracle 中需要先从序列获取值,然后将值作为主键插入到数据库中。

selectKey元素放置的上、下位置不会影响最终执行的结果。这么写仅仅是为了符合实际的执行顺序,看起来更直观而已。

在 Oracle 示例中, SELECT SEQ _ ID.nextval from dual 是一个获取序列的 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.SYSDUMMY 1。

· INFORMIX 使用 select dbinfo ( 'sqlca.sqlerrd 1') from systables where tabid= 1。 

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


2.5 update 用法

先来看一个简单的通过主键更新数据的 update 方法的例子。在 UserMapper 接口中添加以下方法。

     /**
* 根据主键更新
*
* @param sysUser
* @return
* */
int updateById(SysUser sysUser); //这里的参数 sysUser是要更新的数据
在接口对应的 UserMapper.xml中添加如下代码。
    <update id="updateById">
update sys_user
set user_name = #{userName},
user_password = #{userPassword},
user_email = #{userEmail},
user_info = #{userInfo},
head_img = #{headImg, jdbcType=BLOB},
create_time = #{createTime, jdbcType=TIMESTAMP}
where id = #{id}
</update>

这个方法的 SQL 很简单,下面写一个简单的测试来验证一下。在 UserMapperTest 中添加如下代码。

@Test
public void testUpdateById(){
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//从数据库查询 1 个 user 对象
SysUser user = userMapper.selectById(1L);
//当前 userName 为 admin
Assert.assertEquals("admin", user.getUserName());
//修改用户名
user.setUserName("admin_test");
//修改邮箱
user.setUserEmail("test@mybatis.tk");
//更新数据,特别注意,这里的返回值 result 是执行的 SQL 影响的行数
int result = userMapper.updateById(user);
//只更新 1 条数据
Assert.assertEquals(1, result);
//根据当前 id 查询修改后的数据
user = userMapper.selectById(1L);
//修改后的名字 admin_test
Assert.assertEquals("admin_test", user.getUserName());
} finally {
//为了不影响数据库中的数据导致其他测试失败,这里选择回滚
//由于默认的 sqlSessionFactory.openSession() 是不自动提交的,
//因此不手动执行 commit 也不会提交到数据库
sqlSession.rollback();
//不要忘记关闭 sqlSession
sqlSession.close();
}
}

public void testUpdateById()

还可以通过修改 UPDATE 语句中的 WHERE 条件来更新一条或一批数据。基本的 update 用法就这么简单,更复杂的情况在后面的动态 SQL 章节中会进行讲解。


2.6  delete用法

delete 同 update 类似,下面也用一个简单的例子说明。在 UserMapper 中添加一个简单的例子,代码如下。

    /**
* 通过主键删除
*
* @param id
* @return
*/
int deleteById(Long id);

根据主键删除数据的时候,如果主键只有一个字段,那么就可以和这个方法一样使用一个参数id ,这个方法对应UserMapper.xml中的代码如下。

    <delete  id="deleteById">
delete from sys_user
where id = #{id }
</delete>

注意接口中 int deleteById (Long id);方法的参数类型为 Long id,如果将参数类型修改如下,也是正确的。

对于以上的接口,在 UserMapperTest中编写一个测试方法,代码如下。

    @Test
public void testDeleteById(){
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//从数据库查询 1 个 user 对象,根据 id = 1 查询
SysUser user1 = userMapper.selectById( 1L);
//现在还能查询出 user 对象
Assert.assertNotNull(user1);
//调用方法删除
Assert.assertEquals(1, userMapper.deleteById(user1));
//再次查询,这时应该没有值,为 null
Assert.assertNull(userMapper.selectById(1L)); /* //使用 SysUser 参数再做一遍测试,根据 id = 1001 查询
SysUser user2 = userMapper.selectById(1001L);
//现在还能查询出 user 对象
Assert.assertNotNull(user2);
//调用方法删除,注意这里使用参数为 user2
Assert.assertEquals(1, userMapper.deleteById(user2));
//再次查询,这时应该没有值,为 null
Assert.assertNull(userMapper.selectById(1001L));
//使用 SysUser 参数再做一遍测试*/
} finally {
//为了不影响数据库中的数据导致其他测试失败,这里选择回滚
//由于默认的 sqlSessionFactory.openSession() 是不自动提交的,
//因此不手动执行 commit 也不会提交到数据库
sqlSession.rollback();
//不要忘记关闭 sqlSession
sqlSession.close();
}
}

下面给出deleteById方法输出的操作日志。

以上是一个简单的 delete 方法示例,在动态 SQL 章节中还会介绍一些更复杂的用法。


2.7 多个接口参数的用法

上述CURD案例中的方法的参数只有一个:一种是基本类型,另一种是JavaBean。

在实际应用中经常会遇到使用多个参数的情况。前面几节的例子中,我们将多个参数合并到一个 JavaBean 中,并使用这个 JavaBean 作为接口方法的参数。这种方法用起来很方便,但并不适合全部的情况,因为不能只为了两三个参数去创建新的 JavaBean 类,因此对于参数比较少的情况,还有两种方式可以采用:使用 Map 类型作为参数或使用@Param 注解。

现在,在接口方法的参数前添加 @Param注解,代码如下。

    /**
* 根据用户 id 和 角色的 enabled 状态获取用户的角色
*
* @param userId
* @param enabled
* @return
*/
List<SysRole> selectRolesByUserIdAndRoleEnabled(
@Param("userId")Long userId,
@Param("enabled")Integer enabled );

这个接口方法对应的 UserMapper.xml中的代码如下。

    <select id="selectRolesByUserIdAndRoleEnabled" resultType="SysRole">
select
r.id,
r.role_name roleName,
r.enabled,
r.create_by createBy,
r.create_time createTime
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where u.id = #{userId} and r.enabled = #{enabled}
</select>

在 UserMapperTest 中添加如下代码进行测试。

    @Test
public void testSelectRolesByUserIdAndRoleEnabled(){
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用 selectRolesByUserIdAndRoleEnabled 方法查询用户的角色
List<SysRole> roleList = userMapper.selectRolesByUserIdAndRoleEnabled(1L, null);
//结果不为空
Assert.assertNotNull(roleList);
//角色数量大于 0 个
Assert.assertTrue(roleList.size() > 0);
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}

Test

    /**
* 根据用户 id 和 角色的 enabled 状态获取用户的角色
*
* @param user
* @param role
* @return
*/
List<SysRole> selectRolesByUserIdAndRoleEnabledBean(
@Param("user") SysUser user,
@Param("role") SysRole role );
    <select id="selectRolesByUserIdAndRoleEnabledBean" resultType="SysRole">
select
r.id,
r.role_name roleName,
r.enabled,
r.create_by createBy,
r.create_time createTime
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where u.id = #{user.id} and r.enabled = #{role.enabled}
</select>

select id="selectRolesByUserIdAndRoleEnabledBean

    @Test
public void testSelectRolesByUserIdAndRoleEnabledBean(){
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用 selectRolesByUserIdAndRoleEnabled 方法查询用户的角色
SysUser user = new SysUser();
user.setId(1L);
SysRole role = new SysRole();
role.setEnabled(1);
List<SysRole> roleList = userMapper.selectRolesByUserIdAndRoleEnabledBean(user, role);
//结果不为空
Assert.assertNotNull(roleList);
//角色数量大于 0 个
Assert.assertTrue(roleList.size() > 0);
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}

public void testSelectRolesByUserIdAndRoleEnabledBean

=================================================================================================

end

MyBatis从入门到精通(第2章):MyBatis XML方式的基本用法【insert用法、update用法、delete用法】的更多相关文章

  1. MyBatis从入门到精通(第5章):5.4 Example 介绍

    jdk1.8.MyBatis3.4.6.MySQL数据库5.6.45.Eclipse Version: 2019-12 M2 (4.14.0) MyBatis从入门到精通(第5章):MyBatis代码 ...

  2. MyBatis从入门到精通(第9章):Spring集成MyBatis(下)

    MyBatis从入门到精通(第9章):Spring集成MyBatis(下) springmvc执行流程原理 mybatis-spring  可以帮助我们将MyBatis代码无缝整合到Spring中.使 ...

  3. MyBatis从入门到精通(第9章):Spring集成MyBatis(中)

    MyBatis从入门到精通(第9章):Spring集成MyBatis(中) 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法.应该将应用自身的设计和具体 ...

  4. MyBatis从入门到精通(第9章):Spring集成MyBatis(上)

    MyBatis从入门到精通(第9章):Spring集成MyBatis(上) Spring是一个为了解决企业级Web应用开发过程中面临的复杂性,而被创建的一个非常流行的轻量级框架. mybatis-sp ...

  5. MyBatis从入门到精通(第5章):MyBatis代码生成器

    jdk1.8.MyBatis3.4.6.MySQL数据库5.6.45.Eclipse Version: 2019-12 M2 (4.14.0) MyBatis从入门到精通(第5章):MyBatis代码 ...

  6. MyBatis从入门到精通(第3章):MyBatis注解方式的基本使用

    MyBatis 注解方式就是将 SQL 语句直接写在DAO层的接口上. 在黑马录制的2018年双元视频课:\08 SSM整合案例[企业权限管理系统]\07.订单操作  有使用MyBatis注解进行多表 ...

  7. MyBatis从入门到精通:第一章实体类与Mapper.xml文件

    实体类: package tk.mybatis.simple.model; public class Country { public Long getId() { return id; } publ ...

  8. MyBatis从入门到精通:第一章配置MyBatis

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...

  9. MyBatis从入门到精通(第6章):MyBatis 高级查询->6.1.2高级结果映射之一对多映射

    jdk1.8.MyBatis3.4.6.MySQL数据库5.6.45.IntelliJ IDEA 2019.3.1 本章主要包含的内容为 MyBatis 的高级结果映射,主要处理数据库一对一.一对多的 ...

随机推荐

  1. Django——include()三种使用方法

    include()的三种使用方法 1.include(module, namespace=None) 2.include(pattern_list)  最常用 3.include((pattern_l ...

  2. 十七、SAP中使用SQL语句读取一条数据

    一.需要说明的是SAP不同类型的结构体类型之间是不能随意赋值的,如果需要赋值,可以使用CORRESPONDING FIELDS OF关键字, 不同类型结构体中同名的成员会被赋值,代码如下: 二.输出代 ...

  3. 文献阅读报告 - Social Ways: Learning Multi-Modal Distributions of Pedestrian Trajectories with GANs

    文献引用 Amirian J, Hayet J B, Pettre J. Social Ways: Learning Multi-Modal Distributions of Pedestrian T ...

  4. 编译Linux

    下载内核源文件 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/ 生成.config配置文件 make ...

  5. Java交换数据为何不起作用原因分析

    一.概述 目前各类语言中向函数传递参数的类型分为三种: 按值传递 按引用传递 按指针传递 其中按值传递表示方法(函数)接收的是调用者提供的变量的拷贝,不改变参数的值:按引用传递表示方法(函数)接收的调 ...

  6. 六、React 键盘事件 表单事件 事件对象以及React中的ref获取dom节点 、React实现类似Vue的双向数据绑定

    接:https://www.cnblogs.com/chenxi188/p/11782349.html 事件对象 .键盘事件. 表单事件 .ref获取dom节点.React实现类似vue双向数据绑定 ...

  7. leetcode 正则表达式 (动态规划)

    给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符'*' 匹配零个或多个前面的那一个元素所谓匹配,是要涵盖 整个 字符串 s的 ...

  8. ThinkPHP 5.0远程命令执行漏洞分析与复现

    0x00 前言 ThinkPHP官方2018年12月9日发布重要的安全更新,修复了一个严重的远程代码执行漏洞.该更新主要涉及一个安全更新,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的 ...

  9. 2016蓝桥杯省赛C/C++A组第八题 四平方和

    题意: 四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多4个正整数的平方和. 如果把0包括进去,就正好可以表示为4个数的平方和. 比如: 5 = 0^2 + 0^2 + 1^2 + 2^ ...

  10. PWC6199:Generated servlet error:Only a type can be imported. org.apache.jasper.tagplugins.jstl.core.ForEach resolves to a package

    <%@ import="org.apache.jasper.tagplugins.jstl.core.ForEach"%> 去掉这条语句,就不报错了.所以问题就出在这里 ...