黑马点评项目遇到的部分问题

这篇具有很好参考价值的文章主要介绍了黑马点评项目遇到的部分问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. Invalid default value for ‘begin_time‘报错

  • mysql⽇期时间设置默认0000-00-0000:00:00出错。
    • DEFAULT ‘0000-00-00 00:00:00’(零时间戳),这不满足sql_mode中的NO_ZERO_DATE而报错。
    • sql_mode有两种,一种是空值,一种是严格模式,会给出很多默认设置。在MySQL5.7之后默认使用严格模式。
    • NO_ZERO_DATE:若设置该值,MySQL数据库不允许插入零日期,插入零日期会抛出错误而不是警告。
    • 在命令行中设置sql_mode:
      SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

2. ThreadLocal

  • remove 方法,直接将 ThreadLocal 对应的值从当前线程 Thread 中的 ThreadLocalMap 中删除。为什么要删除,这涉及到内存泄漏的问题。
  • ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用, 弱引用的特点是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。
  • 所以如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候会被清理掉的,这样一来 ThreadLocalMap中使用这个 ThreadLocal 的 key 也会被清理掉。但是, value 是强引用,不会被清理,这样一来就会出现 key 为 null 的 value。

3. 悲观锁实现单体一人一单超卖问题

  • 乐观锁适合判断数据更新问题,而当前是判断是否存在,所以可以使用悲观锁解决。

  • 锁的范围尽量小, synchronized尽量锁代码块而不是方法,锁的范围越大性能越低。

  • 锁的对象一定是一个不变的值,不能直接锁 Long 类型的 userId,每请求一次都会创建一个新的 userId 对象,synchronized 要锁不变的值, 所以要将 Long 类型的 userId 通过 toString() 方法转成 String 类型的 userId, toString底层是直接 new 一个新的 String 对象,还是在变, 所以要用 intern() 方法从常量池中寻找与当前字符串值一致的字符串对象, 这样就能保障一个用户发送多次请求,每次请求的 userId 都是不变的,从而完成锁的效果。

  • 要锁整个事务,而不是锁事务内部的代码。如果我们锁住事务内部的代码会导致其它线程能够进入事务,当我们事务还未提交,锁一旦释放,仍然会存在超卖问题。

  • Spring 的 @Transactional 注解要想事务生效,必须使用动态代理。在同一个类中,一个方法调用另外一个有注解(比如@Async,@Transational)的方法,注解是不会生效的,所以我们需要创建一个代理对象,使用代理对象来调用方法。

    • spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是@Transactional注解无效。

    • 让代理对象生效的步骤:

      • 引入 AOP 依赖,动态代理是AOP 的常见实现之一
      <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
      </dependency>
      
      • 暴露动态代理对象,默认是关闭的
      	@EnableAspectJAutoProxy(exposeProxy = true)
      
  • 对于集群下一人一单的并发安全问题,由于每个tomcat 都有一个属于自己的 jvm,此时这个synchronized锁会失效,synchronized是本地锁,只能提供线程级别的同步,每个JVM中都有一把synchronized锁,不能跨 JVM 进行上锁,当一个线程进入被 synchronized 关键字修饰的方法或代码块时,它会尝试获取对象的内置锁(也称为监视器锁)。如果该锁没有被其他线程占用,则当前线程获得锁,可以继续执行代码;否则,当前线程将进入阻塞状态,直到获取到锁为止。而现在我们是创建了两个节点,也就意味着有两个JVM,所以synchronized会失效! 原文链接

  • try…finally…确保发生异常时锁能够释放,注意这给地方不要使用catch,A事务方法内部调用B事务方法,A事务方法不能够直接catch,否则会导致事务失效。

        // 3、创建订单(使用分布式锁)
        Long userId = ThreadLocalUtls.getUser().getId();
        SimpleRedisLock lock = new SimpleRedisLock(stringRedisTemplate, "order:" + userId);
        boolean isLock = lock.tryLock(1200);
        if (!isLock) {
            // 索取锁失败,重试或者直接抛异常(这个业务是一人一单,所以直接返回失败信息)
            return Result.fail("一人只能下一单");
        }
        try {
            // 索取锁成功,创建代理对象,使用代理对象调用第三方事务方法, 防止事务失效
            IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
            return proxy.createVoucherOrder(userId, voucherId);
        } finally {
            lock.unlock();
        }
    
    

4. redisson

  • 可重入:利用hash 结构记录线程id 和重入次数
  • 可重试:利用信号量和 PubSub 功能实现等待、唤醒、获取锁失败的重试机制
  • 超时续约:利用 watchDog ,每个一段时间(releaseTime / 3) 重置超时时间
    获取锁,根据订阅发的通知,在自己获取锁时,判断自己的剩余时间,去监听获取。
    避免业务未完成锁超时释放发问题,采用看门狗的机制,每过一段时间去重置有效期.
  • 主从一致性问题:利用 Redission 的 multiLock ,多个独立的 Redis 节点, 必须在所有节点都获取重入锁,才算获取锁成功

5. 回顾秒杀优化

