近期在项目中用到了这些批量操作,记录一下自己对这些代码的理解。
第一种、批量插入数据表中没有主键(包括Mapper映射文件和映射接口)
1.1 Mapper.xml 映射文件 (此处示例使用的是oracle)
<mapper namespace="com.mxx.demo.mapper.DmDsVestRlatMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.mxx.demo.entity.DmDsVestRlatEntity">
<result column="DM_DS_ID" property="dmDsId" />
<result column="VEST_TYPE_CODE" property="vestTypeCode" />
</resultMap>
<!-- 增加数据集合和归属类型的关系(union all: 是把多个归属类型结果当作临时表并起来插入到数据库中) -->
<insert id="addDmDsVestRlatInfo" parameterType="list">
insert into DM_DS_VEST_RLAT (DM_DS_ID, VEST_TYPE_CODE)
<!--dmDsId和vestTypeCode都是DmDsVestRlatEntity实体中的属性值 -->
<foreach collection="list" item="item" index="index" separator="union all">
( select #{item.dmDsId}, #{item.vestTypeCode} from dual)
</foreach>
</insert>
</mapper>
1.2 Mapper接口如下:
public interface DmDsVestRlatMapper {
// @Param注解的值要和foreach中的collection属性值一致(也就是都要是此处写的list)
int addDmDsVestRlatInfo(@Param("list") List<DmDsVestRlatEntity> list);
}
foreach属性值简单解释(只是本人的理解,如有错误之处请指正):
- collection属性值要和接口方法中的@Param注解值一致;
- item:表示循环体中的具体对象(例:有个List<User`>,那么item就可以看作代表User对象,item.age就类似User.age );具体说明:在 list 和数组中item代表其中的对象,在 map 中是 value,该参数为必选。(它是每一个元素进行迭代时的别名)
- index:在 list 和数组中,index 是元素的序号;在 map 中,index 是元素的 key。
- separator:表示foreach中sql语句以什么作为分隔符;
- open:表示该语句以什么开始;open:表示该语句以什么开始;
- close:表示该语句以什么结束
第二种、批量插入数据不需要返回主键
1.1 Mapper.xml映射文件代码
<insert id="addDwDsDetail" parameterType="list">
insert into DW_DS_DETAIL (
ID,DW_DS_ID, DATA_ELE_ID, DATA_ELE_ORDER_FLAG)
select SEQ_DW_DS_DETAIL.NEXTVAL, cd.* from(
<foreach collection="list" item="item" index="index" separator="union all">
select
#{item.dwDsId},
#{item.dataEleId},
#{item.dataEleOrderFlag}
from dual
</foreach>
) cd
</insert>
1.2 Mapper映射接口方法
int addDwDsDetail(@Param("list") List<DwDsDetailEntity> list);
第三种、 一次新增一条数据,返回新插入的数据主键ID:
1.1 Mapper.xml映射文件代码(这种情况适合返回新插入的数据主键ID):
<!--Oracle数据库必须要使用 useGeneratedKeys、 keyProperty、selectKey 这3个属性,
Mysql数据库使用useGeneratedKeys、 keyProperty即可-->
<insert id="addDmDsInfo" parameterType="com.mxx.demo.entity.DmDsMgrEntity"
useGeneratedKeys="true" keyProperty="id">
<!-- 获取序列值,并赋值到对象的id字段,此处是用oracle进行的操作 -->
<selectKey keyProperty="id" order="BEFORE" resultType="Long" keyColumn="id">
SELECT SEQ_DM_DS_MGR.nextval from dual
</selectKey>
insert into DM_DS_MGR
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="id != null and id != '' ">ID,</if>
<if test="dsEnglishName != null and dsEnglishName != '' ">DS_ENGLISH_NAME,</if>
<if test="dsChineseName != null and dsChineseName != '' ">DS_CHINESE_NAME,</if>
<if test="dsChineseNamePym != null and dsChineseNamePym != '' ">DS_CHINESE_NAME_PYM,</if>
<if test="createDate != null">CREATE_DATE,</if>
<if test="createUserId != null and createUserId != '' ">CREATE_USER_ID</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="id != null and id != '' ">#{id},</if>
<if test="dsEnglishName != null and dsEnglishName != '' ">#{dsEnglishName},</if>
<if test="dsChineseName != null and dsChineseName != '' ">#{dsChineseName},</if>
<if test="dsChineseNamePym != null and dsChineseNamePym != '' ">#{dsChineseNamePym},</if>
<if test="createDate != null ">SYSDATE,</if>
<if test="createUserId != null and createUserId != '' ">#{createUserId}</if>
</trim>
</insert>
1.2 Mapper映射接口方法 :
public interface DmDsMgrMapper {
int addDmDsInfo(DmDsMgrEntity entity);
}
1.3 service层调用mapper层方法后如何获取主键ID值
// 假设已经将Mapper接口dmDsMgrMapper注入到service层了
public ResultMessage addDmDsInfo(DmDsMgrEntity entity) {
// 主键ID在配置文件中指定了为INPUT模式,此处不用关注ID的值
/**
*主键类型 AUTO:"数据库ID自增",
* INPUT:"用户输入ID",
* ID_WORKER:"全局唯一ID (数字类型唯一ID)",
* UUID:"全局唯一ID *UUID";
* -- mybatis-plus.global-config.db-config.id-type=INPUT
* -- mybatis-plus.global-config.db-config.db-type=ORACLE
*/
int addDmDsNum = dmDsMgrMapper.addDmDsInfo(entity);
// 当mapper层方法执行成功后我们直接用entity.getId()就可以取到新增数据的主键ID了
System.out.println("返回的主键 :"+ entity.getId() );
}
第四种、 批量插入数据后批量返回主键
注:批量插入数据后利用mybatis返回主键这个操作对数据库有两点要求:
(1)数据库主键值为自增类型;
(2)数据库提供的jdbc驱动要支持返回批量插入的主键值;
到目前为止能完美支持以上2点要求的仅有mysql数据库,mysql中支持主键自增,oracle通过序列来维护主键 不符合上述的第一点要求,所以mysql数据库支持使用mybatis批量插入数据后批量返回主键,而oracle等其他数据库需要其他方法才能实现。
一. mysql支持批量插入数据批量返回主键:
1.1 Mapper接口类: (mysql返回主键示例)
num addUser(@Param("list") List<User> list);
1.2 Mapper.xml文件
<!-- sql中不用写id -->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into 表名 (user_name, user_password, user_email) values
<foreach collection="list" item="item" separator=",">
(#{item.userName}, #{item.userPassword},#{item.userEmail})
</foreach >
</insert>
1.3 service层调用此方法后获取新增的主键
public void addUser() {
List<User> list = new ArrayList<User>();
for(int i = 0; i < 2; i++) {
User user = new User();
user.setUserName("test"+i);
user.setUserPassword(i);
user.setUserEmail("XXXX");
list.add(user);
}
int num = userMapper.addUser(list);
for(User user : list) {
// 会循环打印出返回的主键
System.out.println(user.getId());
}
}
二. oracle通过mybatis无法批量返回主键需要通过其他方法返回
方法一:先单独调用序列获取主键,把主键值塞到相应的实体类中,再进行批量insert操作;
方法二:通过for循环在程序中遍历插入,这样每次可以单独获取主键(适合小批量数据);
附 :
mysql批量新增数据sql:
insert into 表名(name, password, email)
values ('AA', '123', '0000'),('BB', '456', '1111'),...
Oracle批量新增数据sql:
未涉及表主键:
insert into 表名(name, password, email)
select 'AA', '123', '0000' from dual union all
select 'BB', '456', '1111' from dual
或
涉及表主键:
insert into 表名(id,name, password)
selecy seq_user.nextval,a.* from
(select 'AA', '123' from dual union all
select 'BB', '456' from dual) a
若有错误和不足请指正~~~