In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Today, I will talk to you about the notification of best efforts in SpringBoot distributed transactions, which may not be well understood by many people. in order to make you understand better, the editor has summarized the following for you. I hope you can get something according to this article.
Environment: springboot.2.4.9 + RabbitMQ3.7.4
What is best effort notification?
This is a top-up case.
Interaction process:
1. The account system calls the recharge system API.
2. The top-up system completes the payment and initiates the top-up result notification to the account system. If the notification fails, the top-up system will repeat the notification according to the policy.
3. The account system receives the notification of the recharge result to modify the recharge status.
4. If the account system does not receive the notification, it will actively call the API of the recharge system to query the recharge result.
Through the example above, we summarize the goal of the best effort notification scheme: the initiator tries his best to notify the recipient of the business processing result through a certain mechanism. The details include:
1. There is a mechanism for repeated notification of messages. Because the recipient may not receive the notification, there should be a mechanism to repeat the notification to the message.
2. Message proofreading mechanism. If the receiver does not notify the receiver with his best efforts, or the receiver consumes the message again after consuming the message, the receiver can take the initiative to query the notifier for message information to meet the demand.
What is the difference between best effort notification and reliable message consistency?
1. The idea of the solution is different and the reliable message is consistent. The initiator needs to ensure that the message is sent and sent to the recipient. The reliability of the message is guaranteed by the initiator. Best effort notification, the initiating notifier tries his best to notify the receiving party of the business processing result, but the message may not be received. In this case, the receiving party needs to actively call the initiating party's interface to query the business processing result. The key to the reliability of the notification lies in the receiving party.
2. The consistency of reliable messages in different business application scenarios focuses on the consistency of transactions in the transaction process and completes the transaction in an asynchronous manner. The best effort notification focuses on the notification transaction after the transaction, that is, the reliable notification of the result of the transaction.
3. The consistency of reliable messages in different directions of technical solution is to solve the consistency of messages from sending to receiving, that is, messages are sent and received. Best effort notification can not guarantee the consistency of messages from sending to receiving, but only provides a reliable mechanism for receiving messages. The reliable mechanism is to do our best to notify the receiver of the message, and when the message cannot be received by the receiver, the receiver will actively query the consumption.
Best effort notification through RabbitMQ
Related articles about RabbitMQ, "reliable sending and receiving of SpringBoot RabbitMQ messages", "RabbitMQ message confirmation Mechanism confirm".
Project structure
Two sub-modules users-mananger (account module) and pay-manager (payment module)
Dependence
Org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-amqp mysql mysql-connector-java runtime submodule pay-manager
Configuration file
Server: port: 8080-- spring: rabbitmq: host: localhost port: 5672 username: guest password: guest virtual-host: / publisherConfirmType: correlated publisherReturns: true listener: simple: concurrency: 5 maxConcurrency: 10 prefetch: 5 acknowledgeMode: MANUAL retry: enabled: true initialInterval: 3000 maxAttempts: 3 defaultRequeueRejected: false
Entity class
Record the recharge amount and account information
@ Entity @ Table (name = "t_pay_info") public class PayInfo implements Serializable {@ Id private Long id; private BigDecimal money; private Long accountId;}
DAO and Service
Public interface PayInfoRepository extends JpaRepository {PayInfo findByOrderId (String orderId);} @ Service public class PayInfoService {@ Resource private PayInfoRepository payInfoRepository; @ Resource private RabbitTemplate rabbitTemplate; / / send a message after the data has been saved (here you can apply confirmation mode or transaction mode) @ Transactional public PayInfo savePayInfo (PayInfo payInfo) {payInfo.setId (System.currentTimeMillis ()); PayInfo result = payInfoRepository.save (payInfo) CorrelationData correlationData = new CorrelationData (UUID.randomUUID (). ToString (). ReplaceAll ("-", ")); try {rabbitTemplate.convertAndSend (" pay-exchange "," pay.# ", new ObjectMapper (). WriteValueAsString (payInfo), correlationData);} catch (AmqpException | JsonProcessingException e) {e.printStackTrace ();} return result } public PayInfo queryByOrderId (String orderId) {return payInfoRepository.findByOrderId (orderId);}}
Send a message after the payment is completed.
Controller interface
@ RestController @ RequestMapping ("/ payInfos") public class PayInfoController {@ Resource private PayInfoService payInfoService; / / payment interface @ PostMapping ("/ pay") public Object pay (@ RequestBody PayInfo payInfo) {payInfoService.savePayInfo (payInfo); return "payment has been submitted, waiting for the result";} @ GetMapping ("/ queryPay") public Object queryPay (String orderId) {return payInfoService.queryByOrderId (orderId);}} Sub-module users-manager
Application configuration
Server: port: 8081-- spring: rabbitmq: host: localhost port: 5672 username: guest password: guest virtual-host: / publisherConfirmType: correlated publisherReturns: true listener: simple: concurrency: 5 maxConcurrency: 10 prefetch: 5 acknowledgeMode: MANUAL retry: enabled: true initialInterval: 3000 maxAttempts: 3 defaultRequeueRejected: false
Entity class
@ Entity @ Table (name = "t_users") public class Users {@ Id private Long id; private String name; private BigDecimal money;}
Account information table
@ Entity @ Table (name = "t_users_log") public class UsersLog {@ Id private Long id; private String orderId; / / 0: paying, 1: paid, 2: cancelled @ Column (columnDefinition = "int default 0") private Integer status = 0; private BigDecimal money; private Date createTime;}
Account recharge record form (deduplicated)
DAO and Service
Public interface UsersRepository extends JpaRepository {} public interface UsersLogRepository extends JpaRepository {UsersLog findByOrderId (String orderId);}
Service class
@ Service public class UsersService {@ Resource private UsersRepository usersRepository; @ Resource private UsersLogRepository usersLogRepository; @ Transactional public boolean updateMoneyAndLogStatus (Long id, String orderId) {UsersLog usersLog = usersLogRepository.findByOrderId (orderId); if (usersLog! = null & & 1 = = usersLog.getStatus ()) {throw new RuntimeException (paid);} Users users = usersRepository.findById (id) .orElse (null) If (users = = null) {throw new RuntimeException ("account does not exist");} users.setMoney (users.getMoney (). Add (usersLog.getMoney ()); usersRepository.save (users); usersLog.setStatus (1); usersLogRepository.save (usersLog); return true;} @ Transactional public boolean saveLog (UsersLog usersLog) {usersLog.setId (System.currentTimeMillis ()); usersLogRepository.save (usersLog); return true;}}
Message monitoring
@ Component public class PayMessageListener {private static final Logger logger = LoggerFactory.getLogger (PayMessageListener.class); @ Resource private UsersService usersService; @ SuppressWarnings ("unchecked") @ RabbitListener (queues = {"pay-queue"}) @ RabbitHandler public void receive (Message message, Channel channel) {long deliveryTag = message.getMessageProperties (). GetDeliveryTag (); byte [] buf = null; try {buf = message.getBody () Logger.info ("received message: {}", new String (buf, "UTF-8")); Map result = new JsonMapper (). ReadValue (buf, Map.class); Long id = ((Integer) result.get ("accountId")) + 0L; String orderId = (String) result.get ("orderId"); usersService.updateMoneyAndLogStatus (id, orderId); channel.basicAck (deliveryTag, true) } catch (Exception e) {logger.error ("message acceptance exception: {}, exception message: {}", e.getMessage (), new String (buf, Charset.forName ("UTF-8")); e.printStackTrace (); try {/ / should put such abnormal messages into the dead letter queue for manual troubleshooting. Channel.basicReject (deliveryTag, false);} catch (IOException E1) {logger.error ("reject message re-entry queue exception: {}", e1.getMessage ()); e1.printStackTrace ();}
Controller interface
@ RestController @ RequestMapping ("/ users") public class UsersController {@ Resource private RestTemplate restTemplate; @ Resource private UsersService usersService; @ PostMapping ("/ pay") public Object pay (Long id, BigDecimal money) throws Exception {HttpHeaders headers = new HttpHeaders (); headers.setContentType (MediaType.APPLICATION_JSON); String orderId = UUID.randomUUID (). ToString (). ReplaceAll ("-", ") Map params = new HashMap (); params.put ("accountId", String.valueOf (id)); params.put ("orderId", orderId); params.put ("money", money.toString ()); UsersLog usersLog = new UsersLog (); usersLog.setCreateTime (new Date ()); usersLog.setOrderId (orderId); usersLog.setMoney (money) UsersLog.setStatus (0); usersService.saveLog (usersLog); HttpEntity requestEntity = new HttpEntity (new ObjectMapper (). WriteValueAsString (params), headers); return restTemplate.postForObject ("http://localhost:8080/payInfos/pay", requestEntity, String.class);}}
That's all the code for the two submodules.
test
Initial data
Account sub-module console
Payment submodule console
Datasheet data
After reading the above, do you have any further understanding of the best effort notification in SpringBoot distributed transactions? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.