当前位置: 首页 > news >正文

怎么把网站关掉wordpress小白

怎么把网站关掉,wordpress小白,大型seo公司,网站怎样运营导读 明代著名的心学集大成者王阳明先生在《传习录》中有云#xff1a; 道无精粗#xff0c;人之所见有精粗。如这一间房#xff0c;人初进来#xff0c;只见一个大规模如此。处久#xff0c;便柱壁之类#xff0c;一一看得明白。再久#xff0c;如柱上有些文藻#x…导读 明代著名的心学集大成者王阳明先生在《传习录》中有云 道无精粗人之所见有精粗。如这一间房人初进来只见一个大规模如此。处久便柱壁之类一一看得明白。再久如柱上有些文藻细细都看出来。然只是一间房。 是的知识理论哪有什么精粗之分只是人的认识程度不同而已。笔者在初创公司摸爬滚打数年接触了各式各样的Java服务端架构见得多了自然也就认识深了就能分辨出各种方案的优劣了。这里笔者总结了一些初创公司存在的Java服务端问题并尝试性地给出了一些不成熟的解决方案。 1.系统不是分布式 随着互联网的发展计算机系统早就从单机独立工作过渡到多机器协同工作。计算机以集群的方式存在按照分布式理论构建出庞大复杂的应用服务早已深入人心并得到广泛地应用。但是仍然有不少创业公司的软件系统停留在单机版。 1.1.单机版系统抢单案例 这里用并发性比较高的抢单功能为例说明 // 抢取订单函数 public synchronized void grabOrder(Long orderId, Long userId) {// 获取订单信息OrderDO order orderDAO.get(orderId);if (Objects.isNull(order)) {throw new BizRuntimeException(String.format(订单(%s)不存在, orderId));}// 检查订单状态if (!Objects.equals(order.getStatus, OrderStatus.WAITING_TO_GRAB.getValue())) {throw new BizRuntimeException(String.format(订单(%s)已被抢, orderId));}// 设置订单被抢orderDAO.setGrabed(orderId, userId); } 以上代码在一台服务器上运行没有任何问题。进入函数grabOrder抢取订单时利用synchronized关键字把整个函数锁定要么进入函数前订单未被人抢取从而抢取订单成功要么进入函数前订单已被抢取导致抢取订单失败绝对不会出现进入函数前订单未被抢取而进入函数后订单又被抢取的情况。 但是如果上面的代码在两台服务器上同时运行由于Java的synchronized关键字只在一个虚拟机内生效所以就会导致两个人能够同时抢取一个订单但会以最后一个写入数据库的数据为准。所以大多数的单机版系统是无法作为分布式系统运行的。 1.2.分布式系统抢单案例 添加分布式锁进行代码优化 // 抢取订单函数 public void grabOrder(Long orderId, Long userId) {Long lockId orderDistributedLock.lock(orderId);try {grabOrderWithoutLock(orderId, userId);} finally {orderDistributedLock.unlock(orderId, lockId);} }// 不带锁的抢取订单函数 private void grabOrderWithoutLock(Long orderId, Long userId) {// 获取订单信息OrderDO order orderDAO.get(orderId);if (Objects.isNull(order)) {throw new BizRuntimeException(String.format(订单(%s)不存在, orderId));}// 检查订单状态if (!Objects.equals(order.getStatus, OrderStatus.WAITING_TO_GRAB.getValue())) {throw new BizRuntimeException(String.format(订单(%s)已被抢, orderId));}// 设置订单被抢orderDAO.setGrabed(orderId, userId); } 优化后的代码在调用函数grabOrderWithoutLock不带锁的抢取订单前后利用分布式锁orderDistributedLock订单分布式锁进行加锁和释放锁跟单机版的synchronized关键字加锁效果基本一样。 1.3.分布式系统的优缺点 分布式系统Distributed System是支持分布式处理的软件系统是由通信网络互联的多处理机体系结构上执行任务的系统包括分布式操作系统、分布式程序设计语言及其编译系统、分布式文件系统分布式数据库系统等。 分布式系统的优点 可靠性、高容错性 一台服务器的崩溃不会影响其它服务器其它服务器仍能提供服务。 可扩展性 如果系统服务能力不足可以水平扩展更多服务器。 灵活性 可以很容易的安装、实施、扩容和升级系统。 性能高 拥有多台服务器的计算能力比单台服务器处理速度更快。 性价比高 分布式系统对服务器硬件要求很低可以选用廉价服务器搭建分布式集群从而得到更好的性价比。 分布式系统的缺点 排查难度高 由于系统分布在多台服务器上故障排查和问题诊断难度较高。 软件支持少 分布式系统解决方案的软件支持较少。 建设成本高 需要多台服务器搭建分布式系统。 曾经有不少的朋友咨询我找外包做移动应用需要注意哪些事项 首先确定是否需要用分布式系统。软件预算有多少预计用户量有多少预计访问量有多少是否只是业务前期试水版单台服务器能否解决是否接收短时间宕机……如果综合考虑单机版系统就可以解决的那就不要采用分布式系统了。因为单机版系统和分布式系统的差别很大相应的软件研发成本的差别也很大。 其次确定是否真正的分布式系统。分布式系统最大的特点就是当系统服务能力不足时能够通过水平扩展的方式通过增加服务器来增加服务能力。然而单机版系统是不支持水平扩展的强行扩展就会引起一系列数据问题。由于单机版系统和分布式系统的研发成本差别较大市面上的外包团队大多用单机版系统代替分布式系统交付。那么如何确定你的系统是真正意义上的分布式系统呢从软件上来说是否采用了分布式软件解决方案从硬件上来说是否采用了分布式硬件部署方案。 1.4.分布式软件解决方案 作为一个合格的分布式系统需要根据实际需求采用相应的分布式软件解决方案。 1.4.1.分布式锁 分布式锁是单机锁的一种扩展主要是为了锁住分布式系统中的物理块或逻辑块用以此保证不同服务之间的逻辑和数据的一致性。 目前主流的分布式锁实现方式有3种 基于数据库实现的分布式锁基于Redis实现的分布式锁基于Zookeeper实现的分布式锁。 1.4.2.分布式消息 分布式消息中间件是支持在分布式系统中发送和接受消息的软件基础设施。常见的分布式消息中间件有ActiveMQ、RabbitMQ、Kafka、MetaQ等。 MetaQ全称Metamorphosis是一个高性能、高可用、可扩展的分布式消息中间件思路起源于LinkedIn的Kafka但并不是Kafka的一个拷贝。MetaQ具有消息存储顺序写、吞吐量大和支持本地和XA事务等特性适用于大吞吐量、顺序消息、广播和日志数据传输等场景。 1.4.3.数据库分片分组 针对大数据量的数据库一般会采用分片分组策略 分片(shard)主要解决扩展性问题属于水平拆分。引入分片就引入了数据路由和分区键的概念。其中分表解决的是数据量过大的问题分库解决的是数据库性能瓶颈的问题。 分组(group)主要解决可用性问题通过主从复制的方式实现并提供读写分离策略用以提高数据库性能。 1.4.4.分布式计算 分布式计算( Distributed computing )是一种把需要进行大量计算的工程数据分割成小块由多台计算机分别计算在上传运算结果后将结果统一合并得出数据结论的科学。 当前的高性能服务器在处理海量数据时其计算能力、内存容量等指标都远远无法达到要求。在大数据时代工程师采用廉价的服务器组成分布式服务集群以集群协作的方式完成海量数据的处理从而解决单台服务器在计算与存储上的瓶颈。Hadoop、Storm以及Spark是常用的分布式计算中间件Hadoop是对非实时数据做批量处理的中间件Storm和Spark是对实时数据做流式处理的中间件。 除此之外还有更多的分布式软件解决方案这里就不再一一介绍了。 1.5.分布式硬件部署方案 介绍完服务端的分布式软件解决方案就不得不介绍一下服务端的分布式硬件部署方案。这里只画出了服务端常见的接口服务器、MySQL数据库、Redis缓存而忽略了其它的云存储服务、消息队列服务、日志系统服务…… 1.5.1.一般单机版部署方案 架构说明 只有1台接口服务器、1个MySQL数据库、1个可选Redis缓存可能都部署在同一台服务器上。 适用范围 适用于演示环境、测试环境以及不怕宕机且日PV在5万以内的小型商业应用。 1.5.2.中小型分布式硬件部署方案 架构说明 通过SLB/Nginx组成一个负载均衡的接口服务器集群MySQL数据库和Redis缓存采用了一主一备或多备的部署方式。 适用范围 适用于日PV在500万以内的中小型商业应用。 1.5.3.大型分布式硬件部署方案 架构说明 通过SLB/Nginx组成一个负载均衡的接口服务器集群利用分片分组策略组成一个MySQL数据库集群和Redis缓存集群。 适用范围 适用于日PV在500万以上的大型商业应用。 2.多线程使用不正确 多线程最主要目的就是最大限度地利用CPU资源可以把串行过程变成并行过程从而提高了程序的执行效率。 2.1.一个慢接口案例 假设在用户登录时如果是新用户需要创建用户信息并发放新用户优惠券。例子代码如下 // 登录函数(示意写法) public UserVO login(String phoneNumber, String verifyCode) {// 检查验证码if (!checkVerifyCode(phoneNumber, verifyCode)) {throw new ExampleException(验证码错误);}// 检查用户存在UserDO user userDAO.getByPhoneNumber(phoneNumber);if (Objects.nonNull(user)) {return transUser(user);}// 创建新用户return createNewUser(user); }// 创建新用户函数 private UserVO createNewUser(String phoneNumber) {// 创建新用户UserDO user new UserDO();...userDAO.insert(user);// 绑定优惠券couponService.bindCoupon(user.getId(), CouponType.NEW_USER);// 返回新用户return transUser(user); } 其中绑定优惠券bindCoupon是给用户绑定新用户优惠券然后再给用户发送推送通知。如果随着优惠券数量越来越多该函数也会变得越来越慢执行时间甚至超过1秒并且没有什么优化空间。现在登录login函数就成了名副其实的慢接口需要进行接口优化。 2.2.采用多线程优化 通过分析发现绑定优惠券bindCoupon函数可以异步执行。首先想到的是采用多线程解决该问题代码如下 // 创建新用户函数 private UserVO createNewUser(String phoneNumber) {// 创建新用户UserDO user new UserDO();...userDAO.insert(user);// 绑定优惠券executorService.execute(()-couponService.bindCoupon(user.getId(), CouponType.NEW_USER));// 返回新用户return transUser(user); } 现在在新线程中执行绑定优惠券bindCoupon函数使用户登录login函数性能得到很大的提升。但是如果在新线程执行绑定优惠券函数过程中系统发生重启或崩溃导致线程执行失败用户将永远获取不到新用户优惠券。除非提供用户手动领取优惠券页面否则就需要程序员后台手工绑定优惠券。所以用采用多线程优化慢接口并不是一个完善的解决方案。 2.3.采用消息队列优化 如果要保证绑定优惠券函数执行失败后能够重启执行可以采用数据库表、Redis队列、消息队列的等多种解决方案。由于篇幅优先这里只介绍采用MetaQ消息队列解决方案并省略了MetaQ相关配置仅给出了核心代码。 消息生产者代码 // 创建新用户函数 private UserVO createNewUser(String phoneNumber) {// 创建新用户UserDO user new UserDO();...userDAO.insert(user);// 发送优惠券消息Long userId user.getId();CouponMessageDataVO data new CouponMessageDataVO();data.setUserId(userId);data.setCouponType(CouponType.NEW_USER);Message message new Message(TOPIC, TAG, userId, JSON.toJSONBytes(data));SendResult result metaqTemplate.sendMessage(message);if (!Objects.equals(result, SendStatus.SEND_OK)) {log.error(发送用户({})绑定优惠券消息失败:{}, userId, JSON.toJSONString(result));}// 返回新用户return transUser(user); } 注意可能出现发生消息不成功但是这种概率相对较低。 消息消费者代码 // 优惠券服务类 Slf4j Service public class CouponService extends DefaultMessageListenerString {// 消息处理函数OverrideTransactional(rollbackFor Exception.class)public void onReceiveMessages(MetaqMessageString message) {// 获取消息体String body message.getBody();if (StringUtils.isBlank(body)) {log.warn(获取消息({})体为空, message.getId());return;}// 解析消息数据CouponMessageDataVO data JSON.parseObject(body, CouponMessageDataVO.class);if (Objects.isNull(data)) {log.warn(解析消息({})体为空, message.getId());return;}// 绑定优惠券bindCoupon(data.getUserId(), data.getCouponType());} } 解决方案优点 采集MetaQ消息队列优化慢接口解决方案的优点 如果系统发生重启或崩溃导致消息处理函数执行失败不会确认消息已消费由于MetaQ支持多服务订阅同一队列该消息可以转到别的服务进行消费亦或等到本服务恢复正常后再进行消费。消费者可多服务、多线程进行消费消息即便消息处理时间较长也不容易引起消息积压即便引起消息积压也可以通过扩充服务实例的方式解决。如果需要重新消费该消息只需要在MetaQ管理平台上点击消息验证即可。 3.流程定义不合理 3.1.原有的采购流程 这是一个简易的采购流程由库管系统发起采购采购员开始采购采购员完成采购同时回流采集订单到库管系统。 其中完成采购动作的核心代码如下 /** 完成采购动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void finishPurchase(PurchaseOrder order) {// 完成相关处理......// 回流采购单(调用HTTP接口)backflowPurchaseOrder(order);// 设置完成状态purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.FINISHED.getValue()); } 由于函数backflowPurchaseOrder回流采购单调用了HTTP接口可能引起以下问题 该函数可能耗费时间较长导致完成采购接口成为慢接口该函数可能失败抛出异常导致客户调用完成采购接口失败。 3.2.优化的采购流程 通过需求分析把采购员完成采购并回流采集订单动作拆分为采购员完成采购和回流采集订单两个独立的动作把采购完成拆分为采购完成和回流完成两个独立的状态更方便采购流程的管理和实现。 拆分采购流程的动作和状态后核心代码如下 /** 完成采购动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void finishPurchase(PurchaseOrder order) {// 完成相关处理......// 设置完成状态purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.FINISHED.getValue()); }/** 执行回流动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void executeBackflow(PurchaseOrder order) {// 回流采购单(调用HTTP接口)backflowPurchaseOrder(order);// 设置回流状态purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.BACKFLOWED.getValue()); } 其中函数executeBackflow执行回流由定时作业触发执行。如果回流采购单失败采购单状态并不会修改为已回流等下次定时作业执行时将会继续执行回流动作直到回流采购单成功为止。 3.3.有限状态机介绍 3.3.1.概念 有限状态机Finite-state machineFSM又称有限状态自动机简称状态机是表示有限个状态以及在这些状态之间的转移和动作等行为的一个数学模型。 3.3.2.要素 状态机可归纳为4个要素现态、条件、动作、次态。 现态指当前流程所处的状态包括起始、中间、终结状态。 条件也可称为事件当一个条件被满足时将会触发一个动作并执行一次状态的迁移。 动作当条件满足后要执行的动作。动作执行完毕后可以迁移到新的状态也可以仍旧保持原状态。 次态当条件满足后要迁往的状态。“次态”是相对于“现态”而言的“次态”一旦被激活就转变成新的“现态”了。 3.3.3.状态 状态表示流程中的持久状态流程图上的每一个圈代表一个状态。 初始状态 流程开始时的某一状态 中间状态 流程中间过程的某一状态 终结状态 流程完成时的某一状态。 使用建议 状态必须是一个持久状态而不能是一个临时状态终结状态不能是中间状态不能继续进行流程流转状态划分合理不要把多个状态强制合并为一个状态状态尽量精简同一状态的不同情况可以用其它字段表示。 3.3.4.动作 动作的三要素角色、现态、次态流程图上的每一条线代表一个动作。 角色 谁发起的这个操作可以是用户、定时任务等 现态 触发动作时当前的状态是执行动作的前提条件 次态 完成动作后达到的状态是执行动作的最终目标。 使用建议 每个动作执行前必须检查当前状态和触发动作状态的一致性状态机的状态更改只能通过动作进行其它操作都是不符合规范的需要添加分布式锁保证动作的原子性添加数据库事务保证数据的一致性类似的动作比如操作用户、请求参数、动作含义等可以合并为一个动作并根据动作执行结果转向不同的状态。 4.系统间交互不科学 4.1.直接通过数据库交互 在一些项目中系统间交互不通过接口调用和消息队列而是通过数据库直接访问。问其原因回答道项目工期太紧张直接访问数据库简单又快捷。 还是以上面的采购流程为例——采购订单由库管系统发起由采购系统负责采购采购完成后通知库管系统库管系统进入入库操作。采购系统采购完成后通知库管系统数据库的代码如下 /** 执行回流动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void executeBackflow(PurchaseOrder order) {// 完成原始采购单rawPurchaseOrderDAO.setStatus(order.getRawId(), RawPurchaseOrderStatus.FINISHED.getValue());// 设置回流状态purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.BACKFLOWED.getValue()); } 其中通过rawPurchaseOrderDAO原始采购单DAO直接访问库管系统的数据库表并设置原始采购单状态为已完成。 一般情况下直接通过数据访问的方式是不会有问题的。但是一旦发生竞态就会导致数据不同步。有人会说可以考虑使用同一分布式锁解决该问题。是的这种解决方案没有问题只是又在系统间共享了分布式锁。 直接通过数据库交互的缺点 直接暴露数据库表容易产生数据安全问题多个系统操作同一数据库表容易造成数据库表数据混乱操作同一个数据库表的代码分布在不同的系统中不便于管理和维护具有数据库表这样的强关联无法实现系统间的隔离和解耦。 4.2.通过Dubbo接口交互 由于采购系统和库管系统都是内部系统可以通过类似Dubbo的RPC接口进行交互。 库管系统代码 /** 采购单服务接口 */ public interface PurchaseOrderService {/** 完成采购单函数 */public void finishPurchaseOrder(Long orderId); } /** 采购单服务实现 */ Service(purchaseOrderService) public class PurchaseOrderServiceImpl implements PurchaseOrderService {/** 完成采购单函数 */OverrideTransactional(rollbackFor Exception.class)public void finishPurchaseOrder(Long orderId) {// 相关处理...// 完成采购单purchaseOrderService.finishPurchaseOrder(order.getRawId());} } 其中库管系统通过Dubbo把PurchaseOrderServiceImpl采购单服务实现以PurchaseOrderService采购单服务接口定义的接口服务暴露给采购系统。这里省略了Dubbo开发服务接口相关配置。 采购系统代码 /** 执行回流动作函数(此处省去获取采购单/验证状态/锁定采购单等逻辑) */ public void executeBackflow(PurchaseOrder order) {// 完成采购单purchaseOrderService.finishPurchaseOrder(order.getRawId());// 设置回流状态purchaseOrderDAO.setStatus(order.getId(), PurchaseOrderStatus.BACKFLOWED.getValue()); } 其中purchaseOrderService采购单服务为库管系统PurchaseOrderService采购单服务在采购系统中的Dubbo服务客户端存根通过该服务调用库管系统的服务接口函数finishPurchaseOrder完成采购单函数。 这样采购系统和库管系统自己的强关联通过Dubbo就简单地实现了系统隔离和解耦。当然除了采用Dubbo接口外还可以采用HTTPS、HSF、WebService等同步接口调用方式也可以采用MetaQ等异步消息通知方式。 4.3.常见系统间交互协议 4.3.1.同步接口调用 同步接口调用是以一种阻塞式的接口调用机制。常见的交互协议有 HTTP/HTTPS接口WebService接口Dubbo/HSF接口CORBA接口。 4.3.2.异步消息通知 异步消息通知是一种通知式的信息交互机制。当系统发生某种事件时会主动通知相应的系统。常见的交互协议有 MetaQ的消息通知CORBA消息通知。 4.4.常见系统间交互方式 4.4.1.请求-应答 适用范围 适合于简单的耗时较短的接口同步调用场景比如Dubbo接口同步调用。 4.4.2.通知-确认 适用范围 适合于简单的异步消息通知场景比如MetaQ消息通知。 4.4.3.请求-应答-查询-返回 适用范围 适合于复杂的耗时较长的接口同步调用场景比如提交作业任务并定期查询任务结果。 4.4.4.请求-应答-回调 适用范围 适合于复杂的耗时较长的接口同步调用和异步回调相结合的场景比如支付宝的订单支付。 4.4.5.请求-应答-通知-确认 适用范围 适合于复杂的耗时较长的接口同步调用和异步消息通知相结合的场景比如提交作业任务并等待完成消息通知。 4.4.6.通知-确认-通知-确认 适用范围 适合于复杂的耗时较长的异步消息通知场景。 5.数据查询不分页 在数据查询时由于未能对未来数据量做出正确的预估很多情况下都没有考虑数据的分页查询。 5.1.普通查询案例 以下是查询过期订单的代码 /** 订单DAO接口 */ public interface OrderDAO {/** 查询过期订单函数 */Select(select * from t_order where status 5 and gmt_create date_sub(current_timestamp, interval 30 day))public ListOrderDO queryTimeout(); }/** 订单服务接口 */ public interface OrderService {/** 查询过期订单函数 */public ListOrderVO queryTimeout(); } 当过期订单数量很少时以上代码不会有任何问题。但是当过期订单数量达到几十万上千万时以上代码就会出现以下问题 数据量太大导致服务端的内存溢出数据量太大导致查询接口超时、返回数据超时等数据量太大导致客户端的内存溢出。 所以在数据查询时特别是不能预估数据量的大小时需要考虑数据的分页查询。 这里主要介绍设置最大数量和采用分页查询两种方式。 5.2.设置最大数量 设置最大数量是一种最简单的分页查询相当于只返回第一页数据。例子代码如下 /** 订单DAO接口 */ public interface OrderDAO {/** 查询过期订单函数 */Select(select * from t_order where status 5 and gmt_create date_sub(current_timestamp, interval 30 day) limit 0, #{maxCount})public ListOrderDO queryTimeout(Param(maxCount) Integer maxCount); }/** 订单服务接口 */ public interface OrderService {/** 查询过期订单函数 */public ListOrderVO queryTimeout(Integer maxCount); } 适用于没有分页需求、但又担心数据过多导致内存溢出、数据量过大的查询。 5.3.采用分页查询 采用分页查询是指定startIndex开始序号和pageSize页面大小进行数据查询或者指定pageIndex分页序号和pageSize页面大小进行数据查询。例子代码如下 /** 订单DAO接口 */ public interface OrderDAO {/** 统计过期订单函数 */Select(select count(*) from t_order where status 5 and gmt_create date_sub(current_timestamp, interval 30 day))public Long countTimeout();/** 查询过期订单函数 */Select(select * from t_order where status 5 and gmt_create date_sub(current_timestamp, interval 30 day) limit #{startIndex}, #{pageSize})public ListOrderDO queryTimeout(Param(startIndex) Long startIndex, Param(pageSize) Integer pageSize); }/** 订单服务接口 */ public interface OrderService {/** 查询过期订单函数 */public PageDataOrderVO queryTimeout(Long startIndex, Integer pageSize); } 适用于真正的分页查询查询参数startIndex开始序号和pageSize页面大小可由调用方指定。 5.3.分页查询隐藏问题 假设我们需要在一个定时作业每5分钟执行一次中针对已经超时的订单status5创建时间超时30天进行超时关闭status10。实现代码如下 /** 订单DAO接口 */ public interface OrderDAO {/** 查询过期订单函数 */Select(select * from t_order where status 5 and gmt_create date_sub(current_timestamp, interval 30 day) limit #{startIndex}, #{pageSize})public ListOrderDO queryTimeout(Param(startIndex) Long startIndex, Param(pageSize) Integer pageSize);/** 设置订单超时关闭 */Update(update t_order set status 10 where id #{orderId} and status 5)public Long setTimeoutClosed(Param(orderId) Long orderId) }/** 关闭过期订单作业类 */ public class CloseTimeoutOrderJob extends Job {/** 分页数量 */private static final int PAGE_COUNT 100;/** 分页大小 */private static final int PAGE_SIZE 1000;/** 作业执行函数 */Overridepublic void execute() {for (int i 0; i PAGE_COUNT; i) {// 查询处理订单ListOrderDO orderList orderDAO.queryTimeout(i * PAGE_COUNT, PAGE_SIZE);for (OrderDO order : orderList) {// 进行超时关闭......orderDAO.setTimeoutClosed(order.getId());}// 检查处理完毕if(orderList.size() PAGE_SIZE) {break;}}} } 粗看这段代码是没有问题的尝试循环100次每次取1000条过期订单进行订单超时关闭操作直到没有订单或达到100次为止。但是如果结合订单状态一起看就会发现从第二次查询开始每次会忽略掉前startIndex开始序号条应该处理的过期订单。这就是分页查询存在的隐藏问题 当满足查询条件的数据在操作中不再满足查询条件时会导致后续分页查询中前startIndex开始序号条满足条件的数据被跳过。 可以采用设置最大数量的方式解决代码如下 /** 订单DAO接口 */ public interface OrderDAO {/** 查询过期订单函数 */Select(select * from t_order where status 5 and gmt_create date_sub(current_timestamp, interval 30 day) limit 0, #{maxCount})public ListOrderDO queryTimeout(Param(maxCount) Integer maxCount);/** 设置订单超时关闭 */Update(update t_order set status 10 where id #{orderId} and status 5)public Long setTimeoutClosed(Param(orderId) Long orderId) }/** 关闭过期订单作业(定时作业) */ public class CloseTimeoutOrderJob extends Job {/** 分页数量 */private static final int PAGE_COUNT 100;/** 分页大小 */private static final int PAGE_SIZE 1000;/** 作业执行函数 */Overridepublic void execute() {for (int i 0; i PAGE_COUNT; i) {// 查询处理订单ListOrderDO orderList orderDAO.queryTimeout(PAGE_SIZE);for (OrderDO order : orderList) {// 进行超时关闭......orderDAO.setTimeoutClosed(order.getId());}// 检查处理完毕if(orderList.size() PAGE_SIZE) {break;}}} } 后记 本文是《那些年我们见过的Java服务端“乱象”》的姐妹篇前文主要介绍的是Java服务端规范上的问题而本文主要介绍的是Java服务端方案上的问题。 谨以此文献给当年E代驾下的KK拼车团队怀念曾经一起奋斗过的兄弟们怀念那段为代驾司机深夜返程保驾护航的岁月。深感遗憾的是KK拼车刚刚崭露头角还没来得及好好发展就被公司断臂裁撤了。值得欣慰的是KK拼车自在人心据说现在已经成为了一个民间组织。 原文链接 本文为云栖社区原创内容未经允许不得转载。
http://www.zqtcl.cn/news/711726/

