牛逼!一款基于SpringBoot的微信点餐系统
程序员的成长之路
共 7242字,需浏览 15分钟
·
2020-08-26 15:53
阅读本文大概需要 9 分钟。
来自:jianshu.com/p/ae14101989f2
数据库乐观锁; 基于Redis的分布式锁; 基于ZooKeeper的分布式锁。
# 分布式锁基于Redis的实现:(本系统锁才用的)
SETNX(SET if Not exist):当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。
GETSET:将给定 key 的值设为 value ,并返回 key 的旧值。先根据key获取到旧的value,再set新的value。
EXPIRE 为给定 key 设置生存时间,当 key 过期时,它会被自动删除。
jedis.set(String key, String value, String nxxx, String expx, int time)
Long result = jedis.setnx(Key, value);
if (result == 1) {
// 若在这里程序突然崩溃,则无法设置过期时间,将发生死锁
jedis.expire(Key, expireTime);
}
long expires = System.currentTimeMillis() + expireTime;
String expiresStr = String.valueOf(expires);
// 如果当前锁不存在,返回加锁成功
if (jedis.setnx(lockKey, expiresStr) == 1) {
return true;
}
// 如果锁存在,获取锁的过期时间
String currentValueStr = jedis.get(lockKey);
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
// 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间
String oldValueStr = jedis.getSet(lockKey, expiresStr);
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
// 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才有权利加锁
return true;
}
}
// 其他情况,一律返回加锁失败
return false;
分布式锁基于Zookeeper的实现
Zookeeper的分布式锁原理
在获取分布式锁的时候在locker节点(locker节点是Zookeeper的指定节点)下创建临时顺序节点,释放锁的时候删除该临时节点。 客户端调用createNode方法在locker下创建临时顺序节点,然后调用getChildren(“locker”)来获取locker下面的所有子节点,注意此时不用设置任何Watcher。 客户端获取到所有的子节点path之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。 如果发现自己创建的节点并非locker所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,然后对其调用exist()方法,同时对其注册事件监听器。 之后,让这个被关注的节点删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是locker子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。
分布式系统的下的Session
Redis作为分布式锁
@cacheable 只会执行一次,当标记在一个方法上时表示该方法是支持缓存的,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果。 @cacheput:与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
select * from account where name=”Erica” for update
String hql ="from TUser as user where user.name='Erica'";
Query query = session.createQuery(hql);
query.setLockMode("user",LockMode.UPGRADE); //加锁
List userList = query.list();//执行查询,获取数据
其它
List
public static void main(String[] args) {
String[] names = {"beibei", "jingjing"};
for (String name : names) {
System.out.println(name);
}
}
@Data
public class OrderForm {
@NotEmpty(message = "姓名必填")
private String name;
}
@RequestMapping("save")
public String save( @Valid OrderForm order,BindingResult result) {
//
if(result.hasErrors()){
List
ls=result.getAllErrors(); for (int i = 0; i < ls.size(); i++) {
log.error("参数不正确,OrderForm={}", order);
throw new SellException(
………… ,
result.getFeildError.getDefaultMessage()
)
System.out.println("error:"+ls.get(i));
}
}
return "adduser";
}
public class Apple {
private Integer id;
private String name;
private BigDecimal money;
private Integer num;
/*构造函数*/
}
List
appleList = new ArrayList<>();//存放apple对象集合 Apple apple1 = new Apple(1,"苹果1",new BigDecimal("3.25"),10);
Apple apple12 = new Apple(1,"苹果2",new BigDecimal("1.35"),20);
Apple apple2 = new Apple(2,"香蕉",new BigDecimal("2.89"),30);
Apple apple3 = new Apple(3,"荔枝",new BigDecimal("9.99"),40);
appleList.add(apple1);
appleList.add(apple12);
appleList.add(apple2);
appleList.add(apple3);
Map
appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));
推荐阅读:
面试官:你画的SpringMVC请求处理过程是从网上抄的吧?
微信扫描二维码,关注我的公众号
朕已阅
评论