Distributed transaction solution based on activemq

1. Distributed transaction scenario

Scene Description: Alipay transfer balance treasure

Distributed transactions must meet the following conditions:

1, remote RPC calls, Alipay and balance treasure interface calls

2, Alipay and balance treasure use different databases.

As shown in the picture:

 

2. Distributed transaction solution

1. Two phase commit based on database XA protocol

Xa protocol is a protocol supported by database. The core of XA protocol is a transaction manager used to manage two distributed databases, as shown in the figure

The transaction manager is responsible for dealing with the Alipay database and the balance treasure database. Once a database connection fails, the operation of another database will not be carried out. A database operation failure will lead to another database rollback. Only the transactions of the two databases will be submitted.

The two-stage and three-stage submission based on XA protocol is a strict security confirmation mechanism, and its security is very high, but the premise to ensure security is to sacrifice performance, which is the CAP theory in the distributed system, and the premise to do any architecture needs to have a choice. Therefore, the concurrency of distributed transactions based on XA protocol is not high, which is not suitable for high concurrency scenarios.

 

2. Solution based on activemq

As shown in the picture:

 

 

1, when Alipay deducts money successfully, inserts the message to the message form.

2. The message table has message_id (flow ID), status (confirm, unconfirm)

3. timer scans unconfirm status record of message table to insert message into activemq

4. When yu'e Bao receives the message consumption message, first query the message table. If there is a record, it will not be processed. If there is no record, it will be added to the database

5, if the balance of treasure database operation successfully insert the message to the balance treasure message table, the table field is consistent with Alipay message.

6, if the 5 operation is successful, callback the Alipay interface to modify the state of the message table and convert the unconfirm state to the confirm state.

 

Problem Description:

1, the purpose of Alipay's message table design

If Alipay inserts messages to activemq and the consumption message of the balance treasure is abnormal, it may be that the consumption message is successful and the transaction operation is abnormal. It may be network uncertainty and so on. If there is an exception and activemq receives the confirmation signal, the message in activemq is deleted and the message is lost. Setting the message table means that there is a message stub, and the message in the message table is still missing in activemq. Solve the problem of active MQ message loss

2. The purpose of message table designed by yu'ebao

When the balance treasure consumption is successful and the database operation is successful, callback the message confirmation interface of Alipay. If the callback interface fails, the Alipay state changes or the unconfirm state will fail. At this time, it will be scanned by timer, and will be inserted into the activemq message, and will be consumed by the balance treasure. However, the message has been successfully consumed only by the failure of the callback. Yes, so you need to have a message table like this. When yu'e Bao consumes, insert the message table first. If message can query records according to message [ID], it means that the message is no longer consumed before. Just need to call back successfully. If the message is not queried, consume the message to continue the database operation. If the database operation is successful, insert the message into the message table. This solves the problem of repeated message consumption, which is also the idempotent operation of the consumer side.

 

The distributed transaction based on message middleware is the most ideal solution for distributed transaction, which takes security and concurrency into account!

Next, post the code:

