多表插入、删除操作(批量)——后端
多表插入
场景:当添加一个菜品时,还需要记录菜品的口味信息,因此需要对菜品表(dish)和口味表(dish_flavor)同时进行插入操作。
两个表的字段:
代码思路:由DishController将前端的请求派发给相应的业务层(DishService),业务层随后通过调用持久层(DishMapper,DishFlavorMapper)进行数据的增删改。
细节:
- 由于要操作两张表,所以需要在业务层的对应方法上添加@Transactional,保证该事务的原子性,见DishServiceImpl;
- 插入口味数据时,需要获取刚插入的dish_id值,通过设置useGeneratedKeys实现,见DishMapper.xml;
代码(由上至下):
控制层:
DishController
package com.sky.controller.admin;import com.sky.dto.DishDTO;
import com.sky.result.Result;
import com.sky.service.DishService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** ClassName: DishController* PackageName: com.sky.controller.admin* Description: 菜品管理** @Author Xiyan Zhong* @Create 2023/12/20 下午2:19* @Version 1.0*/@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {@Autowiredprivate DishService dishService;/*** 新增菜品* @param dishDTO* @return*/@PostMapping@ApiOperation("新增菜品")public Result save(@RequestBody DishDTO dishDTO){log.info("新增菜品:{}",dishDTO);dishService.saveWithFlavor(dishDTO);return Result.success();}}
业务层:
DishService:
package com.sky.service;import com.sky.dto.DishDTO;/*** ClassName: DishService* PackageName: com.sky.service* Description:** @Author Xiyan Zhong* @Create 2023/12/20 下午2:23* @Version 1.0*/public interface DishService {/*** 新增菜品和对应的口味* @param dishDTO*/public void saveWithFlavor(DishDTO dishDTO);
}
DishServiceImpl:
package com.sky.service.impl;import com.sky.dto.DishDTO;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.mapper.DishFlavorMapper;
import com.sky.mapper.DishMapper;
import com.sky.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;/*** ClassName: DishServiceImpl* PackageName: com.sky.service.impl* Description:** @Author Xiyan Zhong* @Create 2023/12/20 下午2:25* @Version 1.0*/@Service
@Slf4j
public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;@Autowiredprivate DishFlavorMapper dishFlavorMapper;/*** 新增菜品和对应的口味* @param dishDTO*/@Transactional // 操作多张表的时候,添加@Transactional注解,保证该事件是原子性的,要么全成功,要么全失败@Overridepublic void saveWithFlavor(DishDTO dishDTO) {Dish dish = new Dish();// 在属性拷贝时,注意属性命名要保持一致BeanUtils.copyProperties(dishDTO, dish);// 向菜品表插入1条数据dishMapper.insert(dish);// 获取insert语句生成的主键值Long dishId = dish.getId();List<DishFlavor> flavors = dishDTO.getFlavors();if(flavors != null && flavors.size() > 0){//遍历flavors,为每个口味附上相关的dishIdflavors.forEach(dishFlavor -> {dishFlavor.setDishId(dishId);});// 向口味表插入n条数据dishFlavorMapper.insertBatch(flavors);}}
}
需要注意的是,为了保证@Transactional有效,需要在当前项目的入口类添加@EnableTransactionManagement,启动注解方式的事务管理,如:
package com.sky;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
public class SkyApplication {public static void main(String[] args) {SpringApplication.run(SkyApplication.class, args);log.info("server started");}
}
持久层:
DishMapper 接口
package com.sky.mapper;import com.sky.annotation.AutoFill;
import com.sky.entity.Dish;
import com.sky.enumeration.OperationType;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;/*** ClassName: DishMapper* PackageName: com.sky.mapper* Description:** @Author Xiyan Zhong* @Create 2023/12/15 下午2:52* @Version 1.0*/@Mapper
public interface DishMapper {/*** 根据分类id查询菜品数量* @param categoryId* @return*/@Select("select count(id) from dish where category_id = ${categoryId}")Integer countByCategoryId(Long categoryId);/*** 插入菜品数据* @param dish*/@AutoFill(value = OperationType.INSERT)void insert(Dish dish);
}
DishMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper"><!--设置useGeneratedKeys="true" 表示需要获得插入数据后生成的主键值,返回到keyProperty="id",即Dish对象中的id属性--><insert id="insert" parameterType="Dish" useGeneratedKeys="true" keyProperty="id">insert into dish (name, category_id, price, image, description, create_time, update_time, create_user, update_user, status)values(#{name}, #{categoryId}, #{price}, #{image}, #{description}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser},#{status})</insert></mapper>
DishFlavorMapper 接口
package com.sky.mapper;import com.sky.entity.DishFlavor;
import org.apache.ibatis.annotations.Mapper;import java.util.List;/*** ClassName: DishFlavorMapper* PackageName: com.sky.mapper* Description:** @Author Xiyan Zhong* @Create 2023/12/20 下午2:42* @Version 1.0*/
@Mapper
public interface DishFlavorMapper {/*** 批量插入口味数据* @param flavors*/void insertBatch(List<DishFlavor> flavors);
}
DishFlavorMapper.xml
遍历插入多条数据
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishFlavorMapper"><!--通过遍历插入多条数据--><insert id="insertBatch" parameterType="DishFlavor">insert into dish_flavor (dish_id, name, value)values<foreach collection="flavors" item="df" separator=",">(#{df.dishId},#{df.name},#{df.value})</foreach></insert>
</mapper>
多表删除
场景:当删除一个菜品时,不仅要删除菜品表中的数据,同时也要删除口味表中对应数据和菜品与分类表中的数据。
相关表的关系:
代码思路:由DishController将前端的请求派发给相应的业务层(DishService),业务层随后通过调用持久层(DishMapper,DishFlavorMapper,SetmealDishMapper)进行数据的增删改。
细节:
- 由于要操作三张表,同样需要在业务层的对应方法上添加@Transactional,保证该事务的原子性,见DishServiceImpl;
- 删除菜品数据时,需要完成以下业务操作:
- 判断当前菜品是否能够删除——是否存在起售中
- 判断当前菜品是否能够删除——是否被套餐关联
- 删除菜品表中的菜品数据
- 删除菜品关联的口味数据
代码(由上至下):
DishController
@DeleteMapping@ApiOperation("菜品删除")// 通过@RequestParam解析前端请求地址中字符串参数ids=1,2,3...为一个列表public Result delete(@RequestParam List<Long> ids){log.info("菜品批量删除:{}",ids);dishService.deleteBatch(ids);return Result.success();}
DishService
/*** 菜品的批量删除* @param ids*/void deleteBatch(List<Long> ids);
DishServiceImpl
/*** 菜品的批量删除** @param ids*/@Transactional // 保证事务的原子性@Overridepublic void deleteBatch(List<Long> ids) {// 判断当前菜品是否能够删除——是否存在起售中for (Long id : ids) {Dish dish = dishMapper.getById(id);if (dish.getStatus() == StatusConstant.ENABLE) {throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);}}// 判断当前菜品是否能够删除——是否被套餐关联List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);if (setmealIds != null && setmealIds.size() > 0) {// 当前菜品被套餐关联了,不能删除throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);}// 删除菜品表中的菜品数据/*for (Long id : ids) {dishMapper.deleteById(id);// 删除菜品关联的口味数据dishFlavorMapper.deleteByDishId(id);}*/// sql: delete from dish where id in (?,?,?)// 根据菜品id集合批量删除菜品数据dishMapper.deleteByIds(ids);// 根据菜品id集合批量删除口味数据dishFlavorMapper.deleteByDishIds(ids);}
SetmealDishMapper提供查询操作
SetmealDishMapper
package com.sky.mapper;import org.apache.ibatis.annotations.Mapper;import java.util.List;/*** ClassName: SetmealDishMapper* PackageName: com.sky.mapper* Description:** @Author Xiyan Zhong* @Create 2023/12/20 下午7:29* @Version 1.0*/@Mapper
public interface SetmealDishMapper {/*** 根据菜品id查询对应的套餐id* @param dishIds* @return*/List<Long> getSetmealIdsByDishIds(List<Long> dishIds);}
SetmealDishMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.SetmealDishMapper"><!--对应sql语句:select setmeal_id from setmeal_dish where dish_id in (?,?,?)--><select id="getSetmealIdsByDishIds" resultType="java.lang.Long">select setmeal_id from setmeal_dish where dish_id in<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">#{dishId}</foreach></select>
</mapper>
其中分别实现了单个、批量删除操作
DishMapper
/*** 根据主键删除菜品数据* @param id*/@Delete("delete from dish where id = #{id}")void deleteById(Long id);/*** 根据菜品id集合批量删除菜品* @param ids*/void deleteByIds(List<Long> ids);
DishMapper.xml
<delete id="deleteByIds">delete from dish where id in<foreach collection="ids" open="(" close=")" separator="," item="id">#{id}</foreach></delete>
DishFlavorMapper
/*** 根据菜品id删除对应的口味数据* @param dishId*/@Delete("delete from dish_flavor where dish_id = #{dishId}")void deleteByDishId(Long dishId);/*** 据菜品id批量删除对应的口味数据* @param dishIds*/void deleteByDishIds(List<Long> dishIds);
DishFlavorMapper.xml
<delete id="deleteByDishIds">delete from dish_flavor where dish_id in<foreach collection="dishIds" open="(" close=")" separator="," item="dishId">#{dishId}</foreach></delete>
相关文章:

