Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

In those years, we saw the Java server "problems"

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)06/01 Report--

Mr. Wang Yangming, a famous master of the study of mind in the Ming Dynasty, has a saying in the Biography: Tao is not refined and rough, but what people see is fine and rough. Such as this room, when people first came in, they only saw a large scale like this. For a long time, the pillar wall and so on, one by one can see clearly. No matter how long it takes, if there are some words on the column, you can see it in detail. But it's just a room. Yes, there is no difference in the theory of knowledge, it's just that people have different degrees of understanding. The author has been working in a start-up company for several years and has come into contact with a variety of Java server architectures. If I see more, I will know better, and I will be able to distinguish the pros and cons of various solutions. Here, the author summarizes the Java server problems of some start-ups, and attempts to give some immature solutions. 1. The system is not distributed with the development of the Internet, the computer system has long transitioned from single-machine independent work to multi-machine cooperative work. Computers exist in the form of clusters, and large and complex application services are built according to the distributed theory, which have long been deeply rooted in the hearts of the people and widely used. However, there are still many startups whose software systems remain in the "stand-alone version". 1.1. In the case of order preempting in a stand-alone system, take the order preemptive function with high concurrency as an example: / / preemptive order function public synchronized void grabOrder (Long orderId, Long userId) {/ / get order information OrderDO order = orderDAO.get (orderId); if (Objects.isNull (order)) {throw new BizRuntimeException ("order (% s) does not exist", orderId)) } / / check the order status if (! Objects.equals (order.getStatus, OrderStatus.WAITING_TO_GRAB.getValue () {throw new BizRuntimeException (String.format ("order (% s) has been robbed", orderId));} / set the order to be robbed orderDAO.setGrabed (orderId, userId);} the above code, there is no problem running on a server. When entering the function grabOrder (preemptive order), use the synchronized keyword to lock the entire function, either the order is not preempted before entering the function, so the order is successfully grabbed, or the order has been preempted before entering the function, which leads to the failure of the preemptive order. There will never be a situation in which the order is not preempted before entering the function and then it is preempted after entering the function. However, if the above code runs on two servers at the same time, because the synchronized keyword of Java only works in one virtual machine, it will result in two people being able to grab an order at the same time, subject to the last data written to the database. Therefore, most stand-alone systems cannot run as distributed systems. 1.2. Distributed system preemptive order cases add distributed locks for code optimization: / / preemptive order function public void grabOrder (Long orderId, Long userId) {Long lockId = orderDistributedLock.lock (orderId); try {grabOrderWithoutLock (orderId, userId);} finally {orderDistributedLock.unlock (orderId, lockId) }} / / preemptive order function private void grabOrderWithoutLock (Long orderId, Long userId) {/ / get order information OrderDO order = orderDAO.get (orderId); if (Objects.isNull (order)) {throw new BizRuntimeException ("order (% s) does not exist", orderId)) } / / check the order status if (! Objects.equals (order.getStatus, OrderStatus.WAITING_TO_GRAB.getValue () {throw new BizRuntimeException (String.format ("order (% s) has been robbed", orderId);} / / set the order to be robbed orderDAO.setGrabed (orderId, userId) } the optimized code uses the distributed lock orderDistributedLock (order distributed lock) to lock and release the lock before and after calling the function grabOrderWithoutLock (preemptive order without lock), which is basically the same as the locking effect of the stand-alone synchronized keyword. 1.3. Advantages and disadvantages of distributed system distributed system (Distributed System) is a software system that supports distributed processing and is a system that executes tasks on a multiprocessor architecture interconnected by communication networks, including distributed operating system, distributed programming language and its compiler system, distributed file system, distributed database system and so on. The advantages of distributed system: reliability, high fault tolerance: the collapse of one server will not affect other servers, other servers can still provide services. Scalability: if the service capacity of the system is insufficient, you can scale more servers horizontally. Flexibility: systems can be easily installed, implemented, expanded, and upgraded. High performance: it has the computing power of multiple servers and is faster than a single server. High performance-to-price ratio: the distributed system has low requirements for server hardware, so we can choose cheap servers to build distributed clusters to get a better performance-to-price ratio. The disadvantage of distributed system: it is difficult to troubleshoot: because the system is distributed on multiple servers, it is difficult to troubleshoot and diagnose problems. Less software support: less software support for distributed system solutions. High construction cost: multiple servers are needed to build a distributed system. Many friends have asked me: "looking for outsourcing to do mobile applications, what do you need to pay attention to?" First, determine whether a distributed system is needed. How much is the software budget? How many users are expected? How many visitors are expected? Is it just a pre-business trial version? Can a single server solve the problem? Do you accept short-term downtime? If a comprehensive consideration, the stand-alone system can be solved, then do not use a distributed system. Because there is a great difference between stand-alone system and distributed system, the corresponding software development cost is also very different. Second, determine whether it is a real distributed system. The biggest feature of the distributed system is that when the service capacity of the system is insufficient, it can increase the service capacity by increasing the server by the way of horizontal expansion. However, the stand-alone system does not support horizontal expansion, forced expansion will cause a series of data problems. Due to the great difference in R & D cost between stand-alone system and distributed system, most outsourcing teams in the market use stand-alone system instead of distributed system delivery. So, how do you make sure your system is a truly distributed system? In terms of software, whether the distributed software solution is adopted; in terms of hardware, whether the distributed hardware deployment scheme is adopted. 1.4. As a qualified distributed system, distributed software solution needs to adopt the corresponding distributed software solution according to the actual demand. 1.4.1. Distributed lock is an extension of stand-alone lock, which is mainly used to lock physical blocks or logical blocks in distributed systems, so as to ensure the consistency of logic and data between different services. At present, there are three main ways to realize distributed lock: distributed lock based on database, distributed lock based on Redis, and distributed lock based on Zookeeper. 1.4.2. Distributed message middleware is a software infrastructure that supports sending and receiving messages in distributed systems. Common distributed message middleware includes ActiveMQ, RabbitMQ, Kafka, MetaQ and so on. MetaQ (full name Metamorphosis) is a high-performance, highly available and extensible distributed message middleware. The idea originated from Kafka of LinkedIn, but it is not a copy of Kafka. MetaQ has the characteristics of sequential write of messages, high throughput and support for local and XA transactions. It is suitable for scenarios such as large throughput, sequential messages, broadcast and log data transmission. 1.4.3. Database fragmentation grouping is aimed at databases with a large amount of data, and generally adopts the strategy of "shard grouping": sharding (slicing): it mainly solves the problem of scalability and belongs to horizontal splitting. With the introduction of slicing, the concepts of data routing and partition keys are introduced. Among them, the sub-table solves the problem of excessive amount of data, and the sub-database solves the problem of database performance bottleneck. Grouping (group): mainly solves the usability problem, implements it through master-slave replication, and provides read-write separation strategy to improve database performance. 1.4.4. Distributed Computing distributed Computing (Distributed computing) is a kind of science that divides the engineering data that requires a large number of calculations into small pieces, which are calculated by multiple computers separately, and uniformly merges the results after uploading the operation results. When the current high-performance servers deal with massive data, their computing power, memory capacity and other indicators are far from meeting the requirements. In the era of big data, engineers used cheap servers to form distributed service clusters to complete the processing of massive data in the way of cluster cooperation, so as to solve the bottleneck of computing and storage of a single server. Hadoop, Storm and Spark are commonly used distributed computing middleware, Hadoop is the middleware for batch processing of non-real-time data, and Storm and Spark are middleware for streaming real-time data. In addition, there are more distributed software solutions, which will not be introduced here. 1.5. After introducing the distributed software solution of the server side, we have to introduce the distributed hardware deployment scheme of the server side. Here, only the common interface server, MySQL database and Redis cache on the server side are drawn, while other cloud storage services, message queuing services and log system services are ignored. 1.5.1. General stand-alone deployment solution

Architecture description: only 1 interface server, 1 MySQL database, 1 optional Redis cache, may all be deployed on the same server. Scope of application: suitable for demonstration environment, test environment and small business applications that are not afraid of downtime and whose daily PV is less than 50, 000. 1.5.2. Small and medium-sized distributed hardware deployment scheme

Architecture description: a load-balanced interface server cluster is formed through SLB/Nginx. MySQL database and Redis cache are deployed in an one-master-one-slave (or multi-slave) deployment mode. Scope of application: suitable for small and medium-sized commercial applications with daily PV less than 5 million. 1.5.3. Large-scale distributed hardware deployment

Architecture description: a load-balanced interface server cluster is formed through SLB/Nginx, and a MySQL database cluster and Redis cache cluster are formed by using shard grouping strategy. Scope of application: suitable for large-scale commercial applications with daily PV of more than 5 million. two。 The main purpose of incorrect multithreading is to "maximize the use of CPU resources", which can turn a serial process into a parallel process, thus improving the execution efficiency of the program. 2.1. A slow interface case assumes that when a user logs in, if he is a new user, he or she needs to create user information and issue coupons for new users. The example code is as follows: / / login function (schematic) public UserVO login (String phoneNumber, String verifyCode) {/ / check the verification code if (! checkVerifyCode (phoneNumber, verifyCode)) {throw new ExampleException ("CAPTCHA error");} / / check the existence of UserDO user = userDAO.getByPhoneNumber (phoneNumber); if (Objects.nonNull (user)) {return transUser (user) } / / create new user return createNewUser (user);} / create new user function private UserVO createNewUser (String phoneNumber) {/ / create new user UserDO user = new UserDO ();. UserDAO.insert (user); / / bind coupons couponService.bindCoupon (user.getId (), CouponType.NEW_USER); / / return new user return transUser (user);} where bind coupons (bindCoupon) bind new user coupons to the user, and then send a push notification to the user. If the number of coupons increases, the function will become slower and slower, the execution time will even exceed 1 second, and there is no room for optimization. Now, the login function is a veritable slow interface that requires interface optimization. 2.2. Through the analysis of multithreading optimization, it is found that the bound coupon (bindCoupon) function can be executed asynchronously. The first thought is to use multithreading to solve the problem. The code is as follows: / / create a new user function private UserVO createNewUser (String phoneNumber) {/ / create a new user UserDO user = new UserDO ();. UserDAO.insert (user); / bind coupon executorService.execute (()-> couponService.bindCoupon (user.getId (), CouponType.NEW_USER)); / / return new user return transUser (user);} now, execute the bind coupon (bindCoupon) function in the new thread, which greatly improves the performance of the user login (login) function. However, if the system restarts or crashes during the execution of the bound coupon function by the new thread, which causes the thread to fail, the user will never get the new user coupon. Unless the user is provided with a manual coupon page, the programmer needs to bind the coupon manually in the background. Therefore, using multithreading to optimize slow interface is not a perfect solution. 2.3. Message queue optimization if you want to ensure that the binding coupon function can restart execution after failure, you can use database tables, Redis queues, message queues and other solutions. Because of the space priority, only the MetaQ message queuing solution is introduced here, and the related configuration of MetaQ is omitted and only the core code is given. Message producer code: / / create a new user function private UserVO createNewUser (String phoneNumber) {/ / create a new user UserDO user = new UserDO ();. UserDAO.insert (user); / / send coupon message 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 ("failed to send user ({}) bind coupon message: {}", userId, JSON.toJSONString (result));} / / return new user return transUser (user);} Note: the message may not be successful, but the probability is relatively low. Message consumer code: / / coupon service class @ Slf4j@Servicepublic class CouponService extends DefaultMessageListener {/ / message handling function @ Override @ Transactional (rollbackFor = Exception.class) public void onReceiveMessages (MetaqMessage message) {/ / get message body String body = message.getBody () If (StringUtils.isBlank (body)) {log.warn ("get message ({}) body is empty", message.getId ()); return;} / / parse message data CouponMessageDataVO data = JSON.parseObject (body, CouponMessageDataVO.class) If (Objects.isNull (data)) {log.warn ("parse message ({}) body is empty", message.getId ()); return;} / / bind coupon bindCoupon (data.getUserId (), data.getCouponType ()) }} solution advantages: collect the advantages of MetaQ message queuing optimization slow interface solution: if the system restarts or crashes, resulting in the failure of the message handling function, the message will not be confirmed to have been consumed Since MetaQ supports multiple service subscriptions to the same queue, the message can be transferred to another service for consumption, or wait until the service returns to normal. Consumers can consume messages with multi-service and multi-thread, even if the message processing time is long, it is not easy to cause message backlog; even if it causes message backlog, it can also be solved by expanding service instances. If you need to re-consume the message, just click message Authentication on the MetaQ management platform. 3. The definition of process is unreasonable 3.1. The original procurement process is a simple procurement process, which is initiated by the library management system, the purchaser starts the procurement, the purchaser completes the procurement, and returns the order collection to the warehouse management system.

Among them, the core code to complete the purchase action is as follows: / * complete the purchase action function (here omit the logic of obtaining the purchase order / verification status / locking the purchase order) * / public void finishPurchase (PurchaseOrder order) {/ / complete the relevant processing. / / return purchase order (call HTTP API) backflowPurchaseOrder (order); / / set completion status purchaseOrderDAO.setStatus (order.getId (), PurchaseOrderStatus.FINISHED.getValue ());} because the function backflowPurchaseOrder (return purchase order) calls HTTP interface, it may cause the following problems: this function may take a long time, causing the completion of the purchase interface to become a slow interface This function may fail to throw an exception, causing the customer to call the purchase interface to fail. 3.2. Through demand analysis, the optimized purchasing process divides the action of "purchasers complete procurement and return to collect orders" into two independent actions: "purchasers complete procurement" and "return to collect orders". The "purchase completion" is divided into two independent states: "purchase completion" and "return completion", which is more convenient for the management and implementation of the procurement process.

After splitting the action and status of the purchase process, the core code is as follows: / * complete the purchase action function (here omit the logic of obtaining purchase order / verification status / locking purchase order) * / public void finishPurchase (PurchaseOrder order) {/ / complete the relevant processing. / / set completion status purchaseOrderDAO.setStatus (order.getId (), PurchaseOrderStatus.FINISHED.getValue ());} / * * execute reflux action function (here omitting the logic of obtaining purchase order / verification status / locking purchase order) * / public void executeBackflow (PurchaseOrder order) {/ / reflow purchase order (call HTTP API) backflowPurchaseOrder (order) / / set the reflow status purchaseOrderDAO.setStatus (order.getId (), PurchaseOrderStatus.BACKFLOWED.getValue ());} where the function executeBackflow (execution reflux) is triggered by a scheduled job. If the return purchase order fails, the purchase order status will not be changed to "reflowed"; when the next scheduled operation is executed, the reflow action will continue until the return purchase order is successful. 3.3. Introduction of finite state machine 3.3.1. Conceptual finite state machine (Finite-state machine,FSM), also known as finite state automaton, referred to as state machine, is a mathematical model that represents the behavior of finite states, transitions and actions between them. 3.3.2. The element state machine can be summarized into four elements: present state, condition, action and secondary state.

Current state: refers to the state of the current process, including the start, middle, and end states. Condition: also known as an event; when a condition is met, an action is triggered and a state transition is performed. Action: the action to be performed when the condition is met. After the execution of the action, you can move to the new state, or you can still maintain the original state. Secondary state: the state to move to when the conditions are met. "secondary state" is relative to the "present state". Once the "secondary state" is activated, it will be transformed into a new "present state". 3.3.3. The state state represents the persistent state in the process, and each circle on the flowchart represents a state. Initial state: a state at the beginning of the process; intermediate state: a state in the middle of the process; termination state: a state at the completion of the process. Suggestions: the state must be a persistent state, not a temporary state; the final state cannot be an intermediate state, and the process flow cannot continue; the state is divided reasonably, and multiple states should not be forcibly merged into one state; the state is as concise as possible, and different situations of the same state can be expressed by other fields. 3.3.4. There are three elements of action: role, present state and secondary state, and each line on the flow chart represents an action. Role: who initiated this operation, can be the user, timing task, etc.; present state: the current state when triggering the action is the prerequisite for executing the action; secondary state: the state reached after the completion of the action is the ultimate goal of the execution of the action. Suggestions: before each action is executed, the consistency of the current state and the triggered action state must be checked; the state change of the state machine can only be carried out through the action, and other operations are not in accordance with the specification; it is necessary to add distributed locks to ensure the atomicity of actions and database transactions to ensure the consistency of data. Similar actions (such as operating users, request parameters, action meaning, etc.) can be merged into one action and transferred to different states according to the execution result of the action. 4. The interaction between systems is not scientific 4.1. Direct interaction through the database in some projects, the interaction between systems is not through interface calls and message queues, but directly accessed through the database. Asked the reason, replied: "the project schedule is too tight, direct access to the database, simple and fast." Or take the above procurement process as an example-the purchase order is initiated by the library management system, and the procurement system is responsible for the procurement. After the purchase is completed, the library management system is notified, and the library management system enters the storage operation. After the purchase of the purchasing system is completed, the code to notify the database of the library management system is as follows: / * * execute the reflux action function (here omit the logic of obtaining the purchase order / verification status / locking the purchase order) * / public void executeBackflow (PurchaseOrder order) {/ / complete the original purchase order rawPurchaseOrderDAO.setStatus (order.getRawId (), RawPurchaseOrderStatus.FINISHED.getValue ()) / / set the reflow status purchaseOrderDAO.setStatus (order.getId (), PurchaseOrderStatus.BACKFLOWED.getValue ()); where, directly access the database table of the library management system through rawPurchaseOrderDAO (original purchase order DAO), and set the original purchase order status to completed. In general, there is no problem with direct data access. However, once the race occurs, it will lead to data out of sync. Some people will say that you can consider using the same distributed lock to solve this problem. Yes, there is no problem with this solution, but distributed locks are shared between systems again. The disadvantages of direct interaction through the database: direct exposure of database tables, easy to produce data security problems; multiple systems operating the same database table, easy to cause database table data confusion; code operating the same database table, distributed in different systems, it is not easy to manage and maintain; with strong correlation such as database tables, it is impossible to realize isolation and decoupling between systems. 4.2. Through the Dubbo interface, because the procurement system and the library management system are internal systems, we can interact through the RPC interface similar to Dubbo. Library Management system Code: / * * purchase order Service Interface * / public interface PurchaseOrderService {/ * complete purchase order function * / public void finishPurchaseOrder (Long orderId) } / * * purchase order Service implementation * / @ Service ("purchaseOrderService") public class PurchaseOrderServiceImpl implements PurchaseOrderService {/ * complete purchase order function * / @ Override @ Transactional (rollbackFor = Exception.class) public void finishPurchaseOrder (Long orderId) {/ / related processing. / / complete purchase order purchaseOrderService.finishPurchaseOrder (order.getRawId ()) Among them, the library management system exposes PurchaseOrderServiceImpl (purchase order Service implementation) to the procurement system through Dubbo with the interface service defined by PurchaseOrderService (purchase order Service Interface). Here, the configuration related to the Dubbo development service interface is omitted. Procurement system code: / * * execute reflux action function (here omit the logic of obtaining purchase order / verification status / locking purchase order) * / public void executeBackflow (PurchaseOrder order) {/ / complete purchase order purchaseOrderService.finishPurchaseOrder (order.getRawId ()); / / set reflow status purchaseOrderDAO.setStatus (order.getId (), PurchaseOrderStatus.BACKFLOWED.getValue ()) Among them, purchaseOrderService (purchase order Service) is the Dubbo service client stub of PurchaseOrderService (purchase order Service) in the purchasing system, through which the service interface function finishPurchaseOrder of the library management system is called (to complete the purchase order function). In this way, the strong relationship between the procurement system and the library management system can simply achieve system isolation and decoupling through Dubbo. Of course, in addition to using the Dubbo interface, we can also use synchronous interface calls such as HTTPS, HSF, WebService, and asynchronous message notification methods such as MetaQ. 4.3. Common inter-system interaction protocol 4.3.1. Synchronous interface call synchronous interface call is a blocking interface invocation mechanism. Common interaction protocols are: HTTP/HTTPS interface; WebService interface; Dubbo/HSF interface; CORBA interface. 4.3.2. Asynchronous message notification is a notification-based information interaction mechanism. When an event occurs in the system, it will actively notify the corresponding system. Common interaction protocols are: MetaQ message notification; CORBA message notification. 4.4. The common interaction mode between systems is 4.4.1. Request-reply

Scope of application: it is suitable for simple and time-consuming scenarios where APIs are called synchronously, such as Dubbo API synchronous calls. 4.4.2. Notification-confirmation

Scope of application: suitable for simple asynchronous message notification scenarios, such as MetaQ message notification. 4.4.3. Request-reply-query-return

Scope of application: it is suitable for complex and time-consuming scenarios where interfaces are called synchronously, such as submitting job tasks and querying task results on a regular basis. 4.4.4. Request-reply-callback

Scope of application: it is suitable for complex and time-consuming scenarios where synchronous calls and asynchronous callbacks are combined, such as Alipay's order payment. 4.4.5. Request-reply-Notification-confirmation

Scope of application: it is suitable for complex scenarios where time-consuming synchronous calls of interfaces are combined with asynchronous message notifications, such as submitting job tasks and waiting for completion message notifications. 4.4.6. Notification-confirmation-notification-confirmation

Scope of application: suitable for complex asynchronous message notification scenarios that take a long time. 5. Data query without paging in data query, paging query is not considered in many cases because it can not make a correct estimate of the amount of data in the future. 5.1. The following is the code for querying expired orders: / * * order DAO API * / public interface OrderDAO {/ * * query expired order function * / @ Select ("select * from t_order where status = 5 and gmt_create < date_sub (current_timestamp, interval 30 day)") public List queryTimeout () } / * * order service API * / public interface OrderService {/ * * query expired order function * / public List queryTimeout ();} when the number of expired orders is very small, the above code will not have any problems. However, when the number of expired orders reaches hundreds of thousands or tens of millions, the above code will have the following problems: too much data, resulting in memory overflow on the server; too much data, resulting in query interface timeout, return data timeout, etc.; the amount of data is too large, resulting in memory overflow on the client side. Therefore, in the data query, especially when the amount of data can not be estimated, it is necessary to consider the paging query of the data. Here, we mainly introduce the two ways of "setting the maximum number" and "using paging query". 5.2. Set maximum number is the simplest paging query, which is equivalent to returning only the first page of data. The example code is as follows: / * * order DAO interface * / public interface OrderDAO {/ * * query expired order function * / @ Select ("select * from t_order where status = 5 and gmt_create < date_sub (current_timestamp, interval 30 day) limit 0, # {maxCount}") public List queryTimeout (@ Param ("maxCount") Integer maxCount) } / * * order service API * / public interface OrderService {/ * * query expired order function * / public List queryTimeout (Integer maxCount);} is suitable for queries that have no paging requirements but worry about memory overflow and large amount of data caused by too much data. 5.3. Using paging query "adopt paging query" is to specify startIndex (starting number) and pageSize (page size) for data query, or specify pageIndex (page number) and pageSize (page size) for data query. The example code is as follows: / * * order DAO interface * / public interface OrderDAO {/ * * Statistics expired order function * / @ Select ("select count (*) from t_order where status = 5 and gmt_create < date_sub (current_timestamp, interval 30 day)") public Long countTimeout () / * * query overdue order function * / @ Select ("select * from t_order where status = 5 and gmt_create < date_sub (current_timestamp, interval 30 day) limit # {startIndex}, # {pageSize}") public List queryTimeout (@ Param ("startIndex") Long startIndex, @ Param ("pageSize") Integer pageSize) } / * * order service interface * / public interface OrderService {/ * * query expired order function * / public PageData queryTimeout (Long startIndex, Integer pageSize);} is suitable for real paging query. The query parameters startIndex (starting sequence number) and pageSize (page size) can be specified by the caller. 5.3. The paging query hidden problem assumes that we need to status=10 an order that has timed out (status=5, creation time is 30 days overdue) in a scheduled job (executed every 5 minutes). The implementation code is as follows: / * order DAO API * / public interface OrderDAO {/ * * query expired order function * / @ Select ("select * from t_order where status = 5 and gmt_create < date_sub (current_timestamp, interval 30 day) limit # {startIndex}, # {pageSize}") public List queryTimeout (@ Param ("startIndex") Long startIndex, @ Param ("pageSize") Integer pageSize) / * * set order timeout to close * / @ Update ("update t_order set status = 10 where id = # {orderId} and status = 5") public Long setTimeoutClosed (@ Param ("orderId") Long orderId)} / * * close expired order job class * / public class CloseTimeoutOrderJob extends Job {/ * * number of pages * / private static final int PAGE_COUNT = 100 / * * Page size * / private static final int PAGE_SIZE = 1000; / * * Job execution function * / @ Override public void execute () {for (int I = 0; I < PAGE_COUNT; itemized +) {/ / query processing order List orderList = orderDAO.queryTimeout (I * PAGE_COUNT, PAGE_SIZE) For (OrderDO order: orderList) {/ / performs timeout shutdown. OrderDAO.setTimeoutClosed (order.getId ());} / / check after processing if (orderList.size () < PAGE_SIZE) {break There is no problem to take a rough look at this code, try to cycle through 1000 overdue orders each time, and close the order timeout until there are no orders or reach 100 times. However, if you look at the order status together, you will find that the overdue orders that should be processed by the previous startIndex (start serial number) are ignored each time from the second query. This is the hidden problem in the paging query: when the data that meets the query condition no longer meets the query condition in the operation, it will cause the data that meets the condition in the previous startIndex (start sequence number) item in the subsequent paging query to be skipped. The code is as follows: / * * order DAO API * / public interface OrderDAO {/ * * query expired order function * / @ Select ("select * from t_order where status = 5 and gmt_create < date_sub (current_timestamp, interval 30 day) limit 0, # {maxCount}") public List queryTimeout (@ Param ("maxCount") Integer maxCount) / * * set order timeout to close * / @ Update ("update t_order set status = 10 where id = # {orderId} and status = 5") public Long setTimeoutClosed (@ Param ("orderId") Long orderId)} / * * close expired order jobs (scheduled jobs) * / public class CloseTimeoutOrderJob extends Job {/ * * number of pages * / private static final int PAGE_COUNT = 100 / * * Page size * / private static final int PAGE_SIZE = 1000; / * * Job execution function * / @ Override public void execute () {for (int I = 0; I < PAGE_COUNT; iTunes +) {/ / query processing order List orderList = orderDAO.queryTimeout (PAGE_SIZE) For (OrderDO order: orderList) {/ / performs timeout shutdown. OrderDAO.setTimeoutClosed (order.getId ());} / / check after processing if (orderList.size () < PAGE_SIZE) {break The postscript of this article is the sister article of "chaos" on the Java server that we have seen in those years. The previous article mainly introduces the problems on the specification of the Java server, while this article mainly introduces the problems on the scheme of the Java server. I would like to use this literature to the "KK ride-sharing" team under "E-generation driving" at that time. I miss the brothers who fought together and the days when they escorted the drivers back home late at night. It is a deep regret that "KK carpooling" has just come to the fore and was cut off by the company before it could be properly developed. It is gratifying to note that "KK car sharing" is free in the hearts of the people and is now said to have become a "civil society". The author of this article: the original link of this article is the original content of Yunqi community, which can not be reproduced without permission.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report