多表插入、删除操作(批量)——后端
多表插入
场景:当添加一个菜品时,还需要记录菜品的口味信息,因此需要对菜品表(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 五大模式与六大通…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

Linux基础开发工具——vim工具
文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...