多表插入、删除操作(批量)——后端
多表插入 场景:当添加一个菜品时,还需要记录菜品的口味信息,因此需要对菜品表(dish)和口味表(dish_flavor)同时进行插入操作。 两个表的字段: 代码思路:由DishControll…...
Java操作Word修订功能:启用、接受、拒绝、获取修订
Word的修订功能是一种在文档中进行编辑和审阅的功能。它允许多个用户对同一文档进行修改并跟踪这些修改,以便进行审查和接受或拒绝修改。修订功能通常用于团队合作、专业编辑和文件审查等场景。 本文将从以下几个方面介绍如何使用免费工具Free Spire.Doc for Java在…...

什么是数据仪表板?数据可视化仪表盘怎么制作?
在数据经济时代,分析数据是每个企业做出最佳决策的关键。但是,手动分析和解释大量数据是不可行的。数据可视化对于分析数据中存在的各种有价值信息至关重要,包括可见趋势和隐藏趋势等。仪表盘显示可视化趋势和信息,例如 KPI、趋势…...
HiveServer2
HiveServer2 基本概念介绍 1、HiveServer2基本介绍 HiveServer2 (HS2) is a server interface that enables remote clients to execute queries against Hive and retrieve the results (a more detailed intro here). The current implementation, based on Thrift RPC, i…...

