@Insert的用法

本文详细解析了MyBatis中@Insert注解的使用方法,包括不需要返回主键、返回自增主键及返回非自增主键三种场景下的具体实现,并提供了相应的单元测试案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

找了许久@Insert的用法,先转载一波留个记录,原文链接在最下面

概述
不需要返回主键
1.RoleMapper接口增加接口方法
2.单元测试
返回自增主键
1.RoleMapper接口增加接口方法
2.单元测试
返回非自增主键
1.RoleMapper接口增加接口方法
2.单元测试
概述
@Insert注解本身很简单,需要注意的是如果需要返回主键的值,情况会稍微复杂一点,这种XML方式配置本质是一样的

不需要返回主键
1.RoleMapper接口增加接口方法
/**
     * 
     * 
     * @Title: insertSysRole
     * 
     * @Description: insertSysRole 不需要返回主键的情况
     * 
     * @param sysRole
     * @return
     * 
     * @return: int
     */
    @Insert({ "insert into sys_role(id, role_name, enabled, create_by, create_time) values(#{id}, #{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})" })
    int insertSysRole(SysRole sysRole);

2.单元测试
@Test
    public void insertSysRoleTest() {
        logger.info("insertSysRoleTest");
        // 获取SqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            // 获取RoleMapper接口
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            SysRole sysRole = new SysRole();
            sysRole.setId((long) 99);
            sysRole.setRoleName("小工匠");
            sysRole.setEnabled(1);
            sysRole.setCreateBy("test");
            sysRole.setCreateTime(new Date());
            // 新增用户 ,返回受影响的行数
            int result = roleMapper.insertSysRole(sysRole);

            // 只插入一条数据 ,期望是1
            Assert.assertEquals(1, result);
            // 期望roleName 为小工匠
            Assert.assertEquals("小工匠", sysRole.getRoleName());

            logger.info("sysRole:" + sysRole);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 为了保持测试数据的干净,这里选择回滚
            // 由于默认的sqlSessionFactory.openSession()是不自动提交的
            // 除非显式的commit,否则不会提交到数据库
            sqlSession.rollback();
            logger.info("为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成");

            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }


返回自增主键
1.RoleMapper接口增加接口方法
/**
     * 
     * 
     * @Title: insertSysRole2
     * 
     * @Description: insertSysRole2 返回自增主键的情况
     * 
     * @param sysRole
     * @return
     * 
     * @return: int
     */
    @Insert({ "insert into sys_role(role_name, enabled, create_by, create_time) values(#{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})" })
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insertSysRole2(SysRole sysRole);

和第一个场景相比,SQL语句中少了id这一列,注解多了一个@Options, 我们在这个注解设置了useGeneratedKeys 和 keyProperty ,用法同xml中的配置。

2.单元测试
@Test
    public void insertSysRoleTest2() {
        logger.info("insertSysRoleTest2");
        // 获取SqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            // 获取RoleMapper接口
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            SysRole sysRole = new SysRole();
            sysRole.setRoleName("小工匠2");
            sysRole.setEnabled(1);
            sysRole.setCreateBy("test2");
            sysRole.setCreateTime(new Date());
            // 新增用户 ,返回受影响的行数
            int result = roleMapper.insertSysRole2(sysRole);

            // 只插入一条数据 ,期望是1
            Assert.assertEquals(1, result);
            // 期望roleName 为小工匠
            Assert.assertEquals("小工匠2", sysRole.getRoleName());

            logger.info("sysRole:" + sysRole);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 为了保持测试数据的干净,这里选择回滚
            // 由于默认的sqlSessionFactory.openSession()是不自动提交的
            // 除非显式的commit,否则不会提交到数据库
            sqlSession.rollback();
            logger.info("为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成");

            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }


返回非自增主键
1.RoleMapper接口增加接口方法
/**
     * 
     * 
     * @Title: insertSysRole3
     * 
     * @Description: insertSysRole3 返回非自增主键的情况
     * 
     * @param sysRole
     * @return
     * 
     * @return: int
     */
    @Insert({ "insert into sys_role(role_name, enabled, create_by, create_time) values(#{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})" })
    @SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", resultType = Long.class, before = false)
    int insertSysRole3(SysRole sysRole);