Alipay Code:

  1. @Controller
  2. @RequestMapping("/order")
  3. public class OrderController {
  4. /**
  5. * @Description TODO
  6. * @param @return parameter
  7. * @return String Return type
  8. * @throws
  9. *
  10. * userID: User ID of transfer
  11. * amount: How much is it?
  12. */
  13. @Autowired
  14. @Qualifier("activemq")
  15. OrderService orderService;
  16. @RequestMapping("/transfer")
  17. public @ResponseBody String transferAmount(String userId,String messageId, int amount) {
  18. try {
  19. orderService.updateAmount(amount,messageId, userId);
  20. }
  21. catch (Exception e) {
  22. e.printStackTrace();
  23. return "===============================transferAmount failed===================";
  24. }
  25. return "===============================transferAmount successfull===================";
  26. }
  27. @RequestMapping("/callback")
  28. public String callback(String param) {
  29. JSONObject parse = JSONObject.parseObject(param);
  30. String respCode = parse.getString("respCode");
  31. if(!"OK".equalsIgnoreCase(respCode)) {
  32. return null;
  33. }
  34. try {
  35. orderService.updateMessage(param);
  36. }catch (Exception e) {
  37. e.printStackTrace();
  38. return "fail";
  39. }
  40. return "ok";
  41. }
  42. }
  1. public interface OrderService {
  2. public void updateAmount(int amount, String userId,String messageId);
  3. public void updateMessage(String param);
  4. }
  1. @Service("activemq")
  2. @Transactional(rollbackFor = Exception.class)
  3. public class OrderServiceActivemqImpl implements OrderService {
  4. Logger logger = LoggerFactory.getLogger(getClass());
  5. @Autowired
  6. JdbcTemplate jdbcTemplate;
  7. @Autowired
  8. JmsTemplate jmsTemplate;
  9. @Override
  10. public void updateAmount(final int amount, final String messageId, final String userId) {
  11. String sql = "update account set amount = amount - ?,update_time=now() where user_id = ?";
  12. int count = jdbcTemplate.update(sql, new Object[]{amount, userId});
  13. if (count == 1) {
  14. //Insert into message log table
  15. sql = "insert into message(user_id,message_id,amount,status) values (?,?,?,?)";
  16. int row = jdbcTemplate.update(sql,new Object[]{userId,messageId,amount,"unconfirm"});
  17. if(row == 1) {
  18. //Insert message into activemq
  19. jmsTemplate.send("zg.jack.queue", new MessageCreator() {
  20. @Override
  21. public Message createMessage(Session session) throws JMSException {
  22. com.zhuguang.jack.bean.Message message = new com.zhuguang.jack.bean.Message();
  23. message.setAmount(Integer.valueOf(amount));
  24. message.setStatus("unconfirm");
  25. message.setUserId(userId);
  26. message.setMessageId(messageId);
  27. return session.createObjectMessage(message);
  28. }
  29. });
  30. }
  31. }
  32. }
  33. @Override
  34. public void updateMessage(String param) {
  35. JSONObject parse = JSONObject.parseObject(param);
  36. String messageId = parse.getString("messageId");
  37. String sql = "update message set status = ? where message_id = ?";
  38. int count = jdbcTemplate.update(sql,new Object[]{"confirm",messageId});
  39. if(count == 1) {
  40. logger.info(messageId + " callback successfull");
  41. }
  42. }
  43. }

activemq.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:amq="http://activemq.apache.org/schema/core"
  5. xmlns:jms="http://www.springframework.org/schema/jms"
  6. xmlns:context="http://www.springframework.org/schema/context"
  7. xmlns:mvc="http://www.springframework.org/schema/mvc"
  8. xsi:schemaLocation="
  9. http://www.springframework.org/schema/beans
  10. http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
  11. http://www.springframework.org/schema/context
  12. http://www.springframework.org/schema/context/spring-context-4.1.xsd
  13. http://www.springframework.org/schema/mvc
  14. http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
  15. http://www.springframework.org/schema/jms
  16. http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
  17. http://activemq.apache.org/schema/core
  18. http://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"
  19. >
  20. <context:component-scan base-package="com.zhuguang.jack" />
  21. <mvc:annotation-driven />
  22. <amq:connectionFactory id="amqConnectionFactory"
  23. brokerURL="tcp://192.168.88.131:61616"
  24. userName="system"
  25. password="manager" />
  26. <!-- To configure JMS Connecting foreman -->
  27. <bean id="connectionFactory"
  28. class="org.springframework.jms.connection.CachingConnectionFactory">
  29. <constructor-arg ref="amqConnectionFactory" />
  30. <property name="sessionCacheSize" value="100" />
  31. </bean>
  32. <!-- Defining message queues( Queue) -->
  33. <bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
  34. <!-- Set the name of the message queue -->
  35. <constructor-arg>
  36. <value>zg.jack.queue</value>
  37. </constructor-arg>
  38. </bean>
  39. <!-- To configure JMS Template ( Queue),Spring Provided JMS Tool class, which sends and receives messages. -->
  40. <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
  41. <property name="connectionFactory" ref="connectionFactory" />
  42. <property name="defaultDestination" ref="demoQueueDestination" />
  43. <property name="receiveTimeout" value="10000" />
  44. <!-- trueyes topic,falseyes queue,The default isfalse,Write out herefalse -->
  45. <property name="pubSubDomain" value="false" />
  46. </bean>
  47. </beans>