YOLOv8改进 | 2023注意力篇 | HAttention(HAT)超分辨率重建助力小目标检测 (全网首发)
一、本文介绍 本文给大家带来的改进机制是HAttention注意力机制,混合注意力变换器(HAT)的设计理念是通过融合通道注意力和自注意力机制来提升单图像超分辨率重建的性能。通道注意力关注于识别哪些通道更重要,而自注意力则关注于图…...

IDEA Community html文件里的script标签没有syntax highlighting的解决方案
在网上找到的解决方法有的是针对Ultimate版本才可以下载的plugin,对我所用的Community版本无法生效,找了一圈最后在stackoverflow上找到一个有效的方案,给需要的小伙伴分享一下:IntelliJ Community Edition: Javascript syntax hi…...
如何获取旧版 macOS
识别机型支持的最新的兼容操作系统 识别 MacBook Air - 官方 Apple 支持 (中国) 社区网站:AppStore 无法找到macos cata… - Apple 社区 官网链接隐藏比较深:如何下载和安装 macOS - 官方 Apple 支持 (中国) 获取磁盘映像 Lion 10.7 https://update…...

vp与vs联合开发-Ini配置文件
1.*.ini文件是Initialization file的缩写,即为初始化文件,是Windows系统配置文件所采用的存储格式,统管Windows的各项配置, 2.可以用来存放软件信息、注册表信息等 3.可以使用代码方式和手动编辑操作 ,一般不用直接编辑…...

