mybatis中批量操作的彙總整理
在我們實際開發過程中,免不了會碰到要批量操作資料的情況,如果在程式碼中進行迴圈操作的話,由於跟資料庫連線次數過多會導致效率低下,影響效能,這個時候應用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;
}
}