
锁列表共享与列排他锁意向锁记录锁间隙锁Next-Key锁插入意向锁AUTO-INC锁这次我们只来讨论和实验意向锁。插入意向锁插入意向锁是一种间隙锁形式的意向锁,在真正执行 INSERT 操作之前设置。当执行插入操作时,总会检查当前插入操作的下一条记录(已存在的主索引节点)上是否存在锁对象,判断是否锁住了 gap,如果锁住了,则判定和插入意向锁冲突,当前插入操作就需要等待,也就是配合上面的间隙锁或者临键锁一起防止了幻读操作。因为插入意向锁是一种意向锁,意向锁只是表示一种意向,所以插入意向锁之间不会互相冲突,多个插入操作同时插入同一个 gap 时,无需互相等待,比如当前索引上有记录 4 和 8,两个并发 session 同时插入记录 6,7。他们会分别为(4,8)加上 GAP 锁,但相互之间并不冲突INSERT 语句在执行插入之前,会先在 gap 中加入插入意向锁,如果是唯一索引,还会进行 Duplicate Key 判断,如果存在相同 Key 且该 Key 被加了互斥锁,则还会加共享锁,然后等待(因为这个相同的 Key 之后有可能会回滚删除,这里非常容易死锁)。等到成功插入后,会在这条记录上加排他记录锁实验建表语句:CREATE TABLE `sys_user` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '姓名', `name_pinyin` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '姓名拼音', `id_card` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '身份证号', `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '手机号', `age` int(11) NOT NULL DEFAULT 1 COMMENT '年龄', PRIMARY KEY (`id`), UNIQUE KEY `uni_idx_id_card` (`id_card`) USING BTREE COMMENT '唯一索引-身份证号', KEY `idx_phone_name` (`phone`,`name`) USING BTREE COMMENT '普通索引-手机号' ) ENGINE=InnoDB AUTO_INCREMENT=3495 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户' 插入记录insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (1, '小六', 'xiaoliu', 300000000, 13000008000, 10); insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (2, '小六', 'xiaoliu', 300000001, 13000008000, 11); insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (3, '小六', 'xiaoliu', 300000002, 13000008000, 13); insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (4, '小六', 'xiaoliu', 300000003, 13000008000, 20); 记录锁插入意向锁插入间隙锁区间内(age字段)阻塞等待时刻事务A事务B1begin;begin;2select * from sys_user where age=13 for update; (在11和20之间添加了间隙锁)) 3 insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (5, '小六', 'xiaoliu', 300000004, 13000008000, 12);(阻塞等待)在事务B阻塞等待时,使用show engine innodb status查看事务(内容删除了一部分):---TRANSACTION 133643386, ACTIVE 34 sec inserting insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (5, '小六', 'xiaoliu', 300000004, 13000008000, 19) ------- TRX HAS BEEN WAITING 28 SEC FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 484 page no 46 n bits 80 index idx_age of table `employees`.`sys_user` trx id 133643386 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 5 ------------------两个插入意向锁插入相同间隙(age字段)正常插入时刻事务A事务B1begin;begin;2insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (5, '小六', 'xiaoliu', 300000004, 13000008000, 19); 3 insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (6, '小六', 'xiaoliu', 300000005, 13000008000, 18);两个插入意向锁(age字段)死锁时刻事务A事务B1begin;begin;2select * from sys_user where age=14 for update;select * from sys_user where age=14 for update;3insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (6, '小六', 'xiaoliu', 300000005, 13000008000, 14); (事务A和B插入相同记录) 4 insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (6, '小六', 'xiaoliu', 300000005, 13000008000, 14); (事务A和B插入相同记录)死锁日志------------------------ LATEST DETECTED DEADLOCK ------------------------ 2022-03-01 15:04:27 140684024923904 *** (1) TRANSACTION: TRANSACTION 133654731, ACTIVE 29 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1 MySQL thread id 4796, OS thread handle 140684279383808, query id 5765383 192.168.1.83 root update insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (6, '小六', 'xiaoliu', 300000005, 13000008000, 14) *** (1) HOLDS THE LOCK(S): RECORD LOCKS space id 484 page no 4 n bits 80 index PRIMARY of table `employees`.`sys_user` trx id 133654731 lock_mode X locks rec but not gap Record lock, heap no 6 PHYSICAL RECORD: n_fields 8; compact format; info bits 128 0: len 4; hex 80000006; asc ;; 1: len 6; hex 000007f768cb; asc h ;; 2: len 7; hex 81000000ac0110; asc ;; 3: len 6; hex e5b08fe585ad; asc ;; 4: len 7; hex 7869616f6c6975; asc xiaoliu;; 5: len 9; hex 333030303030303035; asc 300000005;; 6: len 11; hex 3133303030303038303030; asc 13000008000;; 7: len 4; hex 8000000e; asc ;; *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 484 page no 46 n bits 80 index idx_age of table `employees`.`sys_user` trx id 133654731 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 5 *** (2) TRANSACTION: TRANSACTION 133654788, ACTIVE 22 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 4798, OS thread handle 140684407801600, query id 5765426 192.168.1.83 root update insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (6, '小六', 'xiaoliu', 300000005, 13000008000, 14) *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 484 page no 46 n bits 80 index idx_age of table `employees`.`sys_user` trx id 133654788 lock_mode X locks gap before rec Record lock, heap no 5 *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 484 page no 4 n bits 80 index PRIMARY of table `employees`.`sys_user` trx id 133654788 lock mode S locks rec but not gap waiting Record lock, heap no 6 PHYSICAL RECORD: n_fields 8; compact format; info bits 128 0: len 4; hex 80000006; asc ;; 1: len 6; hex 000007f768cb; asc h ;; 2: len 7; hex 81000000ac0110; asc ;; 3: len 6; hex e5b08fe585ad; asc ;; 4: len 7; hex 7869616f6c6975; asc xiaoliu;; 5: len 9; hex 333030303030303035; asc 300000005;; 6: len 11; hex 3133303030303038303030; asc 13000008000;; 7: len 4; hex 8000000e; asc ;;资源分配图个人分析死锁图应该是这样的:注意死锁回滚时,InnoDB会选择资源最小的那个事务进行回滚。不用过度担心死锁,因为死锁事务回滚后再次重试就可以了。参考https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-record-lockshttps://www.infoq.cn/article/zau0ewzsdtx9zofr6c8whttps://segmentfault.com/a/1190000019745324
1、命名规范1、【强制】Topic命名:topic+下划线+业务名,例如:订单领域topic命名为:topic_order。2、【强制】tag命名:tag+下划线+业务动作,比如:订单创建的tag为:tag_create;订单关闭的tag为:tag_close。3、【强制】生产者分组命名:pg+下划线+业务名,例如:订单创建生产者发送订单创建消息,那么生产者分组名为:pg_order4、【强制】消费者分组命名:cg+下划线+业务名+下划线+订阅topic名称+下划线+订阅tag名称。 例如:订单创建消息topic为topic_order,tag为tag_create,消息生产者为订单服务,用户服务和支付服务需要消费这条消息,那么用户服务的消费者分组命名为cg_user_order_create,支付服务的消费者分组命名为cg_payment_order_create。2、使用规范【生产者】2.1【强制】一个领域服务只能有一个topic。2.2【强制】领域服务发送消息时必须根据业务动作设置tag。2.3【强制】在Producer发送消息时必须设置keys。2.4【强制】消息发送成功或者失败要打印消息日志,务必要打印SendResult和key字段。2.5【建议】消息发送失败后建议将消息存储到db,然后由定时器类线程进行定时重试,确保消息达到broker。2.6【建议】对于可靠性要求不高的业务场景可以使用oneway消息。2.7 【强制】新建生产者时必须指定生产者分组。【消费者】2.8【强制】新建消费者时必须指定消费者分组。2.9【强制】消息消费者无法避免消息重复,所以需要业务服务来保证消息消费幂等。2.10【建议】为了提高消费并行度,可以在同一个ConsumerGroup下启动多个Consumer实例或者通过修改ConsumeThreadMin和consumeThreadMax来提高单个Consumer的并行消费能力。2.11【建议】为了增加业务吞吐量,可以通过设置consumer的consumeMessageBatchMaxSize来批量消费消息。2.12 【建议】发生消息堆积时,如果业务对数据要求不高时,可以选择丢弃不重要的消息。2.13【建议】如果消息量较少,建议在消费入口打印消息、消费耗时等,方便后续排查问题。3、申请规范3.1 【强制】在新建topic时必须进行申请,申请形式为:填写申请表,评审通过方可使用4、参考4.1 RocketMQ最佳实践:https://github.com/apache/rocketmq/blob/master/docs/cn/best_practice.md
我们今天来看下事件驱动架构,这个架构主要包括两种拓扑,调度者(Mediator)和代理(Broker)。我们今天主要看一下调度者拓扑。 事件驱动架构模式是一个非常流行的分布式异步架构模式,用来构建高度可扩展性高的应用程序。它也具有高度的适应性,并且可以用来构建小型应用和复杂的大型应用。事件驱动架构是由高度解耦,单一目的的事件处理组件组成,可以异步接收和处理事件。 事件驱动架构模式主要有两个主要的拓扑组成,调度者和代理者。调度者拓扑通常当你需要中心化的调度者通过一个事件协调完成多个步骤的操作时使用,而代理者拓扑则当你想要完成事件链,但是不想要中心化的调度者时使用。由于这两种拓扑的架构特性和实现策略不同,所以对这两种拓扑的深入了解能够使你在具体的场景中能够更好的做出选择。 调度者拓扑 当事件由多个步骤组成,且需要协调执行事件时,就是调度者拓扑的使用场景。例如:股票交易:一个股票交易事件可能需要:验证交易验证股票交易的各种规则将交易分配给代理人,并计算佣金最后再将交易放给代理人这些步骤需要一定程度的协调以确定哪些步骤是顺序或并行执行。 调度者拓扑有四个主要的架构组件:事件队列,事件调度者,事件通道,事件处理器。整个事件流以客户端发送一个事件到事件队列为起点,将事件传输到事件调度者。事件调度者接收到初始化事件后,通过发送额外的异步事件到事件通道来执行每一步的处理。事件处理器监听事件通道,接收来自事件调度者的事件,并执行事件的具体业务逻辑。下图展示了事件驱动架构中一般的调度者拓扑: 架构可能有上百个事件队列。事件驱动架构模式并指定执行事件队列组件的具体实现;事件对应可能是一个消息队列,WebService,或者两者的混合体。 调度者拓扑有两种类型的事件:初始化事件和处理事件。初始化事件是调度者接收到的事件,处理事件是由调度者生成的,并由事件处理组件接收。 事件调度者组件负责协调初始化事件涉及的所有子步骤。在初始化事件阶段,事件调度者发送具体的处理事件到事件通道,事件处理器接收到事件并处理它。注意:事件调度者并不执行业务逻辑去处理初始化事件,而是将初始化事件分解为多个子步骤/事件。 事件通道是用于事件调度者异步传递多个具体的处理事件到事件处理器。事件通道既可以是消息队列,也可以是消息主题,尽管消息主题被广泛用于调度者拓扑以满足处理事件能够被多个事件处理器处理(基于接收到的事件来执行不同的任务)。 事件处理器组件包含处理事件所需要的应用业务逻辑。事件处理器是自我界定的,独立的,高度解耦的架构组件,在应用程序或系统中执行具体的任务(业务逻辑)。每个事件处理器可以有不同的业务粒度,细粒度(例如:计算订单的销售税),粗粒度(处理保险索赔)。重要:一个事件处理器应该处理单一的业务逻辑,并且不要依赖其他事件处理的来完成它的业务。 事件调度者的实现可以有多种方式。作为架构师,你应该深入理解每个实现方式,以确保你选择的事件调度者能够满足你的业务需求。 最简单和通用的事件调度者是使用开源组件,例如:Spring Integeration,Apache Camel 或者Mule ESB。在这些开源组件中,通过Java代码或者DSL实现了事件流。对于更复杂的调度和编排,你可以使用BPEL(业务流程执行语言)和BPEL引擎(如:开源Apche ODE)来完成。BPEL是类似于标准XML语言,来描述数据和初始化事件的处理步骤。对于大型应用如果需要更复杂的编排(包括人机交互的步骤),你可以使用业务流程管理来实现调度者,例如jBPM。 使用调度者拓扑的关键是理解你的需求并使用正确的调度者实现。使用开源组件来实现非常复杂的业务流程管理编排是一种错误的做法,就像使用BPM解决方案来执行简单的路由逻辑一样。 为了说明调度者拓扑是如何工作的,假设你通过保险公司投保,然后你需要搬家。在这种情况下,初始化事件可以称为搬家事件。调度者处理一个搬家事件的步骤可能包括下图内容:在初始化事件步骤,事件调度者创建一个处理事件(例如:改变地址,重新计算价格等),发送处理事件到事件通道,并等待事件处理器将事件处理完成(例如:用户处理器,价格处理器等)。这些流程会一直持续直到初始化事件处理完成。每一个箭头代表这个这些步骤可以同步进行(比如:Recalc Quote和UpdateClaims)。 以上内容即事件驱动架构的调度者拓扑,代理拓扑(Broker topology)将会在下一篇来说明。
引言微服务架构模式作为单体应用和面向服务架构(SOA)的可行替代方案,已经迅速在业界占领了一席之地。由于微服务架构模式还在持续演进中,所以业界对于它是干什么的,以及如何实现它还有很多的疑惑。这部分内容将给你提供必要的关键概念和基础知识,以及微服务架构模式的利弊和它是否适合你的应用。模式描述不论你选择何种拓扑结构或者实现风格,都有几个通用的核心概念来应用到通用架构模式中。第一个核心概念是独立部署单元。如下图,微服务架构中的每个组件都是独立的单元,能够通过有效且流线型的交付管道来提高可伸缩性,高度的将应用和组件解耦。可能理解微服务架构模式最重要的概念是服务组件的理解。大型应用通过良好定义的粒度来拆分成服务组件。服务组件通常有一个或多个模块(例如:java类)可以提供单一目的方法(例如:提供一个具体城镇的天气)或者是一个大型应用的一部分(例如:股票交易或者保险理赔)。设计一个合理的服务组件粒度是微服务架构模式最大的挑战。在后面的服务组件编排部分将会对这个挑战进行更多的讨论。服务架构中的另一个关键概念是分布式架构,这意味着所有的服务组件互相是解耦的,并且可以通过一些远程访问协议进行访问(例如:JMS,AMPQ,REST,SOAP,RMI等)。微服务架构的分布式特性使他可以更好可扩展性以及部署特性。微服务架构是从其他通用架构模式遇到的一些问题演进而来,而不是被创造解决未来遇到的问题。微服务体系架构从两个主要的来源演进而来:使用分层架构的单体应用和通过面向服务的分布式架构。微服务一个演进路线是单体应用。从单体应用到微服务架构主要通过持续交付来实现,从开发到生产环境的持续部署管道概念简化了应用程序的部署。单体应用与它的组件为紧耦合的单个发布单元,这使得单体应用庞大,修改,测试和发布都很困难。通常这些因素都会导致单体应用在每次部署更新时都会遇到更多问题。微服务架构模式通过将应用程序分解为多个独立部署的单元解决了这些问题,这些部署单元称为服务组件,这些服务组件之间独立开发,测试和发布。微服务的另一个演进路线是SOA。SOA模式非常强大,且提供了前所未有的抽象,异构连接,服务编排,将业务功能与IT能力结合起来,但是它对于大部分应用是复杂,昂贵,普遍难以理解与实现。微服务架构通过服务组件概念解决了这些复杂性问题,消除服务编排的需求并简化了服务组件的连接与访问。模式拓扑有很多方式可以实现微服务架构模式,但是有三个的架构拓扑脱颖而出:基于REST API拓扑基于应用REST拓扑集中消息拓扑基于REST API拓扑主要用于网站通过某种形式的API对外暴露小且独立的服务。下图展示了这个拓扑。这个拓扑由细粒度的服务组件组成,每个服务组件包含一个或者多个模块,每个模块负责实现具体的业务逻辑,每个服务组件独立于其他服务组件。在这个拓扑中,通常使用基于REST接口的形式封装这些细粒度的服务,并且这些服务通过基于Web的API层独立发布。基于应用的拓扑与基于REST API拓扑不同的是,客户端的请求通过传统的基于web或者胖客户端的业务应用接收而不是API层。如下图,应用程序的用户层通过独立的web应用进行发布,用户层服务与服务组件通过REST接口进行访问。基于应用的服务组件与及基于REST API服务组件的不同之处在于:基于应用的服务组件一般会更大(更粗粒度),代表着整个业务应用的一部分功能,而不是细粒度,单一的服务。基于应用的拓扑通常应用于中小业务应用,这些业务应用一般业务复杂性相对较低。另一个拓扑模式是集中式消息拓扑。这个拓扑与基于应用的拓扑类似,但是通过轻量级消息代理进行远程访问,而不是使用REST。不要把这个拓扑结构当成SOA或者SOA-lite架构。在这个拓扑中的轻量级消息代理并不执行任何编排,转换,或者复杂的路由(请参考消息驱动架构-Mediator);它只是在拓扑中承担轻量级服务访问的传输。集中式的消息拓扑经常用于大型业务应用或者需要在用户层和服务组件之间需要复杂的业务控制传输层。避免服务依赖和编排微服务架构模式的一个主要挑战是确定服务组件的一个正确粒度。如果服务组件粒度太粗,你可能又回归到单体应用了(发布,扩展,测试与松耦合统统都丢了)。然而,如果服务组件过于细粒度,就会需要服务编排,那么这就会导致你的微服务变成重量级SOA。如果你发现你需要在应用的用户层或者API层编排服务组件,那么你的微服务中的服务组件就是过于细分(粒度太细)。与之类似,如果你发现为了处理一个请求,你需要进行服务间通信,那么,你的服务组件划分的过于细粒度或者他们并没有根据业务功能进行正确拆分。服务间通信,会导致服务与服务的依赖,但是可以通过共享数据库解决。例如,如果一个服务组件需要处理互联网订单,订单需要查询用户信息,这种业务可以通过访问共享数据库得到这些信息,而不是调用用户服务组件的功能获取。共享数据库可以处理数据需求,但是共享功能如何做?如果一个服务组件需要的功能在另一个服务组件中或者其他通用服务组件中,有时可以复制共享功能在这个服务组件中(违反了DRY原则:don't repeat yourself)。但是在大部分实现了微服务架构模式的业务应用中,这个实践非常常用。权衡一些业务逻辑的冗余,使得服务组件之间能够相互独立,并能能够独立发布。一些工具类可能会分到这些重复代码目录中。如果你发现,不管服务粒度细分的粗或者细,你依然无法避免服务组件的编排,那么微服务架构可能不适合你的业务应用。由于微服务架构模式的分布式特性,一个事务的跨服务调用是难以维护的。微服务架构可能需要一个分布式事务框架来回滚事务,但是这会增加微服务架构的复杂性。架构思考微服务架构解决了很多单体应用和SOA中的常见问题。由于主体服务组件被拆分成小且独立发布的单元,使用微服务架构模式的构建的应用,通常健壮的,很好的扩展性,可以很容易的支持持续交付。微服务架构模式的另一个好处是,它提供了一个实时产品发布能力,因此能够有效的减少传统应用的月度或者周度产品发布。由于服务组件之间通常是独立修改的,那么只有这个服务组件需要发布。如果你只有一个服务组件的实例,那么你可以在发布期间在用户层检测服务组件是否正在热发布中,然后将用户重定向到错误页面或者等待页面。但是,你也可以在实时发布期间,启动多个服务组件实例,这样可以在服务发布期间能够持续提供服务(在基于分层架构模式的应用,有时这是非常困难的)。最后一个需要考虑的是,由于微服务架构也是分布式架构,一些复杂的问题解决需要事件驱动架构模式,包括关系建立,维护,管理,远程系统可用性和远程访问认证与授权。模式分析敏捷性:高由于独立部署单元的概念,所以服务组件之间修改是隔离的,因此服务组件能够更快且容易发布。服务与服务之间松耦合,所以能够更快的响应变化。易于部署:高一般服务组件部署都是独立的软件单元,因此拥有在任何时候能够进行热部署。同时部署风险也大大降低,部署失败可以更快的回滚到老版本。可测试性:高将一个大型应用拆分成独立的小应用,测试可以被界定,能够更有针对性的进行功能测试。对一个特定服务组件的测试更容易,且更容易实施。服务组件是松耦合的,这样在修改服务的时候就不会中断应用的其他服务组件。性能:低微服务的分布式特性就不是高性能的应用架构。可扩展性:高每个服务组件独立扩展。易于开发:高服务小且独立范围界定,使得开发更容易,减少团队之间的协作。
项目地址https://github.com/TheLandscapeBe/tinyurl.git项目地址短连接生成服务# 什么是短连接生成? 短连接生成就是把普通网址转换成比较换的地址。 例如:一个很长的链接地址:https://developer.aliyun.com/article/829833?spm=a2c6h.13148508.0.0.67134f0ewKO0ri需要发发布给用户,而用户不能接收这么长的内容,那么就需要将这个很长的链接地址转换为用户能够接收的长度,这就是短连接生成,其实就是一个转换。 # 适用场景短信短信中带有链接不能过长,因为可能会截断为几条短信,将原长链接转换为短连接可以在一条短信内向用户展示全部文件和连接内容。二维码链接生成二维码。如果连接过长会导致扫码速度和成功率下降,将长链接转换为短连接再生成二维码将大大提高扫码速度和成功率。短链接生成算法ID自增算法ID自增算法目前使用MySQL数据库自增ID实现,所以生成的短连接会表现出顺序增加特点: 比如:根据请求顺序,短连接生成会为以下地址:https://xxx.xx.com/a https://xxx.xx.com/b https://xxx.xx.com/c ...snowflake算法生成ID后,使用62进制进行编码得到短链接key,一般会获得9位字符串算法对比1 ID自增算法 目前ID自增算法基于MySQL ID自增算法,不利于扩展,适用于小型应用2 snowflake算法 snowflake算法为twitter设计,特点ID有序且为数字,适合中大型应用进制算法编码核心计算1 选取字母表ALPHABET=[0-9a-zA-Z],字母表长度ALPHABET_LENGTH=62,所有使用62进制,private static String encode(long number) { StringBuilder chip = new StringBuilder(9); while (number > 0) { int mod = (int)(number % ALPHABET_LENGTH); chip.append(ALPHABET.charAt(mod)); number -= mod; number /= ALPHABET_LENGTH; } return chip.reverse().toString(); } 解码核心计算private static long decode(String key) { long number = 0L; for (int i = 0; i < key.length(); i++) { long pow = pow(key, i); number += pow * ALPHABET.indexOf(key.charAt(i)); } return number; } private static long pow(String key, int i) { long pow = 1L; for (int j = 0; j < key.length() - i - 1; j++) { pow *= ALPHABET_LENGTH; } return pow; }## 如何使用? ### 数据库初始化 数据库初始化脚本CREATE DATABASE `tiny_urldb` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; CREATE TABLE `application` ( `id` int NOT NULL AUTO_INCREMENT, `access_key` varchar(256) NOT NULL DEFAULT '' COMMENT '密钥', `name` varchar(256) NOT NULL DEFAULT '' COMMENT '应用名称', `create_time` datetime NOT NULL COMMENT '创建时间', `app_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '应用ID', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='应用'; CREATE TABLE `domain` ( `id` int NOT NULL AUTO_INCREMENT, `domain` varchar(256) NOT NULL DEFAULT '' COMMENT '域名', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='域名'; CREATE TABLE `url` ( `id` bigint NOT NULL AUTO_INCREMENT, `origin_url` varchar(5000) NOT NULL DEFAULT '' COMMENT '原始URL', `hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '原始URL MD5哈希值', `create_time` datetime NOT NULL, `expire_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='URL记录';增加测试应用 INSERT INTO `application` VALUES ('1', '1594708959736', '测试应用', '2020-07-14 14:43:12', '1594708959736');增加测试域名INSERT INTO `domain` VALUES ('1', 'e.example.com');服务部署服务数据可以使用jar部署,docker镜像部署使用jar包部署1.1 代码克隆git clone https://github.com/fofcn/tinyurl.git1.2 代码打包为jarcd tinyurl mvn clean package -Dmaven.test.skip=true cd target java -jar -Xms128M -Xmx256M tinyurl.jar编译docker镜像部署2.1 代码下载git clone https://github.com/fofcn/tinyurl.git2.2 代码打包为镜像docker login docker build -t tinyurl . docker tag tinyurl ${registry}/name/image-name:${tag} docker push ${registry}/name/image-name:${tag} #例如在我的环境中执行命令 docker login docker build -t tinyurl . docker tag tinyurl fofcn/tinyurl:v0.2.0 docker push fofcn/tinyurl2.3 使用docker镜像部署 (目前docker镜像已经上传到doker hub,直接使用fofcn/tinyurl获取镜像即可)2.3.1 编写docker-compose.yml# MAINTAINER: errorfatal89@gmail.com version: '3' networks: your-network-name: driver: bridge services: tinyurl: container_name: tinyurl image: fofcn/tinyurl:v1.3.0 restart: always ports: - "53000:53000" volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /app/applog/tinyurl:/app/applog/tinyurl networks: your-network-name: environment: - SERVER_PORT=53000 # 目前支持dev:开发人员使用,test:测试人员使用,prod:生产环境使用 - SPRING_PROFILES_ACTIVE=dev - SPRING_SHARDINGSPHERE_DATASOURCE_MASTER_URL=jdbc:mysql://localhost:3306/tiny_urldb?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 - SPRING_SHARDINGSPHERE_DATASOURCE_MASTER_USERNAME=tinyurl_user - SPRING_SHARDINGSPHERE_DATASOURCE_MASTER_PASSWORD=Yy123456. - SPRING_SHARDINGSPHERE_DATASOURCE_SLAVE0_URL=jdbc:mysql://localhost:3306/tiny_urldb?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 - SPRING_SHARDINGSPHERE_DATASOURCE_SLAVE0_USERNAME=tinyurl_user - SPRING_SHARDINGSPHERE_DATASOURCE_SLAVE0_PASSWORD=Yy123456. # v1.3.0新增配置 # dataCenterId与WorkerId在多节点部署时必须指定且组合唯一 - TINYURL_SNOWFLAKE_DATACENTERID=0 - TINYURL_SNOWFLAKE_WORKERID=0 # 配置域名http或https - TINYURL_HTTPSCHEME=https2.3.2 docker-compose启动docker-compose up -d# 接口列表生成短链接打开短链接
2022年03月
2022年02月
2022年01月