1、为什么Controller层注入的是Service接口,而不是ServiceImpl实现类
Controller层
@Autowired
private TestImpl testImpl; //注入了实现类
面向接口编程
(1)注入的就是实现类,只不过拿接口来接收,接收的类型为接口,面向接口编程,那么为何要面向接口编程?这就涉及到使用接口做代理,因为通过@autowired的对象是通过接口的方式会使用jdk动态代理,jdk动态代理只能对实现接口的类生成代理,而不能针对类。
(2)注入的是实现类对象,接收的是接口;理解为多态;
要遵循Controller–Service接口–ServiceImpt实现类–Mapper接口模式;
2、分布式锁三种实现方式
(1)、 基于数据库实现分布式锁;
(2)、基于缓存(Redis等)实现分布式锁;
(3)、 基于Zookeeper实现分布式锁;
一、基于数据库实现分布式锁
1. 悲观锁
利用select … where … for update 排他锁
注意: 其他附加功能与实现一基本一致,这里需要注意的是“where name=lock ”,name字段必须要走索引,否则会锁表。有些情况下,比如表不大,mysql优化器会不走这个索引,导致锁表问题。
2. 乐观锁
所谓乐观锁与前边最大区别在于基于CAS思想,是不具有互斥性,不会产生锁等待而消耗资源,操作过程中认为不存在并发冲突,只有update version失败后才能觉察到。我们的抢购、秒杀就是用了这种实现以防止超卖。
通过增加递增的版本号字段实现乐观
3:分布式锁三种实现方式对比:
数据库分布式锁实现
缺点:
1.db操作性能较差,并且有锁表的风险
2.非阻塞操作失败后,需要轮询,占用cpu资源;
3.长时间不commit或者长时间轮询,可能会占用较多连接资源
Redis(缓存)分布式锁实现
缺点:
1.锁删除失败 过期时间不好控制
2.非阻塞,操作失败后,需要轮询,占用cpu资源;
ZK分布式锁实现
缺点:性能不如redis实现,主要原因是写操作(获取锁释放锁)都需要在Leader上执行,然后同步到follower。
总之:ZooKeeper有较好的性能和可靠性。
从理解的难易程度角度(从低到高)数据库 > 缓存 > Zookeeper
从实现的复杂性角度(从低到高)Zookeeper >= 缓存 > 数据库
从性能角度(从高到低)缓存 > Zookeeper >= 数据库
从可靠性角度(从高到低)Zookeeper > 缓存 > 数据库
4、Kafka、RocketMQ、RabbitMQ的对比
RabbitMq
- 由于erlang语言的特性,mq 性能较好,高并发;
- 吞吐量到万级,MQ功能比较完备;
- 健壮、稳定、