mybatis中插入数据库返回主键

mybatis中插入数据库返回主键

     在java后台的数据处理中,经常会有向数据库写入一条数据后,需要获取写入数据的主键,

根据主键再做其他数据库操作。


实现代码:

usercontorl.java:

User user = new User();  
user.setUserName("chenzhou");  
user.setPassword("xxxx");  
user.setComment("测试插入数据返回主键功能");  
  
System.out.println("插入前主键为:"+user.getUserId());  
userDao.insertAndGetId(user);//插入操作  
System.out.println("插入后主键为:"+user.getUserId());  
 Mapper.xml

<insert id="insertAndGetId" useGeneratedKeys="true" keyProperty="userId" parameterType="com.chenzhou.mybatis.User">
    insert into user(userName,password,comment)
    values(#{userName},#{password},#{comment})
</insert>


useGeneratedKeys="true" 表示给主键设置自增长
keyProperty="userId"  表示将自增长后的Id赋值给实体类中的userId字段。

实体类中uerId 要有getter() and setter(); 方法

   




<think>我们正在使用MyBatis进行批量插入操作,并希望从SQL Server数据库中获取所有插入记录的主键值。在MyBatis中,我们通常使用`useGeneratedKeys`和`keyProperty`来获取自增主键。但在批量插入时,情况会复杂一些,因为需要为多个记录获取主键。根据引用[3]的内容,SQLServer的JDBC驱动在执行批量操作时,如果要获取自动生成的主键,通常需要在INSERT语句中使用OUTPUT子句。但是,MyBatis默认生成的批量插入语句并不包含OUTPUT子句,而且直接修改SQL语句来添加OUTPUT子句可能会很复杂,并且如果用户语句中已经包含OUTPUT子句,则无法再添加。然而,我们可以考虑以下方法:1.使用MyBatis的`@Options`注解或`<insert>`标签的`useGeneratedKeys`和`keyProperty`属性,并配合`@InsertProvider`或`<insert>`标签编写包含OUTPUT子句的SQL语句。2.使用SQLServer的SCOPE_IDENTITY()函数只能获取最后插入的标识值,不适用于批量插入。因此,我们需要使用OUTPUT子句来返回插入的多个主键。3.在MyBatis中,我们可以使用`<foreach>`标签来构建批量插入语句,并在其中使用OUTPUT子句。但是,需要注意的是,在SQL Server中,使用OUTPUT子句返回结果集时,不能直接将结果集映射到keyProperty。因此,我们需要调整Mapper接口和XML配置。具体步骤:步骤1:在Mapper接口中定义插入方法,返回值为插入主键列表(或影响的行数,但我们需要主键)。步骤2:在XML映射文件中编写INSERT语句,使用OUTPUT子句返回插入主键值。步骤3:由于MyBatis不支持直接将OUTPUT返回的结果集赋值给keyProperty,我们可以将结果集作为查询结果返回,然后在Mapper接口中接收。示例:假设我们有一个表`t_user`,主键为`id`(自增),其他字段为`name`。Mapper接口: ```javapublicinterface UserMapper {@Insert({"INSERT INTOt_user(name)","OUTPUT INSERTED.id","VALUES(#{name})"})@Options(useGeneratedKeys =true,keyProperty= "id")IntegerinsertUser(User user);//批量插入@InsertProvider(type =UserSqlProvider.class, method= "insertUsers")@Options(useGeneratedKeys =true,keyProperty= "ids")voidinsertUsers(@Param("list") List<User>users);} ```但是,上述单个插入可以工作,批量插入则不行。因为MyBatis默认的批量插入foreach并不支持OUTPUT子句返回多个主键并赋值给每个对象的属性。另一种做法是使用单独的SQL语句,在批量插入返回所有生成的主键,然后手动设置到对象中。但是,这需要我们在一个事务中执行,并且需要确保顺序。我们可以这样写批量插入:```xml<insert id="insertUsers"useGeneratedKeys="true"keyProperty="id">INSERTINTO t_user (name)OUTPUTINSERTED.idVALUES<foreachcollection="list"item="item"separator=",">(#{item.name})</foreach></insert> ```然而,在SQL Server中,上述语句在批量插入时使用OUTPUT子句并配合VALUES列表是允许的,它会返回所有插入的id。但是,MyBatis需要能够将这些id设置到每个对象的keyProperty(即id)属性中。但是,MyBatis在处理批量插入的keyProperty时,要求数据库驱动支持返回多个自增主键。SQLServer的JDBC驱动支持通过OUTPUT子句返回多个主键,而MyBatis从3.3.0版本开始支持批量插入返回自增主键(需要数据库驱动支持)。因此,我们可以尝试以下配置:在MyBatis的XML映射文件中:```xml<insert id="insertUsers"useGeneratedKeys="true"keyProperty="id">INSERT INTOt_user(name)VALUES<foreach collection="list" item="item" separator=",">(#{item.name})</foreach> </insert>```注意:这里并没有显式使用OUTPUT子句,因为MyBatis会自动处理?实际上,对于SQLServer,MyBatis会使用JDBC的getGeneratedKeys方法来获取主键,而JDBC驱动在内部可能会使用OUTPUT子句或SCOPE_IDENTITY(),但批量时通常使用OUTPUT。但是,根据引用[3]中的讨论,SQLServer的JDBC驱动在执行批量插入时,如果要获取生成的主键,需要在连接字符串中设置`useBulkCopyForBatchInsert=false`(默认是false),因为批量复制操作(BulkCopy)不支持返回生成的主键。因此,我们需要确保连接字符串中没有设置`useBulkCopyForBatchInsert=true`。同时,我们还需要注意,使用`<foreach>`拼接的批量插入数据量很大时可能会超出SQL语句的长度限制,此时可以考虑分批次插入。另外,如果使用MyBatis执行批量插入,还可以使用ExecutorType.BATCH来执行批量操作,但这种方式下,获取主键可能会遇到问题,因为JDBC的批处理操作在返回主键方面支持有限。所以,总结如下:方案1:使用foreach拼接单个INSERT语句(适用于数据量不是特别大的情况)```xml<insertid="insertUsers" useGeneratedKeys="true" keyProperty="id">INSERTINTO t_user (name)VALUES<foreach collection="list" item="item" separator=",">(#{item.name})</foreach> </insert>```方案2:使用ExecutorType.BATCH,并配合在INSERT语句中使用OUTPUT子句返回主键,然后在Mapper方法中返回主键列表,并手动设置到对象中(较为复杂)。由于方案1简单且常用,我们优先尝试方案1。但是,请注意:SQL Server对单个INSERT语句插入多行记录时,使用VALUES列表是有限制的(最多1000行)。如果超过,需要分批次插入。另外,确保SQLServer的JDBC驱动版本支持此功能(较新的驱动都支持)。如果使用方案1,在插入后,传入的List<User>中的每个User对象的id属性会被自动设置为对应的主键值。示例代码:UserMapper.xml: ```xml<mappernamespace="com.example.mapper.UserMapper"><insertid="insertUsers" useGeneratedKeys="true" keyProperty="id">INSERTINTO t_user (name)VALUES<foreachcollection="list"item="user" separator=",">(#{user.name})</foreach></insert> </mapper>```在Java中调用:```javaList<User>users =new ArrayList<>(); //添加多个User对象userMapper.insertUsers(users);//此时,每个User对象的id已经被设置```如果遇到问题,可能需要检查:1.数据库连接字符串中是否设置了`useBulkCopyForBatchInsert=true`,如果设置为true,则不会返回主键,需要改为false(或删除,因为默认是false)。2. SQLServer版本是否支持(SQLServer2008及以上支持一次插入多行)。3.主键必须是自增列。如果数据量很大,可以分批次插入,例如每次插入1000条。因此,对于用户的需求,推荐使用foreach拼接的方式,并设置useGeneratedKeys和keyProperty,同时确保JDBC驱动能够返回生成的主键(SQLServer JDBC驱动默认支持通过OUTPUT子句返回,但需要避免使用批量复制模式)。引用说明:引用[3]提到,直接修改用户语句添加OUTPUT子句是困难的,但MyBatis通过JDBC驱动的getGeneratedKeys方法内部处理了这个问题,因此我们不需要显式添加OUTPUT子句(除非特殊需求)。在MyBatis中,我们只需要配置useGeneratedKeys即可。但是,根据SQLServer JDBC驱动的文档,当使用批量插入(多个VALUES)时,驱动会自动使用OUTPUT子句来返回生成的主键。因此,我们按照方案1即可。注意:在MyBatis官方文档中,对于批量插入获取主键,有类似的示例:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#insert_update_and_delete文档中说明:“对于支持自动生成记录主键数据库(如 MySQL和SQL Server),设置useGeneratedKeys=”true”,然后把keyProperty设置为目标属性就 OK了。”因此,我们可以放心使用。但是,如果使用ExecutorType.BATCH(即SqlSession的批处理模式),则不能使用foreach拼接,而需要循环执行单个插入,此时也可以获取主键,但性能可能不如方案1(因为需要多次执行SQL)。所以,在数据量允许的情况下,方案1是首选。如果数据量非常大,可能需要考虑使用SQLServer的Bulk Copy,但BulkCopy不返回主键,所以需要其他方式生成主键(例如使用UUID,或者提前从序列获取一批主键值)。综上所述,我们给出如下解决方案:1.使用MyBatis的foreach标签拼接批量插入语句。2.在insert标签中设置useGeneratedKeys="true"和keyProperty="id"(假设对象的主键属性为id)。3.确保SQLServer JDBC驱动连接字符串中没有设置useBulkCopyForBatchInsert=true(因为这会禁用返回主键的功能)。4.如果数据量超过1000条,分批次插入(每批1000条)。代码示例:分批次插入的Java代码: ```javapublic voidbatchInsert(List<User> users) {intbatchSize=1000;for (int i=0;i <users.size(); i+= batchSize){List<User> batchList= users.subList(i,Math.min(i +batchSize, users.size()));userMapper.insertUsers(batchList);} }```这样,每个批次插入1000条,并且每个User对象的主键id会被正确设置。因此,回答用户问题:在使用MyBatis进行批量插入操作时,可以通过上述方案获取所有插入记录的主键值。</think>在使用 MyBatis 进行批量插入操作时,从 SQL Server 获取所有插入记录的主键值,可通过以下方案实现: ### 解决方案(基于 SQL Server 特性) #### 核心方法:使用 `OUTPUT` 子句 ```xml <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO target_table (column1, column2) OUTPUT INSERTED.id <!-- 返回插入主键值 --> VALUES <foreach collection="list" item="item" separator=","> (#{item.value1}, #{item.value2}) </foreach> </insert> ``` #### 关键步骤: 1. **Mapper 接口定义**: ```java List<Long> batchInsert(List<Entity> list); // 返回主键列表 ``` 2. **SQL 优化**: - 使用 `OUTPUT INSERTED.id` 子句直接返回主键 - 通过 `<foreach>` 拼接批量 VALUES 语句 - 单次插入量建议 ≤ 1000 条(避免超长 SQL) 3. **JDBC 连接配置**: ```properties jdbc.url=jdbc:sqlserver://...;useBulkCopyForBatchInsert=false ``` *必须关闭批量复制模式(否则无法返回主键)[^3]* #### 执行效果: ```java List<Long> ids = mapper.batchInsert(entityList); // ids 包含所有新生成的主键值 ``` ### 备选方案(分批次插入) ```java // 手动分批次提交(每批1000条) try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { for (int i = 0; i < list.size(); i++) { mapper.insertSingle(list.get(i)); if (i % 1000 == 0 || i == list.size() - 1) { session.commit(); // 触发主键获取 } } } ``` *需在单条插入语句中配置 `useGeneratedKeys="true"`* ### 注意事项: 1. **主键要求**: - 仅适用于 `IDENTITY` 自增主键或 `OUTPUT` 支持的列 - 非自增主键需提前生成主键值 2. **性能平衡**: - 大批量数据(>10万条)建议用 SQL Server 原生 `BULK INSERT` - 中等批量(1k~10万)用 `OUTPUT` 方案最优 3. **事务控制**: - 确保操作在事务内执行 - 批量失败时需回滚 > **SQL Server 限制**:`OUTPUT` 子句在包含 `TRIGGER` 的表上可能返回逻辑删除的伪记录,需测试验证[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕容屠苏

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值