不做笨蛋

269 阅读9分钟

在使用MySQL作为论坛项目的数据库时,为什么使用雪花算法生成UserID,而不是使用自增ID作为UserID?

  1. 全局唯一性

使用雪花算法可以生成全局唯一的ID,不同于自增ID只能在本地唯一。在分布式系统中,多个节点同时插入记录时,可能会生成相同的自增ID,而使用雪花算法可以避免这个问题。这样可以确保ID的唯一性,减少数据冲突的可能性。

  1. 排序性

雪花算法生成的ID是按时间递增的,具有良好的排序性,可以优化数据库的查询性能。如果根据ID进行查询或排序,使用雪花算法生成的ID可以加快查询速度。

  1. 灵活性和可扩展性

雪花算法生成的ID不依赖于数据库,这样可以使系统更加灵活和可扩展。如果将来需要更换数据库,也不会影响ID的生成。此外,雪花算法是一种轻量级的ID生成算法,生成ID的速度很快,对系统性能影响较小。

  1. 可配置性

雪花算法的参数可以配置,可以根据需要调整不同的参数值,以满足不同的应用场景。例如,可以调整机器ID和数据中心ID的位数,以适应不同的机器数量和数据中心数量。

  1. 安全性

雪花算法使用64位的二进制数生成ID,随机性非常高,具有很强的安全性。这使得雪花算法生成的ID难以被猜测或预测,从而提高了系统的安全性。

综上所述,使用雪花算法生成UserID相比使用自增ID作为UserID具有更多的优势,特别是在分布式系统中使用时更为明显。

使用自增id的缺点

使用自增ID作为主键存在一些缺点,具体如下:

  1. 不适用于分布式系统

在分布式系统中,多个节点同时插入记录时,可能会生成相同的自增ID,从而导致ID冲突。这是因为自增ID是由数据库单独维护的,不同的节点在不同的时间可能会获取到相同的ID值。这样就会造成数据的不一致,影响系统的正常运行。

  1. 不利于数据迁移

如果需要将数据从一个数据库迁移到另一个数据库,那么自增ID就会出现问题。因为新数据库中的自增ID值可能会与原来的数据库中的自增ID值产生冲突,导致数据不一致。

  1. 不支持分布式ID

自增ID的生成是由数据库单独维护的,无法实现全局唯一性。如果需要支持分布式ID生成,就需要使用分布式ID生成器。

  1. 查询性能差

使用自增ID作为主键时,查询语句通常会按照主键ID进行排序,这样可能会导致在查询时需要进行全表扫描。而雪花算法生成的ID是按时间递增的,具有良好的排序性,可以加速查询操作。

  1. 可预测性

自增ID是连续递增的整数,有序性和可预测性非常高。这就意味着攻击者可以通过推算出ID的规律,猜测出其他用户的ID,并且利用这些信息进行攻击。

总的来说,使用自增ID作为主键在某些情况下可能会存在问题,特别是在分布式系统中使用时更为明显。为了保证系统的可靠性和安全性,应该考虑使用其他的主键生成方式,如UUID或者雪花算法等。

使用了用户名和用户id作为唯一索引,从业务角度说说为什么

  1. 确保唯一性:通过将用户名和用户ID作为唯一索引,可以确保用户在注册时提供的用户名和用户ID是唯一的,从而避免出现重复注册或数据错误的情况。
  2. 方便用户识别和查找:用户名和用户ID通常是用户识别和查找的重要标识,将它们作为唯一索引可以加速用户登录和查找用户信息的过程。
  3. 方便数据关联:在Web论坛中,用户名和用户ID通常与其他表格(如回复、主题、私信等)建立关联。将用户名和用户ID作为唯一索引可以方便地将不同的数据表格关联起来,提高查询效率和数据一致性。
  4. 数据库性能优化:唯一索引可以帮助数据库优化查询,减少查询时需要扫描的数据行数,提高查询效率,减少数据库服务器的负载压力。

综上所述,将用户名和用户ID作为唯一索引是从业务角度考虑的常见设计方式之一,可以帮助提高Web论坛的运行效率、数据一致性和用户体验。

将用户名和用户ID作为唯一索引可以方便地将不同的数据表格关联起来,提高查询效率和数据一致性,这是因为在Web论坛中,用户名和用户ID通常用于识别和查找用户,而与用户相关的数据(如回复、主题、私信等)通常也都要与用户的用户名或用户ID进行关联。

