Day4 商品管理

embedded/2024/9/24 20:52:35/

Day4 商品管理

这里会总结构建项目过程中遇到的问题,以及一些个人思考!!

学习方法:

1 github源码 + 文档 + 官网

2 内容复现 ,实际操作

项目源码同步更新到github 欢迎大家star~ 后期会更新并上传前端项目

编写品牌服务

java">/*** Brand service 实现common中的类** @author bootsCoder* @date created on 2024/4/15*/
@DubboService
@Transactional
public class BrandServiceImpl implements BrandService {@Autowiredprivate BrandMapper brandMapper;/*** 根据id查询品牌* @param id* @return*/@Overridepublic Brand findById(Long id) {if (id == 0){int i = 1/0; // 模拟系统异常}else if(id == -1){throw new MyException(ResultCode.PARAMETER_ERROR); // 模拟业务异常}return brandMapper.selectById(id);}@Overridepublic List<Brand> findAll() {return brandMapper.selectList(null);}@Overridepublic void add(Brand brand) {brandMapper.insert(brand);}@Overridepublic void update(Brand brand) {brandMapper.updateById(brand);}@Overridepublic void delete(Long id) {brandMapper.deleteById(id);}@Overridepublic Page<Brand> search(Brand brand, int page, int size) {QueryWrapper<Brand> queryWrapper = new QueryWrapper();// 判断品牌名是否为空if (brand != null && StringUtils.hasText(brand.getName())){queryWrapper.like("name",brand.getName());}Page page1 = brandMapper.selectPage(new Page(page, size), queryWrapper);return page1;}
}

Brand 完成

商品类型

java">
@DubboService
@Transactional
public class ProductTypeServiceImpl implements ProductTypeService {@Autowiredprivate ProductTypeMapper productTypeMapper;@Overridepublic void add(ProductType productType) {// 根据父类型id查询父类型ProductType productTypeParent = productTypeMapper.selectById(productType.getParentId());// 根据父类型的级别,来设置当前类型的级别if (productTypeParent == null){ // 如果没有父类型,则为1级类型productType.setLevel(1);} else if (productTypeParent.getLevel() < 3) { // 如果父类型级<3 则级别为父级别+1productType.setLevel(productTypeParent.getLevel() + 1);} else if (productTypeParent.getLevel() == 3){ // 如果父类型级=3 则不能添加子级别throw new MyException(ResultCode.INSERT_PRODUCT_TYPE_ERROR);}productTypeMapper.insert(productType);}
}
image-20240418202927525

image-20240418203000901

商品规格项

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bootscoder.shopping_goods_service.mapper.SpecificationMapper"><resultMap id="specificationMapper" type="com.bootscoder.shopping_common.pojo.Specification"><id property="id" column="bid"></id><result property="specName" column="specName"></result><result property="productTypeId" column="productTypeId"></result><collection property="specificationOptions" column="specId" ofType="com.bootscoder.shopping_common.pojo.SpecificationOption"><id property="id" column="oid"></id><result property="optionName" column="optionName"></result><result property="specId" column="specId"></result></collection></resultMap><select id="findById" parameterType="long" resultMap="specificationMapper">SELECTboots_specification.id AS bid,boots_specification.specName,boots_specification.productTypeId,boots_specification_option.id AS oid,boots_specification_option.optionName,boots_specification_option.specIdFROMboots_specificationLEFT JOIN boots_specification_optionON boots_specification.id = boots_specification_option.specIdWHEREboots_specification.id = #{id}</select><select id="findByProductTypeId" parameterType="long" resultMap="specificationMapper">SELECTboots_specification.id AS bid,boots_specification.specName,boots_specification.productTypeId,boots_specification_option.id AS oid,boots_specification_option.optionName,boots_specification_option.specIdFROMboots_specificationLEFT JOIN boots_specification_optionON boots_specification.id = boots_specification_option.specIdWHEREboots_specification.productTypeId = #{productTypeId}</select>
</mapper>

image-20240418203835521

文件服务模块

搜索成功

分页查询成功

# 端口号
server:port: 9003# 日志格式
logging:pattern:console: '%d{HH:mm:ss.SSS} %clr(%-5level) ---  [%-15thread] %cyan(%-50logger{50}):%msg%n'spring:application:name: shopping_file_service #服务名cloud:nacos:discovery:server-addr: 192.168.66.100:8848 # 注册中心地址dubbo:application:name: shopping_file_service #服务名serialize-check-status: DISABLEcheck-serializable: falseprotocol:name: dubbo # 通讯协议port: -1 # 端口号,-1表示自动扫描可用端口。registry:address: nacos://192.168.66.100:8848 # 注册中心fdfs:so-timeout: 3000connect-timeout: 6000tracker-list: # TrackerList路径- 192.168.66.100:22122fileUrl: http://192.168.66.100:81 # 自定义配置,文件访问路径

文件服务实现

安装+配置+启动 fastdfs 和nginx

java">@DubboService
public class FileServiceImpl implements FileService {@Autowiredprivate FastFileStorageClient fastFileStorageClient;@Value("${fdfs.fileUrl}")private String fileUrl; // Nginx访问FastDFS中文件的路径@Overridepublic String uploadImage(byte[] fileBytes, String fileName) {if (fileBytes.length != 0) {try {// 1.将文件的字节数组转为输入流ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);// 2.获取文件的后缀名String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1);// 3.上传文件StorePath storePath = fastFileStorageClient.uploadFile(inputStream, inputStream.available(), fileSuffix, null);// 4.返回图片路径String imageUrl = fileUrl + "/"+storePath.getFullPath();return imageUrl;}catch (Exception e){throw new BusException(CodeEnum.UPLOAD_FILE_ERROR);}} else {throw new BusException(CodeEnum.UPLOAD_FILE_ERROR);}}@Overridepublic void delete(String filePath) {fastFileStorageClient.deleteFile(filePath);}
}

上传文件时使用springMVC 将文件转换为multipartFile

—>对象没有进行序列化

消费者和生产者使用dubbo进行服务调用;数据需要实现接口序列化

–> 需要进行byte数组转换

删除的时候直接根据文件路径进行删除

上传的图片存到了服务器中
image-20240418210759579

image-20240418210824087

image-20240418211544802

在考虑后期是不是可以把这个图床配置一下改到我的oss 阿里云的图床上面;或者把服务器的配置改到其他的服务器上面是不是也可行(如果没有端口限制就好了)

测试商品增删查改功能

java"> @Overridepublic void add(Goods goods) {// 插入商品数据goodsMapper.insert(goods);// 插入图片数据Long goodsId = goods.getId(); // 获取商品主键List<GoodsImage> images = goods.getImages(); // 商品图片集合for (GoodsImage image : images) {image.setGoodsId(goodsId); // 给图片设置商品idgoodsImageMapper.insert(image); // 插入图片}// 插入商品_规格项数据// 1.获取规格List<Specification> specifications = goods.getSpecifications();// 2.获取规格项List<SpecificationOption> options = new ArrayList();// 3.1 遍历规格,获取规格中的所有规格项for (Specification specification : specifications) {options.addAll(specification.getSpecificationOptions());}// 3.2 遍历规格项,插入商品_规格项数据for (SpecificationOption option : options) {goodsMapper.addGoodsSpecificationOption(goodsId,option.getId());}}

关于逻辑:

这里注意一下商品的信息一般不能删除,涉及到用户的订单,将无法查找到对应的商品信息;

添加一个逻辑删除的功能即可

image-20240418212634076

存在的bug:

  1. 无法查看商品
  2. 无法在商品介绍中添加图片
  3. 注释ES后无法查看商品最后一张商品的信息;但是可以查看第一张图片的商品信息;删除本地记录后 等待30s 第一张图片也无法访问; 刷新后又可以进行访问

猜测:

因为新插入的图片没来得及和中间表关联

image-20240418214430886

image-20240418214519089

image-20240418214642662

观察后发现后端数据库中出现了奇怪的拼接

image-20240418235054619image-20240419020718124

检测到问题;代码中的联表方法必须有规格才能查看

java"><select id="findById" parameterType="long" resultMap="goodsMapper">SELECTboots_goods.id AS bid,boots_goods.goodsName AS goodsName,boots_goods.caption AS caption,boots_goods.price AS price,boots_goods.headerPic AS headerPic,boots_goods.introduction AS introduction,boots_goods.isMarketable AS isMarketable,boots_goods.brandId AS brandId,boots_goods.productType1Id AS productType1Id,boots_goods.productType2Id AS productType2Id,boots_goods.productType3Id AS productType3Id,boots_goods_image.id AS imageId,boots_goods_image.imageTitle AS imageTitle,boots_goods_image.imageUrl AS imageUrl,boots_specification.id AS specificationId,boots_specification.specName AS specName,boots_specification.productTypeId AS productTypeId,boots_specification_option.id AS optionId,boots_specification_option.optionName AS optionNameFROMboots_goodsLEFT JOIN boots_goods_image ON boots_goods.id = boots_goods_image.goodsIdLEFT JOIN boots_goods_specification_option ON boots_goods.id = boots_goods_specification_option.gidLEFT JOIN boots_specification_option ON boots_goods_specification_option.optionId = boots_specification_option.idLEFT JOIN boots_specification ON boots_specification_option.specId = boots_specification.idWHEREboots_goods.id = #{gid}
</select>

image-20240419022649213

从inner修改到left后发现,可以正常查询

慢sql 多表联查问题(乌龙)

出现的新问题,出现了慢sql语句; --> 点击一次查看后很难快速点击下一次查看

Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665]
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]

这些日志信息来自使用 MyBatis 框架的 Java 应用程序,在事务处理过程中记录了各个步骤。下面是每条日志的详细解释:

  1. Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665][org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这表示两个不同的 SqlSession 实例正在从事务管理中释放。这通常发生在事务即将完成时,MyBatis 准备将这些会话返回到会话池中。
  2. Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665][org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这表示两个 SqlSession 实例正在提交它们的事务。在这一步,所有的更改(如果有的话)被保存到数据库中。
  3. Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665][org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这说明这两个 SqlSession 实例正在从事务同步管理中注销。这通常发生在事务提交或回滚之后。
  4. Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665][org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这表示这两个 SqlSession 实例正在关闭。关闭操作确保所有的资源都被适当释放,连接被归还到数据库连接池。

提问:如果只是简单的慢sql的话,那么为什么长时间没有反应呢?image-20240419023337509

经过postman和浏览器访问后,重复点击多次仍然有响应,考虑是前端的问题

  1. 缓存问题:可能浏览器或前端应用缓存了第一次请求的结果。您可以尝试禁用缓存或在请求时添加时间戳来确保每次请求都是唯一的。
  2. 后端接口状态问题:如果后端接口在处理完第一次请求后有状态变化或未正确关闭资源(例如数据库连接),可能导致后续请求无法处理。
  • Phantom Reads:虽然REPEATABLE-READ保证了不会出现不一致的重复读,但它不能完全防止幻读。幻读是指在一个事务内读取某范围的记录时,另一个事务插入了新记录,再次查询时看到了新的、之前不存在的记录。在REPEATABLE-READ下,通过间隙锁可以部分避免幻读,但在某些情况下仍然可能发生。

md 我真出现了 之前的图片出现在不同的mysql 的不同的数据中image-20240419032418665

目前暂时未检查出mysql数据库的死锁

邪门了 就只有这一个玩意不能多次查看, 而且是一点完别的本来嫩点的也不能点了

image-20240419031705750

image-20240419032127549

卧槽找到了 isMarkatebal 改变;上下架不改变其值;无效;;;还是不行

修复了!卧槽 因为之前的规格里面没选机身内存image-20240419034353337

image-20240419035010725

image-20240419035105025

image-20240419035135926

image-20240419035223273

前端的查询逻辑可能有点问题;

image-20240419040320145

我还是觉得很神奇; 难道是点击事件认为这件事还没有做完 所以没有cancel?

秒杀商品成功

这里多bb一嘴哈, 因为昨天晚上电脑开虚拟机卡爆了,强制重启,导致文件有损坏;没想到typora 给我留了一个文件夹进行历史恢复,真的cool;详情见偏好设置,未保存文档;(好像还有一个是历史文档的东东, 之前那个旧版本没有, 直接找楠妮儿 要到了她的正版序列号,nice!然后重新配置了一下图床)

image-20240422133235253


http://www.ppmy.cn/embedded/9681.html

相关文章

mysql基础7——where与having的差异

where直接对表中的字段进行限定 筛选结果 having需要根据分组关键字group by一起使用&#xff0c;通过对分组字段和分组计算函数限定 筛选结果 distinct 字段 &#xff0c; 返回字段中所有不同的值 distinct 字段; where 如果需要对关联表进行查询&#xff0c;where字段执…

MyBatis 面试题(六)

1. MyBatis 有几种分页方式&#xff1f; MyBatis 的分页方式主要可以分为两大类&#xff1a;逻辑分页和物理分页。 逻辑分页是一次性把全部数据查询加载进内存&#xff0c;然后再进行分页。这种方式减少了IO次数&#xff0c;适合频繁访问、数据量少的情况&#xff0c;但不适合…

“EDM邮件营销”如何构建企业获客增长新赛道

在这个瞬息万变的数字时代&#xff0c;企业的营销策略不断进化&#xff0c;以求在激烈的市场竞争中脱颖而出。其中&#xff0c;“EDM&#xff08;Electronic Direct Mail&#xff09;邮件营销”作为一项经典且高效的营销手段&#xff0c;正借助先进的技术力量&#xff0c;重新焕…

CSS布局 Flex 和 Grid

在 CSS 中&#xff0c;理解 flex 和 Grid 布局非常重要&#xff0c;今天把这两个重要知识点回顾一下。 Flexbox 弹性盒子布局 弹性布局支持 flex、inline-flex&#xff0c;支持块和内联。 容器 轴的概念&#xff0c;在 Flexbox&#xff0c;有主轴和侧轴的概念&#xff0c;轴…

HarmonyOS ArkUI实战开发-窗口模块(Window)

窗口模块用于在同一物理屏幕上&#xff0c;提供多个应用界面显示、交互的机制。 对应用开发者而言&#xff0c;窗口模块提供了界面显示和交互能力。对于终端用户而言&#xff0c;窗口模块提供了控制应用界面的方式。对于操作系统而言&#xff0c;窗口模块提供了不同应用界面的…

【Interconnection Networks 互连网络】Torus 网络拓扑

1. Torus 网络拓扑2. Torus 网络拓扑结构References 1. Torus 网络拓扑 Torus 和 Mesh 网络拓扑&#xff0c;又可以称为 k-ary n-cubes&#xff0c;在规则的 n 维网格中包裹着 N k^n 个节点&#xff0c;每个维度都有 k 个节点&#xff0c;并且最近邻居之间有通道。k-ary n-c…

Linux 目录操作函数

目录操作函数 ls -l 可以查看目录中文件的信息&#xff0c;比如&#xff1a; petriXX:~/lesson01/05_io/目录操作函数$ ls -l a.txt -rw-r--r-- 1 petri petri 0 Apr 22 18:51 a.txtLinux系统中的目录操作函数&#xff1a; int rename(const char *oldpath, const char *new…

通过Docker新建并使用MySQL数据库

1. 安装Docker 确保您的系统上已经安装了Docker。可以通过以下命令检查Docker是否安装并运行&#xff1a; systemctl status docker如果没有安装或运行&#xff0c;请按照官方文档进行安装和启动。 2. 拉取MySQL镜像 从Docker Hub拉取MySQL官方镜像。这里以MySQL 5.7版本为…