Day4 商品管理
这里会总结构建项目过程中遇到的问题,以及一些个人思考!!
学习方法:
1 github源码 + 文档 + 官网
2 内容复现 ,实际操作
项目源码同步更新到github 欢迎大家star~ 后期会更新并上传前端项目
编写品牌服务
/*** 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 完成
商品类型
@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);}
}
商品规格项
<?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>
文件服务模块
搜索成功
分页查询成功
# 端口号
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
@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数组转换
删除的时候直接根据文件路径进行删除
上传的图片存到了服务器中
在考虑后期是不是可以把这个图床配置一下改到我的oss 阿里云的图床上面;或者把服务器的配置改到其他的服务器上面是不是也可行(如果没有端口限制就好了)
测试商品增删查改功能
@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());}}
关于逻辑:
这里注意一下商品的信息一般不能删除,涉及到用户的订单,将无法查找到对应的商品信息;
添加一个逻辑删除的功能即可
存在的bug:
- 无法查看商品
- 无法在商品介绍中添加图片
- 注释ES后无法查看商品最后一张商品的信息;但是可以查看第一张图片的商品信息;删除本地记录后 等待30s 第一张图片也无法访问; 刷新后又可以进行访问
猜测:
因为新插入的图片没来得及和中间表关联
观察后发现后端数据库中出现了奇怪的拼接
检测到问题;代码中的联表方法必须有规格才能查看
<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>
从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 应用程序,在事务处理过程中记录了各个步骤。下面是每条日志的详细解释:
- Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665] 和 [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这表示两个不同的 SqlSession 实例正在从事务管理中释放。这通常发生在事务即将完成时,MyBatis 准备将这些会话返回到会话池中。
- Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665] 和 [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这表示两个 SqlSession 实例正在提交它们的事务。在这一步,所有的更改(如果有的话)被保存到数据库中。
- Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665] 和 [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这说明这两个 SqlSession 实例正在从事务同步管理中注销。这通常发生在事务提交或回滚之后。
- Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12e56665] 和 [org.apache.ibatis.session.defaults.DefaultSqlSession@2bef026]: 这表示这两个 SqlSession 实例正在关闭。关闭操作确保所有的资源都被适当释放,连接被归还到数据库连接池。
提问:如果只是简单的慢sql的话,那么为什么长时间没有反应呢?
经过postman和浏览器访问后,重复点击多次仍然有响应,考虑是前端的问题
- 缓存问题:可能浏览器或前端应用缓存了第一次请求的结果。您可以尝试禁用缓存或在请求时添加时间戳来确保每次请求都是唯一的。
- 后端接口状态问题:如果后端接口在处理完第一次请求后有状态变化或未正确关闭资源(例如数据库连接),可能导致后续请求无法处理。
- Phantom Reads:虽然
REPEATABLE-READ
保证了不会出现不一致的重复读,但它不能完全防止幻读。幻读是指在一个事务内读取某范围的记录时,另一个事务插入了新记录,再次查询时看到了新的、之前不存在的记录。在REPEATABLE-READ
下,通过间隙锁可以部分避免幻读,但在某些情况下仍然可能发生。md 我真出现了 之前的图片出现在不同的mysql 的不同的数据中
目前暂时未检查出mysql数据库的死锁
邪门了 就只有这一个玩意不能多次查看, 而且是一点完别的本来嫩点的也不能点了
卧槽找到了 isMarkatebal 改变;上下架不改变其值;无效;;;还是不行
修复了!卧槽 因为之前的规格里面没选机身内存
前端的查询逻辑可能有点问题;
我还是觉得很神奇; 难道是点击事件认为这件事还没有做完 所以没有cancel?
秒杀商品成功
这里多bb一嘴哈, 因为昨天晚上电脑开虚拟机卡爆了,强制重启,导致文件有损坏;没想到typora 给我留了一个文件夹进行历史恢复,真的cool;详情见偏好设置,未保存文档;(好像还有一个是历史文档的东东, 之前那个旧版本没有, 直接找楠妮儿 要到了她的正版序列号,nice!然后重新配置了一下图床)