Ethernet/IP 之IO 连接简要记录
IO连接 EIP的IO连接提供了在一个生产者和多个消费者之间的特定的通信路径,以达到IO数据在IO连接下传输。 生产者对象产生IO数据通过生产者IO连接管理者对象将连接ID和数据组帧发送给消费者IO连接管理者对象然后将IO数据发送给消费者对象。 显示消息连接 显式消息传…...

【python基础】-- yarn add 添加依赖的各种类型
目录 1、安装 yarn 1.1 使用npm安装 1.2 查看版本 1.3 yarn 淘宝源配置 2、安装命令说明 2.1 yarn add(会更新package.json和yarn.lock) 2.2 yarn install 2.3 一些操作 2.3.1 发布包 2.3.2 移除一个包 2.3.3 更新一个依赖 2.3.4 运行脚本 …...
@Autowired搭配@interface注解实现策略模式
应用场景:存在银行卡和社保卡的支付、退货等接口,接口报文中使用transWay表示银行卡(0)和社保卡(1),transType表示支付(1)、退货(2)。那么由其组合…...
Linux CentOS下Composer简单使用
1.下载composer-setup.php cd /usr/local/src php -r “copy(‘https://install.phpcomposer.com/installer’, ‘composer-setup.php’);”2.安装composer php composer-setup.php3.设置全局composer cp composer.phar /usr/local/bin/composer4.设置国内镜像 composer co…...

Mysql-干净卸载教程
卸载 服务停掉 先把mysql服务停掉,如下点击右键,停止运行。 删除C盘内文件 接下来c盘里面的三个文件下的MySQL一一删除,需要注意的是 需要注意的是programdata文件下可能 隐藏了MySQL文件,所以可以在查看选项显示隐藏的文件。 …...

纵横字谜的答案 Crossword Answers
纵横字谜的答案 Crossword Answers - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 翻译后大概是: 有一个 r 行 c 列 (1<r,c<10) 的网格,黑格为 * ,每个白格都填有一个字母。如果一个白格的左边相邻位置或者上边相邻位置没有白格&…...

cpp_04_类_对象_this指针_常对象_常(成员)函数
1 类 1.1 类的定义 类的作用是抽象事物(抽取事物特征)的规则。 类的外化表现是用户自定义的复合数据类型(包括成员变量、成员函数): 成员变量用于表达事物的属性,成员函数用于表达事物的行为。 类的表现…...

AttributeError: module ‘_winapi‘ has no attribute ‘SYNCHRONIZE‘解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

多媒体互动橱窗设计如何改变内容展示形式?
橱窗设计在展品展示中扮演着举足轻重的角色,它相较于传统展示形式,能更直观地呈现展品效果,而且优质的橱窗设计还能提升品牌的产品形象,正因此,也被广泛应用于企业、博物馆、店铺等场所。随着多媒体技术的蓬勃发展和行…...

flutter自定义地图Marker完美展示图片
世人都说雪景美 寒风冻脚无人疼 只道是一身正气 结论 参考Flutter集成高德地图并添加自定义Maker先实现自定义Marker。如果自定义Marker中用到了图片,那么会碰到图片没有被绘制到Marker的问题,此时需要通过precacheImage来预加载图片,从而解…...
no module named cv2 、numpy 、xxx超全解决方案
常规解决方案可见博客: https://blog.csdn.net/ALiLiLiYa/article/details/126988014 案例 上述仍没有解决,可以参考如下进行: 例如:明明文件夹存在下述文件,仍然报错。那么可能缺少环境变量导致。 No module named …...

BSWM 模式管理(二)ESH
BSWM 模式管理 ESH 1 ECU State Handling (ESH)2 BSWM ESH 五大模式与六大通用状态机3 状态机对应的切换条件 conditions or rules4 默认主要的 ACTION 或者 ACTION LIST1 ECU State Handling (ESH) 与 ECUM 相关,整个 ECU 状态管理的状态机制 2 BSWM ESH 五大模式与六大通…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...