在本项目中,分页展示的时候,需要先去redis中找到pid,然后通过pid去帖子列表充实帖子信息,拿到uid再去user充实用户信息,这时候用uid做一个关联,提高查询效率

假如给你一组数字,其中两个数字分别出现一次,剩下的数字均出现两次,那么怎么找到这两个数字

  1. 对所有数字进行异或操作,得到的结果就是这两个出现一次的数字的异或结果。因为同一个数异或两次结果为0,所以其它出现两次的数都被抵消了。
  2. 找到结果中二进制中的任意一个非0位,这一位在两个出现一次的数字中一定不同,因为相同数字异或结果为0。
  3. 根据这一位将数组分为两个部分,一部分该位是0,另一部分该位是1。两个出现一次的数字被分到了不同的部分。
  4. 对两个部分分别进行异或操作,得到的结果就是这两个出现一次的数字。

举例: 假设给定的数字是[2, 4, 6, 8, 10, 2, 6, 8],其中两个只出现一次的数字是4和10。

  1. 对所有数字做异或操作:2^4^6^8^10^2^6^8=10^4=14
  2. 14的二进制表示是1110,第二位(从右往左数)是不同的,因此将所有数字按照第二位是否为1分成两组:
  • 第一组:[2, 6, 10, 2, 6],二进制表示为[0010, 0110, 1010, 0010, 0110],做异或操作得到10
  • 第二组:[4, 8, 8],二进制表示为[0100, 1000, 1000],做异或操作得到4
  1. 10和4就是两个只出现一次的数字。

同一个协程拿到了写锁,是否可以拿读锁

在大多数情况下,同一个协程在持有写锁时是无法获得读锁的。这是因为写锁是排他性的,它会阻塞任何其他的读锁和写锁请求,直到写锁被释放。

如果在持有写锁的同时请求读锁,那么该请求将被阻塞,因为写锁正在执行独占操作。只有在写锁被释放后,读锁请求才会获得执行。

但是,在某些情况下,可能会发生死锁,如果同一个协程在持有写锁的同时请求读锁,而另一个协程在持有读锁的同时请求写锁,那么它们可能会相互阻塞,导致死锁。因此,在编写代码时,需要小心处理锁的请求和释放,以避免出现死锁。

数据库和缓存什么时候会出现不一致的情况,如何解决(假如我们一个请求做更新操作,一个请求做查询操作,会不会导致数据库里面的数据和缓存中的数据不一致)

旁路缓存+延时删除or双删 -----解决写缓存由于网络问题导致写比较慢

image.png

是可能的。例如,一个请求正在更新数据库中的数据,而此时缓存中仍然保存的是旧数据。如果另一个请求在此时查询了缓存,那么它将得到旧数据,而不是最新的数据。这会导致数据库中的数据和缓存中的数据不一致。

为了解决这个问题,可以采取以下措施:

  1. 实现缓存和数据库的双写模式。即当一个请求更新数据库时,同时更新缓存中的数据,保证缓存中的数据和数据库中的数据一致。
  2. 设置缓存的过期时间。当数据被更新后,缓存中的数据也需要及时更新。但是如果缓存中的数据过期时间较长,那么就有可能导致数据不一致。因此,可以设置缓存的过期时间,确保数据在一定时间内被更新。
  3. 采用缓存穿透的解决方案。当查询的数据在缓存中不存在时,可以在数据库中查询并将结果缓存起来。这样即使出现不一致的情况,也能够及时更新缓存中的数据,避免数据不一致。
  4. 使用分布式锁。当一个请求正在更新数据库时,可以使用分布式锁来确保其他请求无法同时更新数据库和缓存,从而保证数据的一致性。

为了避免这种情况发生,可以使用缓存锁(也称为 cache-aside lock)机制,即在写操作时,先获得缓存锁,然后进行更新操作,更新完成后再释放锁。在读操作时,先尝试从缓存中读取数据,如果没有命中缓存,则先获得缓存锁,然后再从数据库中读取数据,并将数据更新到缓存中,最后释放锁。这样可以保证写操作和读操作互斥执行,避免读操作读到旧数据的情况发生。