1、能够说出Redison框架的作用?

Redisson是一个在Redis的基础上封装了基本数据结构、分布式的其他数据结构,如通用对象桶、原子整长形、分布式集合(RMap对象、RMapCahe对象、分布式锁);可促进使用者对Redis的关注分离,将更多精力放在处理业务逻辑。
image.png

2、能够说出Redison对象桶有哪些? 什么是对象桶?

通用对象桶、批量通用对象桶;
对象桶既是Redisson用来存储对象实例的,可通过key获取到对应的实例;

对象redissonClient Api(全限定类名也会存入value) 返回值类型 说明
新增修改 getBucket(“BucketOpertions”) RBucket<类型> 存储对象
set(anyObject) 存储
remainTimeToLive() (>0存活时间毫秒) long timeToLive -2:key不存在,-1:永久
set(anyObject,600,TimeUnit.SECONDS) 600秒存活
trySet(xxx,xxx,xxx) boolean 有false,无设置
getAndSet(anyObjectNew) AnyObject(旧值) 替换为新值
查询 get() AnyObjectResult 获取新值
删除 delete()
批量操作 getBuckets() RBuckets 获取所有对象
buckets.get(“A”, B”) Map 获取对象集
clear() 清除所有

3、原子性对象有哪些?

原子整长形,分布式整长形RAtomicLong与java.util.concurrent.atomic.AtomicLong对象类似;
原子双精度浮点,分布式原子双精度浮点RAtomicDouble弥补了Java自身的不足

对象redissonClient Api(多线程保证执行线程安全) 返回值类型 说明
新增修改 getAtomicLong(“AtomicLongOper”) RAtomicLong 获得key
atomicLongOper.set(0) 存储
查询 atomicLongOper.get() Long 获取值
运算 incrementAndGet() Long ++i
getAndIncrement() Long i++
getAndSet(anyObjectNew) AnyObject(旧值) 替换为新值

decrementAndGet() AnyObjectResult 获取新值

getAndDecrement()
删除 delete() boolean
addAndGet(2) Long 正为添加,负数为减
getAndDelete() Long 获取并删除

4、redisson-分布式集合数据结构是什么? 主key和辅key有什么作用?

分布式集合的数据结构有两种:
1、RMap:实现了ConcurrentMap和Map接口,保持元素的插入顺序
2、RMapCache:基于RMap实现了针对单个元素的过期时间配置
有两种key:
1、主key:即存储在redis中的key,可通过RedissonClient获取对应的map对象;
2、辅key:即map中的key,一般是一个对象的id,通过key可获取map中的value;

对象redissonClient Api 返回值类型 说明
新增修改 getMap(“userInfo”) RMap 存储map对象,大key
put(ObjectA.getId(),anyObjectA) 存储对应的value
fastPut(ObjectA.getId(),anyObjectA) 效率快
putAll(map) 批量添加
putIfAbsent(ObjectD.getId(), ObjectD) AnyObject
返回之前的值
key存在(返回null):不修改<==>修改
查询 readAllKeySet() RKeys 获得小key
readAllValues() Collection 所有的value,强转为ArrayList
readAllEntrySet() Set> 所有的元素对象
LinkedHashMap
删除 clear()/delete()

5、redisson-分布式锁原理是什么?怎么用?WatchDog自动延期机制是什么?

1、分布式锁
分布式—>springcloud、dubbo分布式项目
锁—->在多线程同时操作共享数据时,防止脏数据产生
2、能解决什么问题
在并发访问的时候保证数据的一致性;
3、使用synchronized同步锁在在分布式架构中能保证数据一致性吗?
不能,分布式架构,服务是集群部署的,每个服务部署在不同的JVM上;Synchronized是基于JVM的,无法保证分布式访问的都是同一把锁;
4、注意事项
—记得在finally中释放锁;
—可设置锁的失效时间,防止出现死锁;
5、redisson分布式锁的原理
day04点餐平台-开桌、主体信息 - 图2
6、WatchDog自动延期看门狗机制
第一种情况:在一个分布式环境下,假如一个线程获得锁后,突然服务器宕机了,那么这个时候在一定时间后这个锁会自动释放,你也可以设置锁的有效时间(不设置默认30秒),这样的目的主要是防止死锁的发生;
第二种情况:线程A业务还没有执行完,时间就过了,线程A 还想持有锁的话,就会启动一个watch dog后台线程,不断的延长锁key的生存时间;
7、基本使用
RLock是继承Lock锁,lock、unlock、trylock

