- 1、能够说出Redison框架的作用?
- 2、能够说出Redison对象桶有哪些? 什么是对象桶?
- 3、原子性对象有哪些?
- 4、redisson-分布式集合数据结构是什么? 主key和辅key有什么作用?
- 5、redisson-分布式锁原理是什么?怎么用?WatchDog自动延期机制是什么?
- 6、桌台是否开台的前提条件是什么?
- 7、查询相关主体时需要统一查询哪些数据? 核心的字段是什么?
- 8、开桌主要完成哪些操作?
- 9、开桌的实现流程是什么?
- 10、开桌为什么需要加分布式锁? 如果不加分布式锁是否可以? key是什么?
- 11、什么是幂等性? 开桌时为什么需要考虑冪等操作?
- 12、订单创建时机是什么?
- 13、什么是可核算订单项? 什么是购物车项? 分别存到哪里?
1、能够说出Redison框架的作用?
Redisson是一个在Redis的基础上封装了基本数据结构、分布式的其他数据结构,如通用对象桶、原子整长形、分布式集合(RMap对象、RMapCahe对象、分布式锁);可促进使用者对Redis的关注分离,将更多精力放在处理业务逻辑。
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分布式锁的原理
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,无论多少次请求,得到的结果都是一致的;
为什么:确认桌台订单的状态,防止并发重复创建订单;
@Override@Transactionalpublic OrderVo openTable(Long tableId,Integer personNumbers) throws ProjectException {//1、开台状态定义boolean flag = true;//2、锁定桌台,防止并发重复创建订单String key = AppletCacheConstant.OPEN_TABLE_LOCK+tableId;RLock lock = redissonClient.getLock(key);try {if(lock.tryLock(AppletCacheConstant.REDIS_WAIT_TIME,AppletCacheConstant.REDIS_LEASETIME,TimeUnit.SECONDS)){//3、幂等性:再次查询桌台订单情况OrderVo orderVoResult = orderService.findOrderByTableId(tableId);//4、未开台,为桌台创建当订单if (EmptyUtil.isNullOrEmpty(orderVoResult)){//4.1、查询桌台信息Table table = tableService.getById(tableId);//4.2、构建订单Order order = Order.builder().tableId(tableId).tableName(table.getTableName()).storeId(table.getStoreId()).areaId(table.getAreaId()).enterpriseId(table.getEnterpriseId()).orderNo((Long) identifierGenerator.nextId(tableId)).orderState(TradingConstant.DFK).isRefund(SuperConstant.NO).refund(new BigDecimal(0)).discount(new BigDecimal(10)).personNumbers(personNumbers).reduce(new BigDecimal(0)).useScore(0).acquireScore(0l).build();orderService.save(order);//5、修改桌台状态为使用中TableVo tableVo = TableVo.builder().id(tableId).tableStatus(SuperConstant.USE).build();tableService.updateTable(tableVo);}}//6、订单处理:处理可核算订单项和购物车订单项,可调用桌台订单显示接口return showOrderVoforTable(tableId);}catch (Exception e){log.error("开桌操作异常:{}", ExceptionsUtil.getStackTraceAsString(e));throw new ProjectException(TableEnum.OPEN_TABLE_FAIL);}finally {lock.unlock();}}
12、订单创建时机是什么?
当用户点击去下单时,即会在mysql中创建订单;
13、什么是可核算订单项? 什么是购物车项? 分别存到哪里?
1、可核算订单项【已下单可结算】:MySQL
2、购物车订单项【已加入购物车未下单】:Redis