相关文章:

  • 电子商务网站建设百度文库工业设计公司招聘
  • 网站seo测评餐厅设计公司餐厅设计
  • 深圳网站seo推广wordpress swf 上传
  • 织梦做双语网站怎么做制作网站的教程
  • 公司网站开发的国内外研究现状个人网页设计大全
  • 做一个网站人员网站建设及推广优化
  • 胶州市城乡建设局网站能进封禁网站的浏览器
  • 网站做几级等保荣耀商城手机官网
  • 营销网站费用渭南网站建设公司
  • wordpress主题集成插件下载网站如何做360优化
  • 有什么在线做文档的网站网站开发需要用到哪些技术
  • 网站套餐可以分摊吗吗移动登录网页模板免费下载
  • asp网站会员注册不了但是打不开网页
  • wordpress 中文网店杭州排名优化公司
  • wordpress建站安全吗wordpress企业主题教程
  • 网站构建的开发费用信息管理系统网站开发教程
  • 自己做网站怎么维护wordpress素材模板
  • 如何选择一个好的优质网站建设公司wordpress 主题小工具
  • mysql数据库做网站广州网站seo地址
  • 福建省住房和城乡建设厅网站电话网站开发项目步骤
  • 网站注册域名多少钱淘宝网商城
  • 做架构图的网站网站和网店的区别
  • 做红包网站简单个人网站设计
  • 新手学做网站pdf手wordpress修改搜索框
  • 做湲兔费网站视颍如何通过查询网站注册时间
  • 重庆cms建站模板南通网站建设推广优化
  • 合肥网站建设的公司新闻类网站如何做量化统计
  • 好用的在线地图网站十六局集团门户网
  • 网站开发数据库连接失败广州网站建站平台
  • 鄂尔多斯北京网站建设加盟网站建设的内容