spring-dispatcher.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:task="http://www.springframework.org/schema/task"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:tx="http://www.springframework.org/schema/tx"
  7. xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
  8. xsi:schemaLocation="
  9. http://www.springframework.org/schema/util
  10. http://www.springframework.org/schema/util/spring-util-3.2.xsd
  11. http://www.springframework.org/schema/beans
  12. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  13. http://www.springframework.org/schema/context
  14. http://www.springframework.org/schema/context/spring-context-3.2.xsd
  15. http://www.springframework.org/schema/mvc
  16. http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
  17. http://www.springframework.org/schema/task
  18. http://www.springframework.org/schema/task/spring-task-3.0.xsd
  19. http://www.springframework.org/schema/tx
  20. http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  21. http://www.springframework.org/schema/aop
  22. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  23. ">
  24. <!-- Imported under the same folder redis Property profile -->
  25. <!-- Solve springMVC Response data scrambling text/plain Is to return data as is when responding-->
  26. <import resource="../activemq/activemq.xml"/>
  27. <!--<context:property-placeholder ignore-unresolvable="true" location="classpath:config/core/core.properties,classpath:config/redis/redis-config.properties" />-->
  28. <bean id="propertyConfigurerForProject1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  29. <property name="order" value="1" />
  30. <property name="ignoreUnresolvablePlaceholders" value="true" />
  31. <property name="location">
  32. <value>classpath:config/core/core.properties</value>
  33. </property>
  34. </bean>
  35. <mvc:annotation-driven>
  36. <mvc:message-converters register-defaults="true">
  37. <bean class="org.springframework.http.converter.StringHttpMessageConverter">
  38. <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
  39. </bean>
  40. </mvc:message-converters>
  41. </mvc:annotation-driven>
  42. <!-- avoid IE implement AJAX Time,Return JSON Download file appears -->
  43. <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
  44. <property name="supportedMediaTypes">
  45. <list>
  46. <value>text/html;charset=UTF-8</value>
  47. </list>
  48. </property>
  49. </bean>
  50. <!-- open controller Annotation support -->
  51. <!-- Note: if base-package=com.avicit Annotation transaction does not work TODO Read source code -->
  52. <context:component-scan base-package="com.zhuguang">
  53. </context:component-scan>
  54. <mvc:view-controller path="/" view-name="redirect:/index" />
  55. <bean
  56. class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
  57. <bean id="handlerAdapter"
  58. class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  59. </bean>
  60. <bean
  61. class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
  62. <property name="mediaTypes">
  63. <map>
  64. <entry key="json" value="application/json" />
  65. <entry key="xml" value="application/xml" />
  66. <entry key="html" value="text/html" />
  67. </map>
  68. </property>
  69. <property name="viewResolvers">
  70. <list>
  71. <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
  72. <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
  73. <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  74. <property name="prefix" value="/" />
  75. <property name="suffix" value=".jsp" />
  76. </bean>
  77. </list>
  78. </property>
  79. </bean>
  80. <!-- Support to upload files -->
  81. <!-- Controller exception handling -->
  82. <bean id="exceptionResolver"
  83. class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
  84. <property name="exceptionMappings">
  85. <props>
  86. <prop key="java.lang.Exception">
  87. error
  88. </prop>
  89. </props>
  90. </property>
  91. </bean>
  92. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
  93. <property name="driverClass">
  94. <value>${jdbc.driverClassName}</value>
  95. </property>
  96. <property name="jdbcUrl">
  97. <value>${jdbc.url}</value>
  98. </property>
  99. <property name="user">
  100. <value>${jdbc.username}</value>
  101. </property>
  102. <property name="password">
  103. <value>${jdbc.password}</value>
  104. </property>
  105. <property name="minPoolSize" value="10" />
  106. <property name="maxPoolSize" value="100" />
  107. <property name="maxIdleTime" value="1800" />
  108. <property name="acquireIncrement" value="3" />
  109. <property name="maxStatements" value="1000" />
  110. <property name="initialPoolSize" value="10" />
  111. <property name="idleConnectionTestPeriod" value="60" />
  112. <property name="acquireRetryAttempts" value="30" />
  113. <property name="breakAfterAcquireFailure" value="false" />
  114. <property name="testConnectionOnCheckout" value="false" />
  115. <property name="acquireRetryDelay">
  116. <value>100</value>
  117. </property>
  118. </bean>
  119. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  120. <property name="dataSource" ref="dataSource"></property>
  121. </bean>
  122. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  123. <property name="dataSource" ref="dataSource"/>
  124. </bean>
  125. <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
  126. <aop:aspectj-autoproxy expose-proxy="true"/>
  127. </beans>