API 说明
redissonClient.getLock(“lock”) 获取锁对象
rLock.lock() 加锁,默认30秒
rLock.lock(10,TimeUnit.SECONDS) 手动设置有效时间
rLock.tryLock() 获取成功true,失败false(已被占用)
tryLock(6, TimeUnit.SECONDS)
rLock.tryLock(11, 10, TimeUnit.SECONDS) 根据业务执行时间预估,设置等待等待时间,略大于持锁时间
rLock.unlock() 微调用此方法,到期自动释放

6、桌台是否开台的前提条件是什么?

两种前提条件:
1、桌台状态为空闲,即查询数据库中table表的table_status为free;
2、当前桌台对应的订单表中不是【待付款、支付中】状态;

7、查询相关主体时需要统一查询哪些数据? 核心的字段是什么?

品牌、门店、区域、桌台、菜品分类、菜品等相关数据;
核心字段:tableId—>storeId

8、开桌主要完成哪些操作?

1、为桌台创建【待支付】订单
2、修改桌台状态【空闲—->开桌】

9、开桌的实现流程是什么?

实现步骤:
1、定义异常
2、开台状态定义
3、锁定桌台,防止并发重复创建订单 — 分布式锁
4、==幂等性==:再次查询桌台订单情况
5、未开台,为桌台创建订单,并设置订单状态为: DFK
5.1、查询桌台信息
5.2、构建订单
6、修改桌台状态为使用中
7、查询订单处理:处理可核算订单项和购物车订单项,可调用桌台订单显示接口

10、开桌为什么需要加分布式锁? 如果不加分布式锁是否可以? key是什么?

在多人同时扫码点餐,可锁定桌台,防止并发重复创建订单 — 分布式锁;

String key = AppletCacheConstant.OPEN_TABLE_LOCK+tableId;
RLock lock = redissonClient.getLock(key);

11、什么是幂等性? 开桌时为什么需要考虑冪等操作?

幂等性:访问同一个URL,无论多少次请求,得到的结果都是一致的;
为什么:确认桌台订单的状态,防止并发重复创建订单;

  1. @Override
  2. @Transactional
  3. public OrderVo openTable(Long tableId,Integer personNumbers) throws ProjectException {
  4. //1、开台状态定义
  5. boolean flag = true;
  6. //2、锁定桌台,防止并发重复创建订单
  7. String key = AppletCacheConstant.OPEN_TABLE_LOCK+tableId;
  8. RLock lock = redissonClient.getLock(key);
  9. try {
  10. if(lock.tryLock(AppletCacheConstant.REDIS_WAIT_TIME,
  11. AppletCacheConstant.REDIS_LEASETIME,
  12. TimeUnit.SECONDS)){
  13. //3、幂等性:再次查询桌台订单情况
  14. OrderVo orderVoResult = orderService.findOrderByTableId(tableId);
  15. //4、未开台,为桌台创建当订单
  16. if (EmptyUtil.isNullOrEmpty(orderVoResult)){
  17. //4.1、查询桌台信息
  18. Table table = tableService.getById(tableId);
  19. //4.2、构建订单
  20. Order order = Order.builder()
  21. .tableId(tableId)
  22. .tableName(table.getTableName())
  23. .storeId(table.getStoreId())
  24. .areaId(table.getAreaId())
  25. .enterpriseId(table.getEnterpriseId())
  26. .orderNo((Long) identifierGenerator.nextId(tableId))
  27. .orderState(TradingConstant.DFK)
  28. .isRefund(SuperConstant.NO)
  29. .refund(new BigDecimal(0))
  30. .discount(new BigDecimal(10))
  31. .personNumbers(personNumbers)
  32. .reduce(new BigDecimal(0))
  33. .useScore(0)
  34. .acquireScore(0l)
  35. .build();
  36. orderService.save(order);
  37. //5、修改桌台状态为使用中
  38. TableVo tableVo = TableVo.builder()
  39. .id(tableId)
  40. .tableStatus(SuperConstant.USE).build();
  41. tableService.updateTable(tableVo);
  42. }
  43. }
  44. //6、订单处理:处理可核算订单项和购物车订单项,可调用桌台订单显示接口
  45. return showOrderVoforTable(tableId);
  46. }catch (Exception e){
  47. log.error("开桌操作异常:{}", ExceptionsUtil.getStackTraceAsString(e));
  48. throw new ProjectException(TableEnum.OPEN_TABLE_FAIL);
  49. }finally {
  50. lock.unlock();
  51. }
  52. }

12、订单创建时机是什么?

当用户点击去下单时,即会在mysql中创建订单;

13、什么是可核算订单项? 什么是购物车项? 分别存到哪里?

1、可核算订单项【已下单可结算】:MySQL
2、购物车订单项【已加入购物车未下单】:Redis
image.png