å¼è¨
æä»¬ç¥éåä¸ä¸ªè¿ç¨éé¢ä¸ºäºè§£å³èµæºå ±äº«èä¸åºç°é«å¹¶åçé®é¢å¯ä»¥éè¿é«å¹¶åç¼ç¨è§£å³ï¼éè¿ç»åéæ·»å
volatile
å ³é®åå®ç°çº¿ç¨é´åéå¯è§ï¼éè¿
synchronized
å ³é®å修饰代ç åã对象æè æ¹æ³ä»¥åéè¿è°ç¨
java.util.current
å ä¸ç
API
æ¾å¼å°å éåéæ¾éæä½é½å®ç°å¤çº¿ç¨åºæ¯ä¸ç忥å¤çã
使¯å½æå¡å¨é¨ç½²äºå¤å°ä»¥åï¼å¯¹äºæ§å¶ä¸å
JVM
è¿ç¨ä¸çå¤çº¿ç¨é«å¹¶å访é®å°±ä¼å¤±æãæ 论æ¯éè¿ç»åéæ·»å
volatile
å ³é®åï¼è¿æ¯å¨æ§å¶å¹¶å访é®ç代ç åä¸å¯¹ä¸ä¸ªå¯¹è±¡éå
synchronized
å ³é®åï¼æææ¯éè¿è°ç¨
java.util.current
å ä¸ç
API
æ¾å¼å°å éåéæ¾é齿 æ³è§£å³åå¸å¼åºæ¯ä¸ä¸å
JVM
è¿ç¨ä¸çå¤çº¿ç¨å¹¶å访é®åæ¥çé®é¢ãå ¸åçå¦çµååºæ¯ä¸çç§æãä¸ååååºåæä½ï¼è®¢åæå¡ååºåæå¡é½å±äºä¸åçå¾®æå¡ï¼æ¯ä¸ªå¾®æå¡é½ä¼æå¤ä¸ªå®ä¾ã
è¿ä¸ªæ¶åå°±éè¦å¼å ¥åå¸å¼äºå¡éæ¹æ¡æ¥è§£å³é®é¢äºï¼åå¸å¼äºå¡éä¸»è¦æ
redis
ã
zookeeper
å
æ°æ®åºçæ¬é
ï¼ä¹å«ä¹è§éï¼ä¸ç§å¸¸ç¨çå®ç°æ¹å¼ãå ¶ä¸ä»¥
redis
å®ç°åå¸å¼äºå¡éç¨èµ·æ¥æç®å髿ï¼
redis
å®ç°åå¸å¼äºå¡éä¸»è¦æ¯éè¿å®ç
setnx
å½ä»¤ä»¥åæ§è¡
lua
èæ¬å®ç°ååæä½æ¥å®ç°åå¸å¼äºå¡éï¼å¦å¤
redis
客æ·ç«¯ä¹ä»¥åæä¾äº
redission
æ´é«çº§çå®ç°åå¸å¼äºå¡éçç¨æ³ãåªä¸è¿
redission
å®ç°åå¸å¼äºå¡éçåºå±ä¹æ¯åºäºæ§è¡
lua
èæ¬å®ç°çã
ä¸ºäºæ§å¶æç« ç¯å¹ ï¼ä¹ä¸ºäºè®©æ¬ä½å ·æå¼å¾åä½è¯»è ä»ç»ä¸çç干货å å®¹ï¼æ¬æå å®¹åªæ¶åå¨
springboot
å¾®æå¡é¡¹ç®ä¸éè¿
redis
客æ·ç«¯æ§è¡
setnx
å½ä»¤åæ§è¡
lua
èæ¬æ¥å®ç°ãå¦ä¸¤ç§æ¹å¼ç¬è ææ¶é´äºåæ¥å¦å¤éè¿å®æçæ¹å¼æ°æè®²è§£ã
1 Rediså®ç°åå¸å¼äºå¡éçåç
redis
乿以è½å®ç°åå¸å¼äºå¡éæ¯å ä¸ºå®æ¯ä¸ä¸ªå ¨å±æ°æ®åºï¼èä¸å®æ¯ä¸ä¸ªkey-valueå½¢å¼çNO-SQLæ°æ®åºï¼å¯¹äºä¸åjvmè¿ç¨ä¸çå¤çº¿ç¨æ§è¡å䏿®µä»£ç æ¶å¯ä»¥å®ç°å ¨å±å éåéæ¾éæä½ã
setnx
å½ä»¤æ¯å¤æ
redis
ç¼å䏿¯å¦æè¿ä¸ªkey, 没ææsetæåï¼setæå表示æ¿å°äºåå¸å¼éï¼å¯ä»¥è¿è¡åé¢éè¦æ§å¶å¹¶å访é®çé»è¾ã为äºé²æ¢å éçæºå¨å®æºé æçæ»éé®é¢å¯ä»¥éè¿
redis
对ç¼åkey è®¾ç½®è¿ææ¶é´æ¥è§£å³ï¼èæ§è¡
lua
èæ¬æ¯ä¸ä¸ªååæä½ï¼å䏿¶é´åªè½æä¸ä¸ªå®¢æ·ç«¯å¨æ§è¡ï¼è¿å¯¹äºä¿è¯åå¸å¼é«å¹¶ååºæ¯ä¸äºå¡çååæ§åä¸è´æ§æ¯éå¸¸å¿ è¦çãå æ¤éè¿æ§è¡luaèæ¬å®ç°åå¸å¼äºå¡éå°±æä¸ºäºä¸ä¸ªé常好çè§£å³æ¹æ¡ã
2 æå»ºéæRedisçå¾®æå¡é¡¹ç®
Spring Redisè¦æ±Redis 2.6 以ä¸çæ¬ï¼Spring Data éè¿
Jedis
å
Lettuce
两个Java弿ºç±»åºä¸
Redis
éæ, æ 论使ç¨åªç§å®¢æ·ç«¯ï¼ä½ è¦ç¨å°
spring-data-redis
jarå ä¸
org.springframework.data.redis.connection
å ä¸ç两个æ½è±¡æ¥å£
RedisConnection
å
RedisConnectionFactory
ç¨äºè·å¾äº
Redis
交äºçå·¥ä½è¿æ¥ã
Jedis
å
Lettuce
ä¸¤ä¸ªç±»åºæä¾äº
RedisConnectionFactory
æ¥å£çå®ç°ç±»
LettuceConnectionFactory
å
JedisConnectionFactory
ã
spring-boot-starter-data-redis
èµ·æ¥ä¾èµéé¢é»è®¤ä½¿ç¨ç客æ·ç«¯æ¯
Lettuce
客æ·ç«¯ï¼åªæ¯å¾å¤äººä¹ æ¯ä½¿ç¨Jedis客æ·ç«¯æä½
Redis
ï¼ å 为使ç¨
jedis
客æ·ç«¯æä½
redis
å½ä»¤æ´æ¥è¿åçç
redis
å½ä»¤ç¨æ³ã
2.1 redisèªå¨é ç½®ä»ç»
spring-boot
项ç®ä¸çredisèªå¨é 置类ä½äº
org.springframework.boot.autoconfigure.data.redis
å ä¸ç
RedisAutoConfiguration
ç±»ï¼è¿ä¸ªèªå¨é ç½®ç±»çæºç å¦ä¸ï¼
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
å¤å¶
å®ä¼æ ¹æ®
RedisProperties
屿§é 置类ä¸çé 置信æ¯å®ä¾å
redis
è¿æ¥å¯¹è±¡,å¹¶èªå¨å¯¼å ¥
LettuceConnectionConfiguration
å
JedisConnectionConfiguration
两个é 置类ãåæ¶å¨é¡¹ç®ä¸ç¼ºå¤±ä¸¤ä¸ªbeançæ åµæ åµä¸ï¼å
Spring IOC
容å¨ä¸å®ä¾åå¹¶æ³¨å ¥
RedisTemplate
å
StringRedisTemplate
两个beanã
2.1 å¾®æå¡é¡¹ç®éª¨æ¶æå»º
卿çä¸ä¸ç¯æå ³å¾®æå¡å®è·µçæç« è®°ä¸æ¬¡ä½¿ç¨Nacos 2.0.3çæ¬æå»ºå¾®æå¡æ³¨åä¸å¿å客æ·ç«¯ç踩åå¡«å详ç»è¿ç¨é¡¹ç®çåºç¡ä¸æå»ºå¾®æå¡èå项ç®
alibaba-demos
ãå¢å ä¸ä¸ªå模å项ç®ï¼
alibaba-commons
(å ¬å ±æ¨¡å项ç®),
alibaba-service-provider
(å¾®æå¡æä¾è 模å项ç®)ï¼
alibaba-service-consumer
(å¾®æå¡æ¶è´¹è 模å项ç®)ã
alibaba-service-provider
é¡¹ç®æ¨¡æçµååºåæå¡ï¼
alibaba-service-consumer
é¡¹ç®æ¨¡æçµå订åæå¡ï¼ä¸¤ä¸ªå¾®æå¡å坹夿ä¾webæå¡ã
2.2 项ç®mavenä¾èµ
-
项ç®alibaba-demos
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.spring.cloud</groupId>
<artifactId>alibaba-demos</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>alibaba-commons</module>
<module>alibaba-service-provider</module>
<module>alibaba-service-consumer</module>
</modules>
<name>alibaba-demos</name>
<description>spring cloud alibaba demos</description>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.2.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>2.2.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul-discovery</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
<exclusion>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>0.0.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
å¤å¶
-
模å项ç®alibaba-commons
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>alibaba-demos</artifactId>
<groupId>com.spring.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>alibaba-commons</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.5</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
</project>
å¤å¶
-
模å项ç®alibaba-service-provider
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>alibaba-demos</artifactId>
<groupId>com.spring.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>alibaba-service-provider</artifactId>
<dependencies>
<dependency>
<groupId>com.spring.cloud</groupId>
<artifactId>alibaba-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</exclusion>
<exclusion>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</exclusion>
<exclusion>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
</exclusion>
<exclusion>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</exclusion>
<exclusion>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.2.RELEASE</version>
<configuration>
<mainClass></mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
å¤å¶
-
模å项ç®pom.xmlaliba-service-consumer
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.spring.cloud</groupId>
<artifactId>alibaba-consumer</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>alibaba-consumer</name>
<description>Demo project for Spring Boot</description>
<parent>
<artifactId>alibaba-demos</artifactId>
<groupId>com.spring.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-keyvalue</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>com.spring.cloud</groupId>
<artifactId>alibaba-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</exclusion>
<exclusion>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</exclusion>
<exclusion>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</exclusion>
<exclusion>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</exclusion>
<exclusion>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
<exclusion>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.7.RELEASE</version>
<configuration>
<mainClass>com.spring.cloud.alibabaconsumer.AlibabaConsumerApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
å¤å¶
2.3 项ç®é 置类
1
alibaba-service-provider
项ç®
application.properties
server.port=9000
server.servlet.context-path=/services
spring.profiles.active=dev
spring.jackson.time-zone=GMT+8
spring.devtools.add-properties=false
mybatis-plus.mapper-locations=classpath:com/spring/cloud/alibaba/service/provider/mapper/*Mapper.xml
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
å¤å¶
2
alibaba-service-provider
项ç®
application-dev.properties
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=heshengfu2018
logging.level.root.com.apache.ibatis=trace
logging.level.root.java.sql.Connection=debug
logging.level.java.sql.Statement=info
logging.level.java.sql.PreparedStatement=info
å¤å¶
3
alibaba-service-provider
项ç®
bootstrap.properties
ï¼å°åºåæå¡æ³¨åå°æ³¨åä¸å¿
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.namespace=public
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.application.name=stock-service
å¤å¶
4
alibaba-service-consumer
项ç®
application.properties
æä»¶
# åºç¨æå¡ WEB 访é®ç«¯å£
server.port=9002
server.servlet.context-path=/order-service
spring.devtools.add-properties=false
spring.profiles.active=dev
spring.jackson.time-zone=GMT+8
mybatis-plus.mapper-locations=classpath:com/spring/cloud/alibabaconsumer/mapper/*Mapper.xml
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# redisé
ç½®
spring.redis.client-name=redis-client
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=0
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=5000ms
spring.redis.jedis.pool.min-idle=1
spring.redis.jedis.pool.time-between-eviction-runs=30000ms
#å¾®æå¡url
stock.service.query-stock-url=http://stock-service/services/stock/findStockByCode
stock.service.update-count-url=http://stock-service/services/stock/updateStockCountById
å¤å¶
5
alibaba-service-consumer
项ç®
application-dev.properties
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/vueblog2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=vueblog
spring.datasource.password=vueblog2021#
logging.level.root.com.apache.ibatis=trace
logging.level.root.java.sql.Connection=debug
logging.level.java.sql.Statement=info
logging.level.java.sql.PreparedStatement=info
å¤å¶
åºåæå¡ä¸è®¢åæå¡çå ³ç³»åå建订åçæµç¨ï¼ç¬è ç»äºä¸å¹ å¦ä¸æç¤ºçç®åæµç¨å¾

2.4 æ°æ®åºå»ºè¡¨ä¸å建å®ä½ç±»
- æ°å»ºåºåè¡¨å¹¶æ·»å æ°æ®
æå¼
navicat
客æ·ç«¯æ°å»ºè¿æ¥ï¼ä½¿ç¨rootè´¦æ·åç»å½å¯ç è¿æ¥æ¬å°
MySQL
æå¡testæ°æ®åºå卿§å¶å°ä¸æ§è¡ä»¥ä¸
sql
èæ¬
DROP TABLE IF EXISTS `stock_info`;
CREATE TABLE `stock_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主é®',
`good_code` varchar(30) NOT NULL COMMENT 'ååç¼ç ',
`good_name` varchar(100) DEFAULT NULL COMMENT 'åååç§°',
`count` int(11) DEFAULT '0' COMMENT 'ååæ°é',
`created_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´',
`created_by` varchar(30) NOT NULL DEFAULT 'system' COMMENT 'å建人',
`last_updated_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æåæ´æ°æ¶é´',
`last_updated_by` varchar(30) NOT NULL DEFAULT 'system' COMMENT 'æåæ´æ°äºº',
`unit_price` int(11) DEFAULT '0' COMMENT 'åä»·ï¼åä½å',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_good_code` (`good_code`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of stock_info
-- ----------------------------
INSERT INTO `stock_info` VALUES ('1', 'huawei_mate3', 'åä¸ºææºmate3', '1000', '2021-11-08 23:42:02', 'heshengfu', '2021-11-21 21:11:08', 'heshengfu', '200000');
INSERT INTO `stock_info` VALUES ('2', 'huawei_mate5', 'åä¸ºææºmate5', '1000', '2021-11-08 23:42:02', 'heshengfu', '2021-11-21 21:11:08', 'heshengfu', '300000');
INSERT INTO `stock_info` VALUES ('3', 'iphone_plus8', 'è¹æææºplus8', '1000', '2021-11-08 23:42:02', 'heshengfu', '2021-11-21 21:11:08', 'heshengfu', '500000');
INSERT INTO `stock_info` VALUES ('4', 'iphone_11', 'è¹æææº11', '860', '2021-11-08 23:42:02', 'heshengfu', '2022-01-03 14:26:58', 'system', '650000');
INSERT INTO `stock_info` VALUES ('5', 'iphone_12', 'è¹æææº12', '1000', '2021-11-08 23:42:02', 'heshengfu', '2021-11-21 21:11:08', 'heshengfu', '700000');
INSERT INTO `stock_info` VALUES ('6', 'iphone_13', 'è¹æææº13', '1000', '2021-11-08 23:42:02', 'heshengfu', '2021-11-21 21:11:08', 'heshengfu', '800000');
INSERT INTO `stock_info` VALUES ('7', 'xiaomi_note3', 'å°ç±³ææºnote3', '500', '2021-11-28 20:21:23', 'system', '2021-11-28 20:21:23', 'system', '200000');
INSERT INTO `stock_info` VALUES ('8', 'xiaomi_note4', 'å°ç±³ææºnote4', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '280000');
INSERT INTO `stock_info` VALUES ('9', 'xioami_note5', 'å°ç±³ææºnote5', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '300000');
INSERT INTO `stock_info` VALUES ('10', 'xiaomi_note6', 'å°ç±³ææºnote6', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '330000');
INSERT INTO `stock_info` VALUES ('11', 'xiaomi_note7', 'å°ç±³ææºnote7', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '350000');
INSERT INTO `stock_info` VALUES ('12', 'xiaomi_note8', 'å°ç±³ææºnote8', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '380000');
INSERT INTO `stock_info` VALUES ('13', 'honor50', 'è£è50', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '219900');
INSERT INTO `stock_info` VALUES ('14', 'honor50_SE', 'è£è50SE', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '219900');
INSERT INTO `stock_info` VALUES ('15', 'honor50Pro', 'è£è50Pro', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '349900');
INSERT INTO `stock_info` VALUES ('16', 'honorX10', 'è£èX10', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '179900');
INSERT INTO `stock_info` VALUES ('17', 'honorX30_Max', 'è£èX30_Max', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '239900');
INSERT INTO `stock_info` VALUES ('18', 'honorX30_Magic3_drag888', 'è£èX30_Magic3_éªé¾888', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '469900');
INSERT INTO `stock_info` VALUES ('19', 'honorX30_Magic3_Pro', 'è£èX30_Magic3_Pro', '500', '2021-11-28 20:42:19', 'system', '2021-11-28 20:42:19', 'system', '469900');
INSERT INTO `stock_info` VALUES ('20', 'meizu', 'é
æææº', '500', '2021-11-30 02:05:15', 'system', '2021-11-30 02:05:15', 'system', '200000');
INSERT INTO `stock_info` VALUES ('21', 'meizu3', 'é
æææº', '500', '2021-11-30 02:07:46', 'system', '2021-11-30 02:07:46', 'system', '200000');
INSERT INTO `stock_info` VALUES ('22', 'GalaxyNote20', '䏿Noto20', '500', '2021-12-04 16:22:32', 'system', '2021-12-04 16:22:32', 'system', '589900');
INSERT INTO `stock_info` VALUES ('23', 'GalaxyNote3', '䏿Note3', '500', '2021-12-04 16:36:50', 'system', '2021-12-04 16:36:50', 'system', '280000');
INSERT INTO `stock_info` VALUES ('24', 'GalaxyNote4', '䏿Note4', '500', '2021-12-04 16:36:50', 'system', '2021-12-04 16:36:50', 'system', '300000');
INSERT INTO `stock_info` VALUES ('25', 'GalaxyNote5', '䏿Note4', '500', '2021-12-04 16:36:50', 'system', '2021-12-04 16:36:50', 'system', '330000');
INSERT INTO `stock_info` VALUES ('26', 'GalaxyNote6', '䏿Note6', '500', '2021-12-04 16:36:50', 'system', '2021-12-04 16:36:50', 'system', '350000');
INSERT INTO `stock_info` VALUES ('27', 'GalaxyNote7', '䏿Note7', '500', '2021-12-04 16:36:50', 'system', '2021-12-04 16:36:50', 'system', '380000');
å¤å¶
- åæ ·æå¼
客æ·ç«¯æ°å»ºè¿æ¥ï¼ä½¿ç¨navicat
ç¨æ·åç»å½å¯ç è¿æ¥MySQLæå¡vueblog2æ°æ®åºåæ§è¡è®¢å表çåå»ºèæ¬vueblog
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主é®',
`user_id` bigint(20) NOT NULL,
`order_no` varchar(50) NOT NULL COMMENT '订åç¼å·',
`good_code` varchar(30) NOT NULL COMMENT 'ååç ',
`good_count` int(11) NOT NULL DEFAULT '1' COMMENT 'è®¢åæ°é',
`order_money` bigint(20) NOT NULL DEFAULT '0' COMMENT '订åéé¢ï¼åä½å',
`created_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´',
`created_by` varchar(30) NOT NULL DEFAULT 'system' COMMENT 'å建人',
`last_updated_date` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '䏿¬¡ä¿®æ¹æ¶é´',
`last_updated_by` varchar(30) DEFAULT 'system' COMMENT '䏿¬¡ä¿®æ¹äºº',
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4;
å¤å¶
-
模åä¸çalibaba-commons
å 䏿°å»ºä¸ä»¥ä¸ä¸¤ä¸ªæ°æ®åºå¯¹äºçå®ä½ç±»com.spring.cloud.alibaba.commons.pojo
StockInfo.java
@Data
@TableName("stock_info")
public class StockInfo extends BaseEntity {
/**
* 主é®ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* åå代ç
*/
@TableField(value = "good_code")
private String goodCode;
/**
* åååç§°
*/
@TableField(value = "good_name")
private String goodName;
/**
* åºåæ°é
*/
@TableField(value = "count")
private Integer count;
/**
* åååä»·,åä½ï¼å
*/
@TableField(value = "unit_price")
private Long unitPrice;
}
å¤å¶
OrderInfo.java
@Data
@TableName("orders")
public class OrderInfo extends BaseEntity {
@TableId(type=IdType.AUTO)
private Long orderId;
@TableField(value="user_id")
private Long userId;
@TableField(value = "order_no")
private String orderNo;
@TableField(value = "good_code")
private String goodCode;
@TableField(value = "good_count")
private int goodCount;
@TableField(value = "order_money")
private Long orderMoney;
}
å¤å¶
BaseEntity.java
@Data
public class BaseEntity implements Serializable {
/**
* å建人
*/
@TableField(value = "created_by", fill = FieldFill.INSERT)
private String createdBy;
/**
* åå»ºæ¥æï¼å¸¦æ¶é´ï¼
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(value = "created_date", fill = FieldFill.INSERT)
private Date createdDate;
/**
* ä¿®æ¹äººç¨æ·ID
*/
@TableField(value = "last_updated_by", fill = FieldFill.INSERT_UPDATE)
private String lastUpdatedBy;
/**
* ä¿®æ¹æ¥æï¼å¸¦æ¶é´ï¼
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(value = "last_updated_date", fill = FieldFill.INSERT_UPDATE)
private Date lastUpdatedDate;
}
å¤å¶
2.5 åºåå¾®æå¡ç¼ç
- å¯å¨ç±»
ServiceProviderApplication.java
@SpringBootApplication(scanBasePackages = {"com.spring.cloud.alibaba.commons",
"com.spring.cloud.alibaba.service.provider"})
@MapperScan(basePackages = "com.spring.cloud.alibaba.service.provider.mapper")
@EnableDiscoveryClient
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
å¤å¶
@EnableDiscoveryClient
注解ç¨äºå¼å¯å¾®æå¡èªå¨åç°åè½
-
å页é 置类MybatisPlus
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setOverflow(true);
paginationInterceptor.setDialectClazz("com.baomidou.mybatisplus.extension.plugins.pagination.dialects.MySqlDialect");
paginationInterceptor.setSqlParser(new JsqlParserCountOptimize());
return paginationInterceptor;
}
}
å¤å¶
3ï¼ Mapperå±ç¼ç
è¿éæä»¬éç¨
MybatisPlus
ä½ä¸ºæä¹ 屿¡æ¶ï¼éè¿ç»§æ¿
BaseMapper
å¯ç´æ¥è·å¾åºæ¬çæ°æ®åºCRUDæ¹æ³ã
@Repository
public interface StockMapper extends BaseMapper<StockInfo> {
}
å¤å¶
- Serviceå±ç¼ç
public interface IStockService extends IService<StockInfo> {
/**
* éè¿ååç¼ç æ¥æ¾åºå
*/
ResponseVo findStockByGoodCode(String goodCode);
/**
* ä¿®æ¹åºå
*/
ResponseVo updateStockById(StockInfo stockInfo);
}
å¤å¶
- æ§å¶å¨å±ç¼ç
@RestController
@RequestMapping("/stock")
@RefreshScope
public class StockController {
@Resource
private IStockService stockService;
/**
* éè¿ååç¼ç æ¥æ¾åºå
*/
@GetMapping(value = "/findStockByCode")
public ResponseVo findStockByGoodCode(@RequestParam("goodCode") String goodCode){
if(StringUtils.isEmpty(goodCode)) {
throw new IllegalArgumentException("parameter goodCode cannot be null");
}
return stockService.findStockByGoodCode(goodCode);
}
/**
* ä¿®æ¹åºå
*/
@PostMapping("/updateStockCountById")
public ResponseVo updateStockById(@RequestBody StockInfo stockInfo){
if(stockInfo.getId()==null || stockInfo.getId()<=0){
throw new IllegalArgumentException("parameter id cannot small than 0");
}
if(stockInfo.getCount() < 0) {
throw new IllegalArgumentException("parameter count cannot small than 0");
}
return stockService.updateStockById(stockInfo);
}
}
å¤å¶
2.6 订åæå¡ç¼ç
1ï¼ å¯å¨ç±»
AlibabaConsumerApplication.java
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(basePackages = "com.spring.cloud.alibabaconsumer.mapper")
public class AlibabaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(AlibabaConsumerApplication.class, args);
}
}
å¤å¶
- é 置类
RestTemplateConfig
ç±»ç¨äºæé å®ç°
http
æ
https
åè®®çè¿ç¨æå¡è°ç¨ç
RestTemplate
模æ¿å·¥å ·ç±»beanã
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
return restTemplateBuilder.build();
}
}
å¤å¶
TaskPoolConfig
ç±»ç¨äºæé èªå®ä¹çº¿ç¨æ± ï¼ç¨æ·ä¸åæåå弿¥è§åºå
package com.spring.cloud.alibabaconsumer.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
public class TaskPoolConfig {
/**
* èªå®ä¹çº¿ç¨æ±
* @return ThreadPoolExecutor
*/
@Bean(name = "customTaskWorkPoolExecutor")
public ThreadPoolExecutor customTaskWorkPoolExecutor() {
ArrayBlockingQueue<Runnable> taskQueue = new ArrayBlockingQueue(25);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 50, 30000, TimeUnit.MILLISECONDS, taskQueue);
return threadPoolExecutor;
}
}
å¤å¶
- æä¹ å±ç¼ç
package com.spring.cloud.alibabaconsumer.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.spring.cloud.alibaba.commons.pojo.OrderInfo;
import org.springframework.stereotype.Repository;
@Repository
public interface OrderMapper extends BaseMapper<OrderInfo> {
}
å¤å¶
- æå¡å±ç¼ç
æå¡å±ä¸»è¦å®ç°åå»ºè®¢åæ¹æ³
public interface OrderService extends IService<OrderInfo> {
ResponseVo createOrder(OrderInfo orderEntity, Integer flag);
}
å¤å¶
package com.spring.cloud.alibabaconsumer.service.impl;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spring.cloud.alibaba.commons.pojo.OrderInfo;
import com.spring.cloud.alibaba.commons.pojo.ResponseVo;
import com.spring.cloud.alibaba.commons.pojo.StockInfo;
import com.spring.cloud.alibabaconsumer.mapper.OrderMapper;
import com.spring.cloud.alibabaconsumer.service.OrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import redis.clients.jedis.Jedis;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService {
private final static Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
@Resource
private RestTemplate restTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private RedisConnectionFactory redisConnectionFactory;
@Resource(name="customTaskWorkPoolExecutor")
private ThreadPoolExecutor threadPoolExecutor;
@Value("${stock.service.query-stock-url}")
private String queryGoodStockServiceUrl;
@Value("${stock.service.update-count-url}")
private String updateStockCountUrl;
/**
* éè¿flagåæ°æ§å¶æ§è¡éæ¾éçæ¹å¼
* @param orderEntity 订åå®ä½ç±»
* @param flag 鿾鿹弿 è¯ï¼1-RedisTemplate#del(key)æ¹å¼éæ¾éï¼2-Jedis#evalæ¹æ³æ§è¡luaèæ¬éæ¾éï¼3-RedisTemplate#executeæ¹æ³æ§è¡luaèæ¬éæ¾é
*/
@Override
public ResponseVo createOrder(OrderInfo orderEntity, Integer flag) {
ResponseVo responseVo;
if (flag == 1 || flag == 2) {
responseVo = setNxLock(orderEntity, flag);
} else {
responseVo = redisTemplateLock(orderEntity);
}
return responseVo;
}
private void completeOrderInfo(OrderInfo orderInfo) {
if (orderInfo.getUserId() == null) {
orderInfo.setUserId(1L);
}
String orderNo = sdf.format(new Date(System.currentTimeMillis()));
logger.info("orderNo={}", orderNo);
orderInfo.setOrderNo(orderNo);
Date now = new Date(System.currentTimeMillis());
orderInfo.setCreatedBy("system");
orderInfo.setCreatedDate(now);
orderInfo.setLastUpdatedBy("system");
orderInfo.setLastUpdatedDate(now);
}
private ResponseVo setNxLock(OrderInfo orderEntity, Integer flag) {
String goodCode = orderEntity.getGoodCode();
Jedis jedis = (Jedis) redisConnectionFactory.getConnection().getNativeConnection();
// æ¥åºåæ¶å ä¸åå¸å¼é
String lockKey = "lock_" + goodCode;
long currentTime = System.currentTimeMillis();
Long lockResult = jedis.setnx(lockKey, String.valueOf(currentTime));
if (lockResult == 1) {
// 设置éå¤±ææ¶é´5s
try {
jedis.expire(lockKey, 5);
logger.info("get distribute lock success, lockKey={}", lockKey);
return queryStockAndInsertOrder(orderEntity);
} catch (Exception e) {
logger.error("", e);
return ResponseVo.error(e.getMessage());
} finally {
delLockByExecuteJedisCommand(jedis, lockKey, currentTime, flag);
}
} else {
logger.warn("get redis lock failed, stop to order");
return ResponseVo.error("请ç¨ååä¸åï¼å
¶ä»å®¢æ·æ£å¨å¯¹åä¸ååä¸å");
}
}
/**
* æ¥è¯¢åºåå¹¶ä¿å订å
* @param orderEntity
* @return
*/
private ResponseVo queryStockAndInsertOrder(OrderInfo orderEntity) {
String goodCode = orderEntity.getGoodCode();
String requestUrl = queryGoodStockServiceUrl + "?goodCode={goodCode}";
Map<String, Object> paramMap = new HashMap<>(1);
paramMap.put("goodCode", goodCode);
// éè¿RestTemplateè°ç¨è¿ç¨åºåæå¡
JSONObject jsonResponse = restTemplate.getForObject(requestUrl, JSONObject.class, paramMap);
logger.info("queryResponse={}", JSONUtil.toJsonStr(jsonResponse));
if (jsonResponse == null) {
return ResponseVo.error("è¿ç¨è°ç¨åºåæå¡å¤±è´¥");
}
int status = jsonResponse.getInt("status");
if (status != 200) {
return ResponseVo.error(status, jsonResponse.getStr("message"));
}
StockInfo stockInfo = jsonResponse.get("data", StockInfo.class);
if (stockInfo.getCount() <= orderEntity.getGoodCount()) {
return ResponseVo.error("åååºåä¸è¶³");
}
completeOrderInfo(orderEntity);
int insertCount = this.baseMapper.insert(orderEntity);
logger.info("insertCount={}", insertCount);
// 弿¥ååºå
asyncDecreaseStock(stockInfo, orderEntity.getGoodCount());
return ResponseVo.success(orderEntity);
}
private ResponseVo redisTemplateLock(OrderInfo orderEntity) {
String goodCode = orderEntity.getGoodCode();
String lockKey = "lock_" + goodCode;
Long value = System.currentTimeMillis();
// ValueOperation#setIfAbsent(key, value)çåä¸jedis.setNx(key,value)æ¹æ³ï¼é½å¯ä»¥å®ç°redisä¸åå¨key弿¶çæ·»å ç¼å
Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, String.valueOf(value));
if (flag) {
// å éæå,æ§è¡æ¥åºåæä½
try {
stringRedisTemplate.expire(lockKey, 5, TimeUnit.SECONDS);
logger.info("get distribute lock success, lockKey={}", lockKey);
return queryStockAndInsertOrder(orderEntity);
} catch (Exception e) {
logger.error("", e);
return ResponseVo.error(e.getMessage());
} finally {
// luaèæ¬ï¼æ³¨æluaèæ¬è¯è¨çè¯æ³ï¼Luaå°ç½è¯»è
å¯è·³è½¬å°è¿éå¦ä¹ ï¼https://www.runoob.com/lua/lua-tutorial.html
String script = "local value = redis.call('GET', KEYS[1])\n" +
"if value == ARGV[1] then \n" +
" redis.call('DEL', KEYS[1])" +
"return 1 \n" +
"end " +
"return 0 \n" ;
// æé RedisScriptå®ä¾
RedisScript<Long> redisScript = RedisScript.of(script, Long.class);
List<String> keys = new ArrayList<>(1);
keys.add(lockKey);
Long count = stringRedisTemplate.execute(redisScript, keys, String.valueOf(value));
if (count == 1) {
logger.info("release redis lock success");
} else {
logger.warn("release redis lock failed");
}
}
} else {
logger.warn("get redis lock failed, stop to order");
return ResponseVo.error("请ç¨ååä¸åï¼å
¶ä»å®¢æ·æ£å¨å¯¹åä¸ååä¸å");
}
}
private void delLockByExecuteJedisCommand(Jedis jedis, String lockKey, Long currentTime, Integer flag) {
if (flag==1) {
String value = jedis.get(lockKey);
if (value !=null && Long.parseLong(value) == currentTime) {
jedis.del(lockKey);
logger.info("release redis lock, lockKey={}",lockKey);
}
} else if (flag == 2) {
delLockByJedisExecuteLuaScript(jedis, lockKey, currentTime);
}
}
private void delLockByJedisExecuteLuaScript(Jedis jedis, String lockKey, Long currentTime) {
String script = "local value = redis.call('GET', KEYS[1])\n" +
"if value == ARGV[1] then \n" +
" redis.call('DEL', KEYS[1])" +
"return 1 \n" +
"end " +
"return 0 \n" ;
List<String> keys = new ArrayList<>(1);
keys.add(lockKey);
List<String> args = new ArrayList<>(1);
args.add(String.valueOf(currentTime));
// 注æè¿éçè¿åç±»åå¿
须使ç¨Long,ç¨Integerçè¯ä¼æ¥é
Long count = (Long) jedis.eval(script, keys, args);
if (count == 1) {
logger.info("release redis lock success");
} else {
logger.warn("release redis lock failed");
}
}
/**
* 弿¥ååºå 为äºç®åæ¥éª¤è¿é使ç¨çº¿ç¨æ± 模æååºåï¼çå®ççµåç¯å¢ä¼ä½¿ç¨RabbitMqæè
RocketMqæ¶æ¯é忥å®ç°ååºåçé»è¾
* @param stockInfo
* @param orderCount
*/
private void asyncDecreaseStock(StockInfo stockInfo, int orderCount) {
threadPoolExecutor.execute(() -> {
// ååºå
int remainCount = stockInfo.getCount() - orderCount;
stockInfo.setCount(remainCount);
stockInfo.setLastUpdatedBy("system");
stockInfo.setLastUpdatedDate(new Date(System.currentTimeMillis()));
ResponseVo updateResponse = restTemplate.postForObject(updateStockCountUrl, stockInfo, ResponseVo.class);
logger.info("updateResponse={}", JSONUtil.toJsonStr(updateResponse));
if (updateResponse.getStatus() == 200) {
logger.info("update stock count success");
} else {
logger.warn("update stock count failed, stockInfo={}, remainCount={}", stockInfo, remainCount);
}
});
}
}
å¤å¶
为äºé¿å ä¸ä¸ªå®¢æ·ç«¯éæ¾å«ç客æ·ç«¯ææçéï¼å¨éæ¾éä¹åéè¦è¿è¡æ ¡éªè¦å é¤ç鿝妿¯èªå·±å çéï¼ä¹å«éªç¾ãç´æ¥éè¿
Redis
客æ·ç«¯å æ§è¡
get(key)
夿value弿¯å¦ä¸é¢æçå¼ç¸çååå é¤keyéæ¾éï¼è¿ç§æ¹å¼æ æ³ä¿è¯æä½çååæ§ãå 为åå¨
redis
éªç¾ä¹åå é¤keyä¹åçªç¶åºç°æå¡å®æºçæ åµï¼èéè¿
redis
æ§è¡
lua
ååèæ¬çæ¹å¼æ°å¥½ä¿è¯äºæä½çååæ§ã
éè¿
redis
客æ·ç«¯æ§è¡
lua
èæ¬æä¸¤ç§æ¹å¼ï¼ä¸ç§æ¯éè¿
Jedis#eval
æ¹æ³æ§è¡ï¼å¦ä¸ç§æ¯éè¿
RedisTemplate#execute
æ¹æ³å®ç°ãéè¿è¿½è¸ªæ¹æ³æ§è¡é¾ï¼æä»¬ä¼åç°å®ä»¬çåºå±å ¶å®é½æ¯éè¿
RedisConnnection
æ§è¡
eval
å½ä»¤è¿è¡è¡
lua
èæ¬çã
5ï¼ æ§å¶å¨å±ç¼ç
æ§å¶å¨å±æ³¨æå®ç°åå»ºè®¢åæ¥å£åæ°çæ¥æ¶ä¸æå¡å±çè°ç¨
package com.spring.cloud.alibabaconsumer.controller;
import com.spring.cloud.alibaba.commons.pojo.OrderInfo;
import com.spring.cloud.alibaba.commons.pojo.ResponseVo;
import com.spring.cloud.alibabaconsumer.service.OrderService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/order")
public class OrderController {
@Resource
private OrderService orderService;
@PostMapping("/create")
public ResponseVo createOrder(@RequestBody OrderInfo orderEntity, @RequestParam("flag") Integer flag) {
return orderService.createOrder(orderEntity, flag);
}
}
å¤å¶
3 ææä½éª
ç¼ç 宿ä¹åå°±æ¯æé¡¹ç®è·èµ·æ¥æ¥çææ æ¶å»äºï¼
3.1 æå¡å¯å¨
æ¬å°å¯å¨
Mysql
å
Redis
æå¡ï¼ Linuxæå¡å¨ä¸åæºæ¨¡å¼å¯å¨
Nacos
æå¡
æ¬æºä¸ç
Mysql
å
Redis
æå¡å¯éè¿âæççµèâ->å³é®"管ç"->âæå¡ååºç¨ç¨åºâ->âæå¡âæ¾å°æç §å¨æ¬å°ç
Mysql
å
Redis
æå¡ï¼ç¶åç¹å·¦ä¸è§çâå¯å¨âæ¤æå¡å®æ
Mysql
å
Redis
æå¡çå¯å¨ã
å®è£ å¨Linuxæå¡å¨ä¸çNacosæå¡çå¯å¨å¯éè¿è¿ç¨ssh客æ·ç«¯è¿æ¥Linuxæå¡å¨åè¿å ¥nacosçbinæ§è¡åæºæ¨¡å¼å¯å¨å½ä»¤(Nacosé群模å¼å¨æç1æ ¸2Gçæå¡å¨ä¸ä½¿ç¨ä¸å端å£ä»£æ¿ä¸åå®ä¾å¯å¨ä¸äºï¼åªå¥½ç¨åæºæ¨¡å¼äº)
ssh startup.sh -m standalaone
å¤å¶
妿æ¯å¨èªå·±çwindowsç³»ç»è®¡ç®æºä¸å¯å¨nacosæå¡ï¼åéè¿ doså½ä»¤å¨nacosçbinç®å½ä¸éè¿è¾å ¥cmdå卿å¼çæ§å¶å°ä¸è¾å ¥ä»¥ä¸å½ä»¤åå车å³å¯
startup.cmd -m standalone
å¤å¶
ç¶åå¨IDEAä¸å åå¯å¨
alibaba-service-provider
å
alibaba-service-consumer
两个微æå¡
两个微æå¡å¯å¨æååæä»¬è¿å ¥å¨æµè§å¨ä¸è¾å ¥ä»¥ä¸ç½åè¿å ¥nacosçUIçé¢å¯ä»¥çå°
stock-service
å
order-service
齿³¨åå°äºNacos注åä¸å¿
3.2 åå»ºè®¢åæ¥å£æµè¯
两个微æå¡å¯å¨æååå¨postmanä¸è°ç¨åå»ºè®¢åæ¥å£(å¯ä»¥éè¿ä¿®æ¹flag忰弿¥çä¸åçå éåéæ¾
redis
éæ¹å¼)
POST http://localhost:9002/order-service/order/create?flag=2
{
"userId": 1,
"goodCode": "iphone_11",
"goodCount": 10,
"orderMoney": 6500000
}
å¤å¶
ç¹å»Sendæé®åå¯ä»¥çå°æ¥å£ååºä¿¡æ¯å¦ä¸ï¼
{
"uuid": "c6f638f1-a1d8-4b98-9be7-2508a27f0a3b",
"status": 200,
"message": "OK",
"data": {
"createdBy": "system",
"createdDate": "2022-01-03 23:20:43",
"lastUpdatedBy": "system",
"lastUpdatedDate": "2022-01-03 23:20:43",
"orderId": 12,
"userId": 1,
"orderNo": "20220103232043.752",
"goodCode": "iphone_11",
"goodCount": 10,
"orderMoney": 6500000
}
}
å¤å¶
å¨
alibab-service-consumer
æå¡çæ§å¶å°ä¸å¯ä»¥çå°å¦ä¸æ¥å¿ä¿¡æ¯:
2022-01-03 23:20:43.679 INFO 3884 --- [nio-9002-exec-5] c.s.c.a.service.impl.OrderServiceImpl : get distribute lock success, lockKey=lock_iphone_11
2022-01-03 23:20:43.749 INFO 3884 --- [nio-9002-exec-5] c.s.c.a.service.impl.OrderServiceImpl : queryResponse={"data":{"unitPrice":650000,"lastUpdatedBy":"system","count":860,"lastUpdatedDate":"2022-01-03 14:26:58","createdDate":"2021-11-08 23:42:02","goodName":"è¹æææº11","createdBy":"heshengfu","id":4,"goodCode":"iphone_11"},"message":"OK","uuid":"3c3c4016-ec9f-40c0-928f-c4375c52ea14","status":200}
2022-01-03 23:20:43.753 INFO 3884 --- [nio-9002-exec-5] c.s.c.a.service.impl.OrderServiceImpl : orderNo=20220103232043.752
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12906d4] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@21355453 wrapping com.mysql.cj.jdbc.ConnectionImpl@1f928ab] will not be managed by Spring
==> Preparing: INSERT INTO orders ( user_id, order_no, good_code, good_count, order_money, created_by, created_date, last_updated_by, last_updated_date ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )
==> Parameters: 1(Long), 20220103232043.752(String), iphone_11(String), 10(Integer), 6500000(Long), system(String), 2022-01-03 23:20:43.753(Timestamp), system(String), 2022-01-03 23:20:43.753(Timestamp)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@12906d4]
2022-01-03 23:20:43.771 INFO 3884 --- [nio-9002-exec-5] c.s.c.a.service.impl.OrderServiceImpl : insertCount=1
2022-01-03 23:20:43.794 INFO 3884 --- [pool-4-thread-2] c.s.c.a.service.impl.OrderServiceImpl : updateResponse={"data":1,"message":"OK","uuid":"288b8ca8-a9f2-4dec-9f04-3fb1de1adb6b","status":200}
2022-01-03 23:20:43.794 INFO 3884 --- [pool-4-thread-2] c.s.c.a.service.impl.OrderServiceImpl : update stock count success
2022-01-03 23:20:43.942 INFO 3884 --- [nio-9002-exec-5] c.s.c.a.service.impl.OrderServiceImpl : release redis lock success
å¤å¶
å¨ä¸è¿°æ¥å¿ä¸æä»¬å¯ä»¥æ¸ æ°å°çå°è·åè·åå°rediséåéæ¾rediséï¼ä»¥å订å表æå ¥æ°æ®çsqlæ§è¡æ¥å¿ã
å¨
alibaba-service-consumer
æå¡æ§å¶å°ä¸å¯ä»¥çå°æ¥è¯¢åºååååºåçæ¥å¿ä¿¡æ¯
2022-01-03 23:20:43.695 INFO 19532 --- [nio-9000-exec-4] c.s.c.a.s.p.service.impl.StockService : goodCode=iphone_11
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@a91626] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@7270531 wrapping com.mysql.cj.jdbc.ConnectionImpl@517d56] will not be managed by Spring
==> Preparing: SELECT id,good_code,good_name,count,unit_price,created_by,created_date,last_updated_by,last_updated_date FROM stock_info WHERE good_code = ?
==> Parameters: iphone_11(String)
<== Columns: id, good_code, good_name, count, unit_price, created_by, created_date, last_updated_by, last_updated_date
<== Row: 4, iphone_11, è¹æææº11, 860, 650000, heshengfu, 2021-11-08 23:42:02, system, 2022-01-03 14:26:58
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@a91626]
2022-01-03 23:20:43.779 INFO 19532 --- [nio-9000-exec-5] c.s.c.a.s.p.service.impl.StockService : id=4, count=850
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@909c37] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@2391458 wrapping com.mysql.cj.jdbc.ConnectionImpl@517d56] will not be managed by Spring
==> Preparing: UPDATE stock_info SET good_code=?, good_name=?, count=?, unit_price=?, created_by=?, created_date=?, last_updated_by=?, last_updated_date=? WHERE id=?
==> Parameters: iphone_11(String), è¹æææº11(String), 850(Integer), 650000(Long), heshengfu(String), 2021-11-08 23:42:02.0(Timestamp), system(String), 2022-01-03 23:20:43.0(Timestamp), 4(Long)
<== Updates: 1
å¤å¶
åºåæå¡æ§å¶å°ä¸ä¹æå°åºäºæ¥è¯¢åºååååºåç详ç»ä¿¡æ¯
ç¶åæä»¬æ¥è¯¢ä¸¤ä¸ªæ°æ®åºä¸ç
stock_info
表å
orders
表é½è½çå°åºåæ°æ®çæ¹å以åè®¢åæ°æ®çå¢å
5 å°ç»
- æ¬æä»¥nacosä½ä¸ºæ³¨åä¸å¿ï¼æå»ºäºä¸¤ä¸ªå¾®æå¡æ¨¡æçµå项ç®ä¸çåºåæå¡å订åæå¡ï¼ä¸»è¦æ¼ç¤ºäºåå¸å¼åºæ¯ä¸ä½¿ç¨rediså®ç°åå¸å¼äºå¡éã
- redis é¢åjavaè¯è¨ç两ç§å¸¸ç¨ç客æ·ç«¯ælettuceåJedisï¼
- redisæ§è¡Luaèæ¬ä¿è¯äºå®åºæä½äºå¡çååæ§ï¼redisæ§è¡luaèæ¬ä¸»è¦æä¸¤ç§æ¹å¼ï¼
åJedis#eval(String script, List<String> keys, List<String> args)
RedisTemplate#execute(RedisScript<T> script, List<K> keys, Object... args)
- ä¸è¶³ä¹å¤ï¼æ²¡æå¯å¨å¤ä¸ª
æå¡å®ä¾ï¼ä¹æ²¡ä½¿ç¨alibaba-service-provider
åæµå·¥å ·è¿è¡é«å¹¶ååºæ¯æµè¯ï¼ ä¸ä¸ç¯æç« å°å¯¹å¤å®ä¾åé«å¹¶ååºæ¯è¿è¡è¡¥å æµè¯Jemter
æ¬æé¡¹ç®å·²ä¸ä¼ å°gitee个人代ç ä»åºï¼æå ´è¶£çæåå¯ä»¥å é䏿¥åèï¼gitee代ç ä»åºå°å https://gitee.com/heshengfu1211/alibaba-demos.git
---END---
ååä¸æï¼æ¬¢è¿çå°è¿éçæåé½è½ç¹äº®ãå¨çãï¼è°¢è°¢ï¼
å¤å¶