logback.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--
  3. scan: When this property is set totrueIf the configuration file changes, it will be reloaded. The default value istrue.
  4. scanPeriod: Set whether the monitoring profile has a modified time interval. If no time unit is given, the default unit is ms when scan bytrueThis property takes effect. The default time interval is1Minute.
  5. debug: When this property is set totrueWill be printed out logback Internal log information, real-time viewing logback Operation status. The default value isfalse.
  6. -->
  7. <configuration scan="false" scanPeriod="60 seconds" debug="false">
  8. <!-- Define log root -->
  9. <!-- <property name="LOG_HOME" value="/app/log" /> -->
  10. <!-- Define log file name -->
  11. <property name="appName" value="netty"></property>
  12. <!-- ch.qos.logback.core.ConsoleAppender Represents console output -->
  13. <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
  14. <Encoding>UTF-8</Encoding>
  15. <!--
  16. Log output format:%d Represents date time,%thread Represents the thread name,%-5level: Level left5Character width
  17. %logger{50} Express logger Name is the longest.50Characters, otherwise separated by periods. %msg: Log messages,%n Newline character
  18. -->
  19. <encoder>
  20. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  21. </encoder>
  22. </appender>
  23. <!-- Scroll to record the file, first record the log to the specified file, and when a certain condition is met, record the log to other files -->
  24. <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
  25. <Encoding>UTF-8</Encoding>
  26. <!-- Specify the name of the log file -->
  27. <file>${appName}.log</file>
  28. <!--
  29. When scrolling occurs, decide RollingFileAppender , involving file movement and renaming
  30. TimeBasedRollingPolicy: The most commonly used rolling strategy, which makes rolling strategy according to time, is responsible for rolling as well as starting rolling.
  31. -->
  32. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  33. <!--
  34. Storage location and file name of files generated during scrolling %d{yyyy-MM-dd}: Scroll logs by day
  35. %i: When the file size exceeds maxFileSize In accordance with i Scrolling files
  36. -->
  37. <fileNamePattern>${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
  38. <!--
  39. Optional node, which controls the maximum number of archive files to be retained. If the number exceeds, the old files will be deleted. Suppose you set scrolling every day,
  40. And maxHistory yes365,Save only recent365Days of files, delete previous old files. Note that deleting old files is,
  41. Directories created for archiving are also deleted.
  42. -->
  43. <MaxHistory>365</MaxHistory>
  44. <!--
  45. When the log file exceeds maxFileSize The specified size is based on the above mentioned%i Scroll the log file note the configuration here SizeBasedTriggeringPolicy Scrolling by file size is not possible and must be configured timeBasedFileNamingAndTriggeringPolicy
  46. -->
  47. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  48. <maxFileSize>100MB</maxFileSize>
  49. </timeBasedFileNamingAndTriggeringPolicy>
  50. </rollingPolicy>
  51. <!--
  52. Log output format:%d Represents date time,%thread Represents the thread name,%-5level: Level left5Character width %logger{50} Express logger Name is the longest.50Characters, otherwise separated by periods. %msg: Log messages,%n Newline character
  53. -->
  54. <encoder>
  55. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
  56. </encoder>
  57. </appender>
  58. <!--
  59. logger It is mainly used to store log objects and define log types and levels
  60. name: For matching logger The type prefix, which is the first half of the package
  61. level: The level of logging to log, including TRACE < DEBUG < INFO < WARN < ERROR
  62. additivity: The role lies in children-logger Whether to use rootLogger Configured appender Output,false: Indicates only the current logger Of appender-ref,true: Present logger Of appender-ref and rootLogger Of appender-ref All effective
  63. -->
  64. <!-- <logger name="edu.hyh" level="info" additivity="true">
  65. <appender-ref ref="appLogAppender" />
  66. </logger> -->
  67. <!--
  68. root And logger It is a parent-child relationship. If there is no special definition, it defaults to root,Any class can only be associated with one logger Corresponding,
  69. Or defined logger,Either root,The key to judgment is to find this logger,And then judge this logger Of appender and level.
  70. -->
  71. <root level="debug">
  72. <appender-ref ref="stdout" />
  73. <appender-ref ref="appLogAppender" />
  74. </root>
  75. </configuration>

 

2,Yu'ebao code

  1. package com.zhuguang.jack.controller;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.zhuguang.jack.service.OrderService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.ResponseBody;
  8. @Controller
  9. @RequestMapping("/order")
  10. public class OrderController {
  11. /**
  12. * @Description TODO
  13. * @param @return parameter
  14. * @return String Return type
  15. * @throws
  16. *
  17. * Simulated bank transfer
  18. * userID: User ID of transfer
  19. * amount: How much is it?
  20. */
  21. @Autowired
  22. OrderService orderService;
  23. @RequestMapping("/transfer")
  24. public @ResponseBody String transferAmount(String userId, String amount) {
  25. try {
  26. orderService.updateAmount(Integer.valueOf(amount), userId);
  27. }
  28. catch (Exception e) {
  29. e.printStackTrace();
  30. return "===============================transferAmount failed===================";
  31. }
  32. return "===============================transferAmount successfull===================";
  33. }
  34. }

 Message listener

  1. package com.zhuguang.jack.listener;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.zhuguang.jack.service.OrderService;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.http.client.SimpleClientHttpRequestFactory;
  8. import org.springframework.stereotype.Service;
  9. import org.springframework.transaction.annotation.Transactional;
  10. import org.springframework.web.client.RestTemplate;
  11. import javax.jms.JMSException;
  12. import javax.jms.Message;
  13. import javax.jms.MessageListener;
  14. import javax.jms.ObjectMessage;
  15. @Service("queueMessageListener")
  16. public class QueueMessageListener implements MessageListener {
  17. private Logger logger = LoggerFactory.getLogger(getClass());
  18. @Autowired
  19. OrderService orderService;
  20. @Transactional(rollbackFor = Exception.class)
  21. @Override
  22. public void onMessage(Message message) {
  23. if (message instanceof ObjectMessage) {
  24. ObjectMessage objectMessage = (ObjectMessage) message;
  25. try {
  26. com.zhuguang.jack.bean.Message message1 = (com.zhuguang.jack.bean.Message) objectMessage.getObject();
  27. String userId = message1.getUserId();
  28. int count = orderService.queryMessageCountByUserId(userId);
  29. if (count == 0) {
  30. orderService.updateAmount(message1.getAmount(), message1.getUserId());
  31. orderService.insertMessage(message1.getUserId(), message1.getMessageId(), message1.getAmount(), "ok");
  32. } else {
  33. logger.info("Abnormal transfer");
  34. }
  35. RestTemplate restTemplate = createRestTemplate();
  36. JSONObject jo = new JSONObject();
  37. jo.put("messageId", message1.getMessageId());
  38. jo.put("respCode", "OK");
  39. String url = "http://jack.bank_a.com:8080/alipay/order/callback?param="
  40. + jo.toJSONString();
  41. restTemplate.getForObject(url,null);
  42. } catch (JMSException e) {
  43. e.printStackTrace();
  44. throw new RuntimeException("abnormal");
  45. }
  46. }
  47. }
  48. public RestTemplate createRestTemplate() {
  49. SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
  50. simpleClientHttpRequestFactory.setConnectTimeout(3000);
  51. simpleClientHttpRequestFactory.setReadTimeout(2000);
  52. return new RestTemplate(simpleClientHttpRequestFactory);
  53. }
  54. }
  1. package com.zhuguang.jack.service;
  2. public interface OrderService {
  3. public void updateAmount(int amount, String userId);
  4. public int queryMessageCountByUserId(String userId);
  5. public int insertMessage(String userId,String messageId,int amount,String status);
  6. }
  1. package com.zhuguang.jack.service;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.http.client.SimpleClientHttpRequestFactory;
  6. import org.springframework.jdbc.core.JdbcTemplate;
  7. import org.springframework.stereotype.Service;
  8. import org.springframework.transaction.annotation.Transactional;
  9. import org.springframework.web.client.RestTemplate;
  10. @Service
  11. @Transactional(rollbackFor = Exception.class)
  12. public class OrderServiceImpl implements OrderService {
  13. private Logger logger = LoggerFactory.getLogger(getClass());
  14. @Autowired
  15. JdbcTemplate jdbcTemplate;
  16. /*
  17. * Update the database table and subtract the amount from the account balance
  18. */
  19. @Override
  20. public void updateAmount(int amount, String userId) {
  21. //1. Agricultural Bank of China transfers 3000, that is to say, the Bank of agriculture's jack account will be reduced by 3000
  22. String sql = "update account set amount = amount + ?,update_time=now() where user_id = ?";
  23. int count = jdbcTemplate.update(sql, new Object[] {amount, userId});
  24. if (count != 1) {
  25. throw new RuntimeException("Order creation failed, Agricultural Bank of China transfer failed!");
  26. }
  27. }
  28. public RestTemplate createRestTemplate() {
  29. SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
  30. simpleClientHttpRequestFactory.setConnectTimeout(3000);
  31. simpleClientHttpRequestFactory.setReadTimeout(2000);
  32. return new RestTemplate(simpleClientHttpRequestFactory);
  33. }
  34. @Override
  35. public int queryMessageCountByUserId(String messageId) {
  36. String sql = "select count(*) from message where message_id = ?";
  37. int count = jdbcTemplate.queryForInt(sql, new Object[]{messageId});
  38. return count;
  39. }
  40. @Override
  41. public int insertMessage(String userId, String message_id,int amount, String status) {
  42. String sql = "insert into message(user_id,message_id,amount,status) values(?,?,?)";
  43. int count = jdbcTemplate.update(sql, new Object[]{userId, message_id,amount, status});
  44. if(count == 1) {
  45. logger.info("Ok");
  46. }
  47. return count;
  48. }
  49. }

activemq.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:amq="http://activemq.apache.org/schema/core"
  5. xmlns:jms="http://www.springframework.org/schema/jms"
  6. xmlns:context="http://www.springframework.org/schema/context"
  7. xmlns:mvc="http://www.springframework.org/schema/mvc"
  8. xsi:schemaLocation="
  9. http://www.springframework.org/schema/beans
  10. http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
  11. http://www.springframework.org/schema/context
  12. http://www.springframework.org/schema/context/spring-context-4.1.xsd
  13. http://www.springframework.org/schema/mvc
  14. http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
  15. http://www.springframework.org/schema/jms
  16. http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
  17. http://activemq.apache.org/schema/core
  18. http://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"
  19. >
  20. <context:component-scan base-package="com.zhuguang.jack" />
  21. <mvc:annotation-driven />
  22. <amq:connectionFactory id="amqConnectionFactory"
  23. brokerURL="tcp://192.168.88.131:61616"
  24. userName="system"
  25. password="manager" />
  26. <!-- To configure JMS Connecting foreman -->
  27. <bean id="connectionFactory"
  28. class="org.springframework.jms.connection.CachingConnectionFactory">
  29. <constructor-arg ref="amqConnectionFactory" />
  30. <property name="sessionCacheSize" value="100" />
  31. </bean>
  32. <!-- Defining message queues( Queue) -->
  33. <bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
  34. <!-- Set the name of the message queue -->
  35. <constructor-arg>
  36. <value>zg.jack.queue</value>
  37. </constructor-arg>
  38. </bean>
  39. <!-- Display injection message listening container( Queue),Configure the connection factory to monitor demoQueueDestination,A listener is a listener defined above -->
  40. <bean id="queueListenerContainer"
  41. class="org.springframework.jms.listener.DefaultMessageListenerContainer">
  42. <property name="connectionFactory" ref="connectionFactory" />
  43. <property name="destination" ref="demoQueueDestination" />
  44. <property name="messageListener" ref="queueMessageListener" />
  45. </bean>
  46. <!-- To configure JMS Template ( Queue),Spring Provided JMS Tool class, which sends and receives messages. -->
  47. <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
  48. <property name="connectionFactory" ref="connectionFactory" />
  49. <property name="defaultDestination" ref="demoQueueDestination" />
  50. <property name="receiveTimeout" value="10000" />
  51. <!-- trueyes topic,falseyes queue,The default isfalse,Write out herefalse -->
  52. <property name="pubSubDomain" value="false" />
  53. </bean>
  54. </beans>

OK~~~~~~~~~~~~be accomplished!!! ,  If you are satisfied and interested in technology, please add: 171239762, Pure technology exchange group, if you are the one.

                        <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">Give the thumbs-up</span>
                        <span class="count">6</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">Collection</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>share</a></li>
                        <!--Reward begins-->
                                                <!--End of reward-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">Article report</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/luoyang_java">
                    <img src="https://profile.csdnimg.cn/2/F/E/3_luoyang_java" class="avatar_pic" username="luoyang_java">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/1x/4.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://Blog. CSDN. Net / luoyang_java "data report Click =" {& quot; mod & quot;: & quot; pop_379 & quot;} "target =" _blank "> Huangshan technological ape</a></span>
                                            </div>
                    <div class="text"><span>Published 106 original articles</span> · <span>Praise 34</span> · <span>40000 visitors+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://Im. CSDN. Net / im / main. HTML? Username = Luoyang? Java "target =" [blank "class =" BTN BTN SM BTN red hold BT button personal letter "> private message
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">follow</a>
                                    </div>
                            </div>
                    </div>
    </article>
    
    weixin_32822759
    Published 0 original articles, won 0 praise, visited 5
    Private letter follow

    Keywords: Spring Database SQL xml

    Added by zero-one on Mon, 17 Feb 2020 08:25:17 +0200