遇到自增 ID 问题,通过实现分布式ID解决了问题;后面我们在单体系统下遇到了一人多单超卖问题,我们通过乐观锁解决了;我们对业务进行了变更,将一人多单变成了一人一单,结果在高并发场景下同一用户发送相同请求仍然出现了超卖问题,我们通过悲观锁解决了;由于用户量的激增,我们将单体系统升级成了集群,结果由于锁只能在一个JVM中可见导致又出现了,在高并发场景下同一用户发送下单请求出现超卖问题,我们通过实现分布式锁成功解决集群下的超卖问题;由于我们最开始实现的分布式锁比较简单,会出现超时释放导致超卖问题,我们通过给锁添加线程标识成功解决了;但是释放锁时,判断锁是否是当前线程 和 删除锁两个操作不是原子性的,可能导致超卖问题,我们通过将两个操作封装到一个Lua脚本成功解决了;为了解决锁的不可重入性,我们通过将锁以hash结构的形式存储,每次释放锁都value-1,获取锁value+1,从而实现锁的可重入性,并且将释放锁和获取锁的操作封装到Lua脚本中以确保原子性。最最后,我们发现可以直接使用现有比较成熟的方案Redisson来解决上诉出现的所有问题,不可重试、不可重入、超时释放、原子性等问题Redisson都提供相对应的解决方法。
原文链接

6. Nginx 负载均衡

搭建集群环境时,修改 Nginx 配置后要重启。 nginx.exe -s reload文章来源地址https://www.toymoban.com/news/detail-856839.html

到了这里,关于黑马点评项目遇到的部分问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于springboot+Redis的前后端分离项目(九)-【黑马点评】

    🎁🎁资源文件分享 链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11 提取码:eh11 GEO就是Geolocation的简写形式,代表地理坐标。Redis在3.2版本中加入了对GEO的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。常见的命令有: GEOADD:添加一个地理空间信息,包含

    2024年02月16日
    浏览(42)
  • 基于springboot+Redis的前后端分离项目(八)-【黑马点评】

    🎁🎁资源文件分享 链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11 提取码:eh11 针对用户的操作:可以对用户进行关注和取消关注功能。 实现思路: 需求:基于该表数据结构,实现两个接口: 关注和取关接口 判断是否关注的接口 关注是User之间的关系,是博主与粉丝的

    2024年02月16日
    浏览(45)
  • 基于springboot+Redis的前后端分离项目(二)-【黑马点评】

    🎁🎁资源文件分享 链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11 提取码:eh11 缓存( Cache),就是数据交换的 缓冲区 ,俗称的缓存就是 缓冲区内的数据 ,一般从数据库中获取,存储于本地代码。(例如: 由于其被 Static 修饰,所以随着类的加载而被加载到 内存之中 ,作为本地缓存

    2024年02月10日
    浏览(43)
  • 黑马点评-项目集成git及redis实现短信验证码登录

    目录     IDEA集成git 传统session存在的问题  redis方案 业务流程 选用的数据结构 整体访问流程 发送短信验证码  获取校验验证码 配置登录拦截器 拦截器注册配置类 拦截器 用户状态刷新问题 刷新问题解决方案   远程仓库采用码云,创建好仓库,复制仓库的url    在idea中点

    2024年02月12日
    浏览(39)
  • 基于springboot+Redis的前后端分离项目之消息队列(六)-【黑马点评】

    🎁🎁资源文件分享 链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11 提取码:eh11 我们来回顾一下下单流程 当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单

    2024年02月12日
    浏览(42)
  • 基于springboot+Redis的前后端分离项目之分布式锁(四)-【黑马点评】

    🎁🎁资源文件分享 链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11 提取码:eh11 分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让

    2024年02月11日
    浏览(51)
  • 基于springboot+Redis的前后端分离项目之分布式锁-redission(五)-【黑马点评】

    🎁🎁资源文件分享 链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11 提取码:eh11 基于setnx实现的分布式锁存在下面的问题: 重入问题 :重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都

    2024年02月11日
    浏览(43)
  • 黑马点评Redis实战(优惠卷秒杀)

    本文是上一篇文章的后续,上一篇文章链接 马点评Redis实战(短信登录;商户查询缓存) id是一个订单必备的属性,而订单的id属性是必须唯一的,首先我们会想到使用数据库主键id,并设置为自增。这样似乎就能满足唯一性。 但是,这样会存在一些问题: id的规律太过明显,因

    2024年02月04日
    浏览(35)
  • 黑马点评-01基于Redis实现短信登陆的功能

    当前模型 nginx服务器的作用 手机或者app端向nginx服务器发起请求,nginx基于七层模型走的是HTTP协议,可以实现基于Lua直接绕开tomcat访问Redis nginx也可以作为静态资源服务器,轻松扛下上万并发并负载均衡到下游的tomcat服务器,利用集群支撑起整个项目 使用nginx部署前端项目后还可以

    2024年02月07日
    浏览(41)
  • attempt to compare nil with number -- 黑马点评出现问题

     问题情况 :   主要问题 :  调用lua执行redis时,有一个值会接受nil(因为redis中没有该数据)或者数值,当该值为nil时执行报错,因为会用到将该值与其他数字比较,故报错attempt to compare nil with number 当然运行前手动在redis中加上SecKill:stock:voucherId对应的值也行,但也可以通过

    2024年04月28日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包