多表插入操作——后端

2023-12-20 17:39:21

场景:当添加一个菜品时,还需要记录菜品的口味信息,因此需要对菜品表(dish)和口味表(dish_flavor)同时进行插入操作。
两个表的字段:
在这里插入图片描述
代码思路:由DishController将前端的请求派发给相应的业务层(DishService),业务层随后通过调用持久层(DishMapper,DishFlavorMapper)进行数据的增删改。
细节:

  1. 由于要操作两张表,所以需要在业务层的对应方法上添加@Transactional,保证该事务的原子性,见DishServiceImpl;
  2. 插入口味数据时,需要获取刚插入的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 {
    @Autowired
    private 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 {

    @Autowired
    private DishMapper dishMapper;

    @Autowired
    private DishFlavorMapper dishFlavorMapper;

    /**
     * 新增菜品和对应的口味
     * @param dishDTO
     */
    @Transactional // 操作多张表的时候,添加@Transactional注解,保证该事件是原子性的,要么全成功,要么全失败
    @Override
    public 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,为每个口味附上相关的dishId
            flavors.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>

文章来源:https://blog.csdn.net/Z__XY_/article/details/135109765
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。