配置和xml基本是相同的,其中before=false 等同于order=”AFTER”. before=true 等同于order=”BEFORE”.

不同数据库中,order的配置不同,需要注意下。

2.单元测试
@Test
    public void insertSysRoleTest3() {
        logger.info("insertSysRoleTest3");
        // 获取SqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            // 获取RoleMapper接口
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            SysRole sysRole = new SysRole();
            sysRole.setRoleName("小工匠3");
            sysRole.setEnabled(1);
            sysRole.setCreateBy("test3");
            sysRole.setCreateTime(new Date());
            // 新增用户 ,返回受影响的行数
            int result = roleMapper.insertSysRole3(sysRole);

            // 只插入一条数据 ,期望是1
            Assert.assertEquals(1, result);
            // 期望roleName 为小工匠
            Assert.assertEquals("小工匠3", sysRole.getRoleName());

            logger.info("sysRole:" + sysRole);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 为了保持测试数据的干净,这里选择回滚
            // 由于默认的sqlSessionFactory.openSession()是不自动提交的
            // 除非显式的commit,否则不会提交到数据库
            sqlSession.rollback();
            logger.info("为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成");

            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }


原文:https://blog.youkuaiyun.com/yangshangwei/article/details/80003186 
 

<think>我们正在讨论MyBatis中使用@Insert注解插入HashMap数据的问题。 根据用户需求,他想知道如何使用@Insert注解来插入HashMap类型的数据。 在MyBatis中,我们可以使用注解直接编写SQL,而HashMap作为参数时,其键值对可以直接在SQL中使用。 注意:HashMap的键(key)需要与SQL语句中的参数占位符名称一致。 例如,假设我们有一个HashMap,它包含以下键值对: "name" -> "张三" "age" -> 25 那么,在SQL语句中,我们可以使用#{name}和#{age}来引用这些值。 下面是一个示例,展示如何使用@Insert注解插入一个HashMap到数据库表中: 假设表结构为: CREATE TABLE user ( name VARCHAR(100), age INT ); Mapper接口中的方法可以这样写: ```java @Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})") int insertUser(HashMap<String, Object> map); ``` 这样,当调用这个方法并传入一个包含"name"和"age"键的HashMap时,MyBatis就会将对应的值插入到数据库中。 但是,如果HashMap中的键与数据库表的列名不一致,或者我们想插入的HashMap包含多个键值对(对应多个列),我们需要确保SQL语句中包含了所有需要的列,并且占位符的键名与HashMap中的键名一致。 另外,如果表中有很多列,我们也可以使用一个通用的方法,但是要注意SQL注入问题,因为MyBatis的#{}可以防止SQL注入。 然而,有时我们可能不知道HashMap中具体有哪些键,或者键的数量是动态的,这时使用@Insert注解可能就不太方便,因为注解中的SQL是静态的。在这种情况下,可以考虑使用动态SQL,比如使用@InsertProvider注解,通过一个类来动态生成SQL语句。但用户要求使用@Insert注解,所以我们只讨论静态SQL的情况。 因此,使用@Insert注解插入HashMap的前提是:我们确切地知道HashMap中包含哪些键,并且这些键与表的列名对应。 如果用户希望插入的HashMap中键的数量和名称不固定,那么可能需要考虑其他方式,例如使用@InsertProvider。 但是,根据用户的问题,他明确要求使用@Insert注解,所以我们提供静态SQL的示例。 另外,引用[1]中提到了使用@Param注解,但在这个例子中,我们只有一个参数(HashMap),所以不需要@Param注解。如果方法有多个参数,则需要使用@Param来指定参数名。 引用[3]中展示了在XML中如何插入多个值,但用户要求使用注解,所以不适用。 因此,总结如下: 1. 使用@Insert注解,在SQL语句中直接使用HashMap的键作为参数占位符。 2. 确保传入的HashMap包含SQL语句中需要的所有键。 示例代码: ```java import org.apache.ibatis.annotations.Insert; import java.util.HashMap; public interface UserMapper { @Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})") int insertUser(HashMap<String, Object> userMap); } ``` 调用这个方法时,传入的HashMap必须包含"name"和"age"这两个键。 如果表中有更多的列,比如添加一个"email"列,那么SQL语句可以改为: ```java @Insert("INSERT INTO user (name, age, email) VALUES (#{name}, #{age}, #{email})") int insertUser(HashMap<String, Object> userMap); ``` 同时,HashMap中需要包含"email"键。 注意事项: - 如果HashMap中缺少某个键,那么对应的值将是null。 - 如果HashMap中有多余的键,这些键在SQL中没有使用,则不会影响插入(会被忽略)。 因此,使用@Insert注解插入HashMap是可行的,但要求SQL语句中需要的键在HashMap中必须存在(除非数据库列允许为null,且我们确实要插入null)。 如果用户需要处理动态列,那么可能需要使用@InsertProvider,但这超出了当前问题的范围。 现在,生成相关问题: 1. 如果插入的HashMap中键名与数据库列名不一致怎么办? 2. 如何使用MyBatis的@InsertProvider注解动态生成插入HashMap的SQL? 3. 在插入HashMap时,如何避免SQL注入? 4. 如果插入的HashMap中缺少某个必须的列(数据库列非空),会发生什么?</think>### MyBatis中使用@Insert插入HashMap数据 在MyBatis中,使用`@Insert`注解插入`HashMap`数据时,需直接通过`#{key}`引用Map中的键值。以下是实现方法和注意事项: #### 1. **基础实现示例** ```java @Insert("INSERT INTO users (username, email) " + "VALUES (#{userMap.username}, #{userMap.email})") void insertUser(@Param("userMap") Map<String, Object> userMap); ``` - **调用方式**: ```java Map<String, Object> data = new HashMap<>(); data.put("username", "John"); data.put("email", "john@example.com"); mapper.insertUser(data); ``` #### 2. **动态键值处理** 若需插入动态字段(如不确定Map中的键),需改用**XML映射**或**@InsertProvider**: ```java // 使用@InsertProvider动态生成SQL @InsertProvider(type = UserSqlProvider.class, method = "insertDynamic") void insertDynamic(Map<String, Object> params); ``` ```java public class UserSqlProvider { public String insertDynamic(Map<String, Object> params) { StringBuilder columns = new StringBuilder(); StringBuilder values = new StringBuilder(); params.keySet().forEach(key -> { columns.append(key).append(","); values.append("#{").append(key).append("},"); }); // 移除末尾逗号 columns.setLength(columns.length() - 1); values.setLength(values.length() - 1); return "INSERT INTO users (" + columns + ") VALUES (" + values + ")"; } } ``` #### 3. **注意事项** 1. **键名匹配**:`#{key}`中的`key`必须与Map中的键**完全一致**(区分大小写)。 2. **安全风险**:直接拼接键名可能引发SQL注入,确保键名来自可信来源或使用白名单校验。 3. **空值处理**:若Map中缺少键,MyBatis会尝试插入`null`;若数据库列非空,将报错。 4. **批量插入**:需结合`<foreach>`(XML)或`@InsertProvider`实现[^3]。 #### 4. **应用场景** - 适合简单、字段固定的插入操作。 - 复杂场景(如动态字段、批量插入)优先选择XML映射或`@InsertProvider`[^2]。 --- ### 相关问题 1. **如何防止使用HashMap插入数据时的SQL注入风险?** > 建议对键名进行白名单校验,或使用XML/Provider动态生成SQL时严格过滤参数[^2]。 2. **插入HashMap时遇到`Parameter 'xxx' not found`错误如何解决?** > 检查`#{key}`是否与Map中的键名完全一致(包括大小写),或使用`@Param`显式声明参数名。 3. **MyBatis中如何用HashMap实现批量插入?** > 需在XML中使用`<foreach>`遍历Map集合,或通过`@InsertProvider`构建批量SQL语句[^3]。 4. **插入HashMap与插入JavaBean相比有何优劣?** > **优势**:灵活性高,适合动态字段;**劣势**:类型安全性低,重构困难。建议关键业务使用JavaBean+`@Param`。 [^1]: 通过`@Param`声明参数名,确保`#{key}`正确解析。 [^2]: 动态SQL场景推荐使用`@InsertProvider`灵活构建语句。 [^3]: 批量操作需结合`<foreach>`或动态SQL实现多记录插入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值