- 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
@Transactional
public 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