在我们实际开发过程中,免不了会碰到要批量操作数据的情况,如果在代码中进行循环操作的话,由于跟数据库连接次数过多会导致效率低下,影响性能,这个时候应用mybatis进行批量操作就很重要了,这篇文章的目的主要为了对mybatis中的批量操作做一个整理,包括删除,更新,插入。
目录
测试建表,插入数据如下:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for ins_orbit_point
-- ----------------------------
DROP TABLE IF EXISTS `ins_orbit_point`;
CREATE TABLE `ins_orbit_point` (
`point_id` bigint(20) NOT NULL COMMENT '巡查点id',
`orbit_id` bigint(20) NOT NULL COMMENT '巡查轨迹id',
`point_type` int(2) NOT NULL COMMENT '巡查点类型(1开始点,2中间点,3结束点)',
`point_sort` int(10) NOT NULL COMMENT '巡查点在轨迹中的实际顺序'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '巡查轨迹与巡查点关联表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of ins_orbit_point
-- ----------------------------
INSERT INTO `ins_orbit_point` VALUES (359, 1, 1, 1);
INSERT INTO `ins_orbit_point` VALUES (360, 1, 2, 2);
INSERT INTO `ins_orbit_point` VALUES (361, 1, 3, 3);
INSERT INTO `ins_orbit_point` VALUES (362, 2, 1, 1);
INSERT INTO `ins_orbit_point` VALUES (363, 2, 2, 2);
INSERT INTO `ins_orbit_point` VALUES (364, 2, 2, 3);
INSERT INTO `ins_orbit_point` VALUES (366, 2, 2, 4);
INSERT INTO `ins_orbit_point` VALUES (366, 2, 3, 5);
INSERT INTO `ins_orbit_point` VALUES (359, 11, 3, 1);
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for ins_orbit
-- ----------------------------
DROP TABLE IF EXISTS `ins_orbit`;
CREATE TABLE `ins_orbit` (
`orbit_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
`start_point_id` bigint(20) NOT NULL COMMENT '轨迹开始点id',
`end_point_id` bigint(20) NULL DEFAULT NULL COMMENT '轨迹结束点id',
`is_end` int(2) NOT NULL COMMENT '是否结束(1是,0否)',
`ins_date` date NOT NULL COMMENT '巡查日期',
`insor_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '巡查人id',
`ins_orb_distance` decimal(5, 3) NULL DEFAULT NULL COMMENT '里程,单位km',
`ins_orb_spending` decimal(5, 3) NULL DEFAULT NULL COMMENT '花费时间,单位小时',
`ins_orb_speed` decimal(5, 3) NULL DEFAULT NULL COMMENT '速度,单位km/h',
`start_time` timestamp(0) NULL DEFAULT NULL COMMENT '开始时间',
`end_time` timestamp(0) NULL DEFAULT NULL COMMENT '结束时间',
`park_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '项目id',
`dept_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门id',
PRIMARY KEY (`orbit_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '巡查轨迹表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of ins_orbit
-- ----------------------------
INSERT INTO `ins_orbit` VALUES (1, 359, 361, 1, '2018-11-09', '2e636fc47624493aa1056c6ed9e8f168', 10.000, 6.000, 1.650, '2018-11-08 09:22:54', '2018-11-08 15:23:11', 'af98a32c9b4d490297cadc2d85faf797', '74c6071187dd44d68eac5b7a295f65fd');
INSERT INTO `ins_orbit` VALUES (2, 362, 366, 0, '2018-11-09', '2e636fc47624493aa1056c6ed9e8f168', 10.000, 7.000, 2.000, '2018-11-08 08:25:26', '2018-11-08 15:25:35', 'af98a32c9b4d490297cadc2d85faf797', '74c6071187dd44d68eac5b7a295f65fd');
INSERT INTO `ins_orbit` VALUES (11, 359, 359, 0, '2018-11-09', '11111', 12.000, 22.000, 22.000, '2018-11-09 15:44:44', '2018-11-09 15:44:47', '111', '1111');
SET FOREIGN_KEY_CHECKS = 1;
1.批量删除,插入
批量插入跟批量插入的原理是一样的,主要用到的就是foreach循环处理。
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。item表示集合中每一个元素进行迭代时的别名,index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔 符,close表示以什么结束,在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况:
1. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3. 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在breast里面也 是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map 里面的key
以上面的轨迹表为例,批量删除跟插入的代码如下:
批量插入:
<insert id="insert" parameterType="com.pcos.inspection.insorbit.entity.InsOrbit">
insert into ins_orbit (orbit_id, start_point_id, end_point_id,
is_end, ins_date, insor_id,
ins_orb_distance, ins_orb_spending, ins_orb_speed,
start_time, end_time, park_id, dept_id
)
values
<foreach collection="list" item="item" separator=",">
(
#{item.orbitId,jdbcType=BIGINT},
#{item.startPointId,jdbcType=BIGINT},
#{item.endPointId,jdbcType=BIGINT},
#{item.isEnd,jdbcType=INTEGER},
#{item.insDate,jdbcType=DATE},
#{item.insorId,jdbcType=VARCHAR},
#{item.insOrbDistance,jdbcType=DECIMAL},
#{item.insOrbSpending,jdbcType=DECIMAL},
#{item.insOrbSpeed,jdbcType=DECIMAL},
#{item.startTime,jdbcType=TIMESTAMP},
#{item.endTime,jdbcType=TIMESTAMP},
#{item.parkId,jdbcType=VARCHAR},
#{item.deptId,jdbcType=VARCHAR}
)
</foreach>
</insert>
转换为sql如下:
INSERT INTO ins_orbit (
orbit_id,
start_point_id, end_point_id,
is_end, ins_date, insor_id, ins_orb_distance,
ins_orb_spending, ins_orb_speed, start_time,
end_time, park_id, dept_id )
VALUES
( ?,?,?,?,?,?,?,?,?,?,?,?,? ),
( ?,?,?,?,?,?,?,?,?,?,?,?,? ),
( ?,?,?,?,?,?,?,?,?,?,?,?,? )
可以看到,实际上mybatis就是做了字符串的拼接。批量删除跟插入的代码差不多,就是将插入语句改成了删除语句而已
在了解了批量插入后,我们可以反过来推断批量删除的mybatis写法。
首先,如果要我们在数据库中一次删除多条数据我们会怎么写呢?为了方便,我们以主键为基准进行删除,sql如下:
DELETE from ins_orbit where orbit_id in (2,1,11);
现在问题就很简单了,只要用foreach拼接成in后面这个字符串就行了,很明显前缀open = "(",后缀close=")",分隔符=","
如下:
<delete id="deleteBatch">
delete from ins_orbit where
orbit_id
in
<foreach collection="list" separator="," open="(" close=")" item="item">
#{item}
</foreach>
</delete>
2.批量更新
由于作者这里表数据比较复杂,推荐一个批量更新链接https://blog.csdn.net/xyjawq1/article/details/74129316
批量更新比插入及删除要稍微麻烦一些,这里我先将需求说一下,还是上面那两站表,我需要批量更新数据,将ins_prbit中is_end为0的数据改为1,同时需要将ins_orbit_point表中对应数据(一条轨迹上会有多个点),也就是轨迹上的最后一个点置为结束点(point_type = 3)。
批量更新轨迹表(ins_orbit)如下:
<update id="updateBatch">
update ins_orbit
set
is_end = 1
where orbit_id in
<foreach collection="list" item="item" separator="," open="(" close=")">
#{item.orbitId,jdbcType=BIGINT}
</foreach>
</update>
批量更新轨迹途径点表如下:
<update id="updateBatch">
update ins_orbit_point t1
set
point_type = 3
<where>
t1.orbit_id in
<foreach collection="list" item="item" separator="," open="(" close=")">
#{item.orbitId,jdbcType=BIGINT}
</foreach>
and
<foreach collection="list" item="item" separator=" " open="case orbit_id" close="end">
when #{item.orbitId,jdbcType=BIGINT}
then t1.point_id = #{item.pointId,jdbcType=BIGINT}
</foreach>
and
<foreach collection="list" item="item" separator=" " open="case orbit_id" close="end">
when #{item.orbitId,jdbcType=BIGINT}
then t1.point_sort = (select t3.sort from
(select max(point_sort) as sort from ins_orbit_point t2 where t2.orbit_id = #{item.orbitId,jdbcType=BIGINT})
t3)
</foreach>
</where>
</update>
dao层代码如下:
public interface InsOrbitPointDao {
/**
* 批量更新
*
* @param insOrbitPoints
*/
void updateBatch(List<InsOrbitPoint> insOrbitPoints);
}
public interface InsOrbitDao extends OVUBaseDao<InsOrbit, Long> {
/**
* 批量更新
*
* @param list
*/
void updateBatch(List<InsOrbit> list);
}
实体类如下:
public class InsOrbit {
/**
* 主键,自增
*/
private Long orbitId;
/**
* 轨迹开始点id
*/
private Long startPointId;
/**
* 轨迹结束点id
*/
private Long endPointId;
/**
* 是否结束(1是,0否)
*/
private Integer isEnd;
/**
* 巡查日期
*/
private Date insDate;
/**
* 巡查人id
*/
private String insorId;
/**
* 里程,单位km
*/
private BigDecimal insOrbDistance;
/**
* 花费时间,单位小时
*/
private BigDecimal insOrbSpending;
/**
* 速度,单位km/h
*/
private BigDecimal insOrbSpeed;
/**
* 开始时间
*/
private Date startTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 项目id
*/
private String parkId;
/**
* 部门id
*/
private String deptId;
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public Long getOrbitId() {
return orbitId;
}
public void setOrbitId(Long orbitId) {
this.orbitId = orbitId;
}
public Long getStartPointId() {
return startPointId;
}
public void setStartPointId(Long startPointId) {
this.startPointId = startPointId;
}
public Long getEndPointId() {
return endPointId;
}
public void setEndPointId(Long endPointId) {
this.endPointId = endPointId;
}
public Integer getIsEnd() {
return isEnd;
}
public void setIsEnd(Integer isEnd) {
this.isEnd = isEnd;
}
public Date getInsDate() {
return insDate;
}
public void setInsDate(Date insDate) {
this.insDate = insDate;
}
public String getInsorId() {
return insorId;
}
public void setInsorId(String insorId) {
this.insorId = insorId;
}
public BigDecimal getInsOrbDistance() {
return insOrbDistance;
}
public void setInsOrbDistance(BigDecimal insOrbDistance) {
this.insOrbDistance = insOrbDistance;
}
public BigDecimal getInsOrbSpending() {
return insOrbSpending;
}
public void setInsOrbSpending(BigDecimal insOrbSpending) {
this.insOrbSpending = insOrbSpending;
}
public BigDecimal getInsOrbSpeed() {
return insOrbSpeed;
}
public void setInsOrbSpeed(BigDecimal insOrbSpeed) {
this.insOrbSpeed = insOrbSpeed;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getParkId() {
return parkId;
}
public void setParkId(String parkId) {
this.parkId = parkId;
}
}
public class InsOrbitPoint {
/**
* 巡查点id
*/
private Long pointId;
/**
* 巡查轨迹id
*/
private Long orbitId;
/**
* 巡查点类型(1开始点,2中间点,3结束点)
*/
private Integer pointType;
/**
* 巡查点在轨迹中的实际顺序
*/
private Integer pointSort;
public Long getPointId() {
return pointId;
}
public void setPointId(Long pointId) {
this.pointId = pointId;
}
public Long getOrbitId() {
return orbitId;
}
public void setOrbitId(Long orbitId) {
this.orbitId = orbitId;
}
public Integer getPointType() {
return pointType;
}
public void setPointType(Integer pointType) {
this.pointType = pointType;
}
public Integer getPointSort() {
return pointSort;
}
public void setPointSort(Integer pointSort) {
this.pointSort = pointSort;
}
}