Compare commits

...

2 Commits

Author SHA1 Message Date
8b37cccb93 完成基本下单的学习 2026-03-03 18:02:03 +08:00
887fea1961 添加rocketmq依赖 2026-03-03 14:23:10 +08:00
24 changed files with 648 additions and 57 deletions

1
broker.conf Normal file
View File

@@ -0,0 +1 @@
"brokerIP1=127.0.0.1"

View File

@@ -1,61 +1,62 @@
version: '3.8'
services:
# NameServer 服务
rocketmq-namesrv:
image: apache/rocketmq:5.2.0
container_name: rocketmq-namesrv
rmqnamesrv:
image: apache/rocketmq:5.3.2 # 或换成 5.2.0,如果你必须用这个版本
container_name: rmqnamesrv
restart: unless-stopped
ports:
- "9876:9876"
# 移除挂载配置
environment:
- TZ=Asia/Shanghai
- JAVA_OPT_EXT=-Xms512m -Xmx512m -Xmn256m
command: sh mqnamesrv
restart: always
networks:
- rocketmq-network
- rmq
rmqbroker:
image: apache/rocketmq:5.3.2
container_name: rmqbroker
restart: unless-stopped
ports:
- "10911:10911" # FastRemoting 端口(客户端主要连接这里)
- "10909:10909" # HA 端口(可选)
environment:
- TZ=Asia/Shanghai
# 调整JVM内存避免内存不足
- ROCKETMQ_OPT="-Xms256m -Xmx256m -Xmn128m"
# Broker 服务
rocketmq-broker:
image: apache/rocketmq:5.2.0
container_name: rocketmq-broker
ports:
- "10911:10911"
- "10909:10909"
# 移除挂载配置,直接通过环境变量传递核心配置
- NAMESRV_ADDR=rmqnamesrv:9876
- JAVA_OPT_EXT=-Xms1g -Xmx1g -Xmn512m
depends_on:
- rmqnamesrv
command: >
sh mqbroker -n rocketmq-namesrv:9876
-c /home/rocketmq/conf/broker.conf
-Drocketmq.broker.ip1=你的服务器IP
-Drocketmq.broker.autoCreateTopicEnable=true
-Drocketmq.broker.autoCreateSubscriptionGroup=true
depends_on:
- rocketmq-namesrv
environment:
- TZ=Asia/Shanghai
- NAMESRV_ADDR=rocketmq-namesrv:9876
- ROCKETMQ_OPT="-Xms512m -Xmx512m -Xmn256m"
restart: always
sh -c "
echo '
brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = true
autoCreateSubscriptionGroup = true
' > /home/rocketmq/rocketmq-5.3.2/conf/broker.conf &&
mqbroker -n rmqnamesrv:9876 -c /home/rocketmq/rocketmq-5.3.2/conf/broker.conf
"
networks:
- rocketmq-network
- rmq
# RocketMQ 控制台端口改为8083
rocketmq-dashboard:
image: apacherocketmq/rocketmq-dashboard:2.0.0
container_name: rocketmq-dashboard
rmqdashboard:
image: apacherocketmq/rocketmq-dashboard:latest
container_name: rmqdashboard
restart: unless-stopped
ports:
- "8083:8080" # 宿主机8083端口映射到容器8080
- "18080:8080" # 主机端口改成 18080避免与你其他服务冲突
environment:
- NAMESRV_ADDR=rocketmq-namesrv:9876
- TZ=Asia/Shanghai
- JAVA_OPTS=-Drocketmq.namesrv.addr=rmqnamesrv:9876 -Xms512m -Xmx512m
depends_on:
- rocketmq-namesrv
restart: always
- rmqnamesrv
networks:
- rocketmq-network
- rmq
networks:
rocketmq-network:
rmq:
driver: bridge

View File

@@ -24,5 +24,16 @@
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>13.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,14 @@
package cn.mayiming.Common.Entity;
import lombok.Data;
import org.jetbrains.annotations.NotNull;
@Data
public class StockDeductDTO {
@NotNull
private Long id;
@NotNull
private Integer deductNum;
}

View File

@@ -44,6 +44,22 @@ spring:
# 按 IP 限流(默认)
key-resolver: "#{@ipKeyResolver}"
- id: stock-service
uri: lb://stock-service
predicates:
- Path=/stock/**
filters:
- RewritePath=/stock/(?<segment>.*), /${segment}
# 全局限流配置
- name: RequestRateLimiter
args:
# 令牌桶填充速率:每秒生成 1 个令牌(即 10 秒 10 个)
redis-rate-limiter.replenishRate: 1
# 令牌桶最大容量:最多存 10 个令牌(允许突发 10 次请求)
redis-rate-limiter.burstCapacity: 10
# 按 IP 限流(默认)
key-resolver: "#{@ipKeyResolver}"
sentinel:
# Sentinel 控制台地址(如果启动了控制台,用于可视化配置)
transport:

View File

@@ -78,5 +78,9 @@
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -3,27 +3,77 @@ package cn.mayiming.Controller;
import cn.mayiming.Service.OrderService;
import cn.mayiming.entity.Order;
import cn.mayiming.entity.Result;
import cn.mayiming.entity.StockDeductDTO;
import cn.mayiming.entity.User;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/order")
@PostMapping("/search")
public User getUserOrder(@RequestBody User user){
//throw new RuntimeException("Cuowu ");
return orderService.SearchUserbyname(user);
}
@GetMapping("/order")
@GetMapping("/list")
public List<Order> getUserOrder(@RequestParam Integer id){
return orderService.OrderListById(id);
}
@PostMapping("/create")
public Result<Object> createOrder(@RequestBody Map<String, Object> jsonMap){
try {
// 1. 安全获取userId先转Number再取int值兼容Integer/Long
Number userIdNum = (Number) jsonMap.get("userId");
if (userIdNum == null) {
return Result.fail(400, "userId不能为空");
}
int userId = userIdNum.intValue();
// 2. 安全获取stockid先转Number再取long值兼容Integer/Long
Number stockIdNum = (Number) jsonMap.get("stockid");
if (stockIdNum == null) {
return Result.fail(400, "stockid不能为空");
}
Long stockId = stockIdNum.longValue();
// 3. 安全获取deductnum先转Number再取int值兼容Integer/Long
Number deductNumNum = (Number) jsonMap.get("deductnum");
if (deductNumNum == null) {
return Result.fail(400, "deductnum不能为空");
}
int deductNum = deductNumNum.intValue();
// 4. 组装DTO
StockDeductDTO stockDeductDTO = new StockDeductDTO();
stockDeductDTO.setId(stockId);
stockDeductDTO.setDeductNum(deductNum);
// 5. 调用服务
int serviceResult = orderService.createOrder(stockDeductDTO, userId);
if (serviceResult != 0) {
// 库存扣减/订单创建失败
return Result.fail("库存扣减失败,订单创建失败");
}
// 成功可以返回额外数据比如订单ID
return Result.success("库存扣减成功,订单创建成功");
} catch (Exception e) {
// 捕获所有异常,返回友好提示
e.printStackTrace();
return Result.fail("订单创建异常:" + e.getMessage());
}
}
}

View File

@@ -2,8 +2,12 @@ package cn.mayiming.Service;
import cn.mayiming.Mapper.OrderMapper;
import cn.mayiming.entity.Order;
import cn.mayiming.entity.StockDeductDTO;
import cn.mayiming.entity.User;
import cn.mayiming.feign.StockFeignClient;
import cn.mayiming.feign.UserFeignClient;
import jakarta.annotation.Resource;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -17,6 +21,12 @@ public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private StockFeignClient stockFeignClient;
@Resource
private RocketMQTemplate rocketMQTemplate;
public User SearchUserbyname (User user) {
return userFeignClient.selectByUsername(user);
}
@@ -31,4 +41,30 @@ public class OrderService {
}
public void sendPaySuccessMessage(String msg) {
// 2. 发送消息:格式为 "主题:标签"
// 同步发送:等待 Broker 确认,返回发送结果(可靠)
try {
// 参数1topic:tag对应消费者的 topic + selectorExpression
// 参数2消息体自动序列化
rocketMQTemplate.convertAndSend("pay_topic:pay_success", msg);
} catch (Exception e) {
// 发送失败处理(如记录日志、重试、告警)
System.err.println("消息发送失败:" + ",原因:" + e.getMessage());
throw new RuntimeException("消息发送失败", e);
}
}
public int createOrder(StockDeductDTO stockDeductDTO,int i) {
int res = 0;
if(stockFeignClient.deductstock(stockDeductDTO)==0){
res ++;
}
if(userFeignClient.GetUserByid(i)==null){
res ++;
}
return res;
}
}

View File

@@ -0,0 +1,69 @@
package cn.mayiming.entity;
/**
* 通用接口响应结果类
* @param <T> 响应数据类型
*/
public class Result<T> {
// 响应码200成功500失败400参数错误等
private Integer code;
// 响应消息
private String msg;
// 响应数据
private T data;
// 静态构造方法(推荐)
// 成功(无数据)
public static <T> Result<T> success() {
return new Result<>(200, "操作成功", null);
}
// 成功(带数据)
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
// 失败
public static <T> Result<T> fail(String msg) {
return new Result<>(500, msg, null);
}
// 失败(自定义码+消息)
public static <T> Result<T> fail(Integer code, String msg) {
return new Result<>(code, msg, null);
}
// 构造器、getter/setter
public Result() {}
public Result(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
// getter和setter
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

View File

@@ -0,0 +1,17 @@
package cn.mayiming.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class StockDeductDTO {
@NotNull
@JsonProperty("id")
private Long id;
@NotNull
@JsonProperty("deductnum")
private Integer deductNum;
}

View File

@@ -0,0 +1,14 @@
package cn.mayiming.feign;
import cn.mayiming.entity.StockDeductDTO;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = "stock-service")
public interface StockFeignClient {
@PostMapping("/stock/deduct")
int deductstock(@RequestBody StockDeductDTO stockDeductDTO);
}

View File

@@ -24,7 +24,7 @@ spring:
# 数据库驱动类MySQL 8.x 用 com.mysql.cj.jdbc.Driver5.x 用 com.mysql.jdbc.Driver
driver-class-name: com.mysql.cj.jdbc.Driver
# 数据库连接 URL替换为你的数据库地址、端口、库名如 user_db
url: jdbc:mysql://rm-f8z6oc5a03331500p8o.mysql.rds.aliyuncs.com:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
url: jdbc:mysql://rm-f8z6oc5a03331500p8o.mysql.rds.aliyuncs.com:3306/order_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
# 数据库用户名(默认 root根据实际情况修改
username: root
# 数据库密码(替换为你的 MySQL 密码)
@@ -38,4 +38,18 @@ spring:
# 连接超时时间(毫秒)
connection-timeout: 30000
# 连接最大存活时间(毫秒)
max-lifetime: 1800000
max-lifetime: 1800000
rocketmq:
# NameServer 地址(替换为你的 RocketMQ 服务器IP
name-server: 127.0.0.1:9876
producer:
# 生产者组名(必须唯一,建议:服务名+producer
group: pay-service-producer
# 发送失败重试次数默认2次
retry-times-when-send-failed: 3
# 发送超时时间默认3000ms
send-message-timeout: 5000
# 消息最大长度默认4M
max-message-size: 4194304
# 压缩消息阈值超过4K自动压缩
compress-message-body-threshold: 4096

View File

@@ -19,10 +19,69 @@
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 可选Nacos 配置管理(从 Nacos 读取配置文件) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 负载均衡Feign 内置,但显式引入更清晰) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.19</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>4.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,13 +1,17 @@
package cn.mayiming;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Hello world!
*
*/
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
SpringApplication.run(App.class, args);
}
}

View File

@@ -0,0 +1,18 @@
package cn.mayiming.Consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
@Component
@RocketMQMessageListener(
topic = "pay_topic",
consumerGroup = "pay-service-consumer",
selectorExpression = "pay_success"
)
public class payConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("接收到消息"+s);
}
}

View File

@@ -0,0 +1,52 @@
server:
port: 9093
spring:
application:
name: pay-service
cloud:
nacos:
# 服务注册发现配置
discovery:
server-addr: localhost:8848 # Nacos 服务地址(默认端口 8848
namespace: public # 命名空间(默认 public自定义需先在 Nacos 控制台创建)
group: DEFAULT_GROUP # 分组(默认 DEFAULT_GROUP
service: pay-service # 注册到 Nacos 的服务名(建议和子项目 artifactId 一致)
# 配置管理配置(如果引入了 config 依赖才需要)
config:
server-addr: localhost:8848 # 和 discovery 一致
file-extension: yaml
namespace: public
group: DEFAULT_GROUP
config:
import: nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}?server-addr=${spring.cloud.nacos.config.server-addr}
datasource:
# 数据库驱动类MySQL 8.x 用 com.mysql.cj.jdbc.Driver5.x 用 com.mysql.jdbc.Driver
driver-class-name: com.mysql.cj.jdbc.Driver
# 数据库连接 URL替换为你的数据库地址、端口、库名如 user_db
url: jdbc:mysql://rm-f8z6oc5a03331500p8o.mysql.rds.aliyuncs.com:3306/pay_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
# 数据库用户名(默认 root根据实际情况修改
username: root
# 数据库密码(替换为你的 MySQL 密码)
password: Root123456
# 可选:连接池配置(推荐使用 HikariCPSpring Boot 2.x 默认)
hikari:
# 连接池最大连接数
maximum-pool-size: 10
# 连接池最小空闲连接数
minimum-idle: 2
# 连接超时时间(毫秒)
connection-timeout: 30000
# 连接最大存活时间(毫秒)
max-lifetime: 1800000
rocketmq:
# NameServer 地址(替换为你的 RocketMQ 服务器IP
name-server: 127.0.0.1:9876
consumer:
# 消费者组名(必须唯一,建议按服务+用途命名)
group: order-service-consumer
# 消费模式CONCURRENTLY并发消费默认/ORDERLY顺序消费
consume-mode: CONCURRENTLY
# 批量消费最大条数默认1单条消费
consume-message-batch-max-size: 1
# 最大重试次数(消费失败后自动重试,超过次数进入死信队列)
max-reconsume-times: 3

17
pom.xml
View File

@@ -32,6 +32,8 @@
<mysql.version>8.0.33</mysql.version>
</properties>
<!-- 依赖管理(子模块继承版本,仅管理不引入) -->
<dependencyManagement>
<dependencies>
@@ -83,6 +85,21 @@
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client-java</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.3.2</version> <!-- 适配 RocketMQ 5.x建议2.2.x+ -->
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>5.3.2</version> <!-- 这个存在于 Central -->
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -19,10 +19,70 @@
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 可选Nacos 配置管理(从 Nacos 读取配置文件) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 负载均衡Feign 内置,但显式引入更清晰) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.19</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>4.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,13 +1,21 @@
package cn.mayiming;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Hello world!
*
*/
@SpringBootApplication
@EnableTransactionManagement
@MapperScan("cn.mayiming.Mapper")
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
SpringApplication.run(App.class, args);
}
}

View File

@@ -0,0 +1,23 @@
package cn.mayiming.Controller;
import cn.mayiming.Entity.StockDeductDTO;
import cn.mayiming.Service.stockService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/stock")
public class stockController {
@Autowired
stockService stockService;
@PostMapping("/deduct")
public int deductstock(@Valid @RequestBody StockDeductDTO stockDeductDTO) {
return stockService.deductStock(stockDeductDTO.getId(),stockDeductDTO.getDeductNum());
}
}

View File

@@ -0,0 +1,17 @@
package cn.mayiming.Entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class StockDeductDTO {
@NotNull
@JsonProperty("id")
private Long id;
@NotNull
@JsonProperty("deductnum")
private Integer deductNum;
}

View File

@@ -0,0 +1,16 @@
package cn.mayiming.Mapper;
import feign.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
@Repository
public interface StockMapper {
@Select("SELECT stock_num FROM t_stock WHERE goods_id = #{goodsId}")
Integer selectStockByGoodsId(@Param("goodsId") Long goodsId);
@Update("UPDATE t_stock SET stock_num = stock_num - #{deductNum} WHERE goods_id = #{goodsId} AND stock_num >= #{deductNum}")
int deductStock(@Param("goodsId") Long goodsId, @Param("deductNum") Integer deductNum);
}

View File

@@ -0,0 +1,18 @@
package cn.mayiming.Service;
import cn.mayiming.Mapper.StockMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class stockService {
@Autowired
StockMapper stockMapper;
@Transactional(rollbackFor = Exception.class)
public int deductStock(Long goodsId, int i) {
return stockMapper.deductStock(goodsId, i);
}
}

View File

@@ -0,0 +1,52 @@
server:
port: 9094
spring:
application:
name: stock-service
cloud:
nacos:
# 服务注册发现配置
discovery:
server-addr: localhost:8848 # Nacos 服务地址(默认端口 8848
namespace: public # 命名空间(默认 public自定义需先在 Nacos 控制台创建)
group: DEFAULT_GROUP # 分组(默认 DEFAULT_GROUP
service: stock-service # 注册到 Nacos 的服务名(建议和子项目 artifactId 一致)
# 配置管理配置(如果引入了 config 依赖才需要)
config:
server-addr: localhost:8848 # 和 discovery 一致
file-extension: yaml
namespace: public
group: DEFAULT_GROUP
config:
import: nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}?server-addr=${spring.cloud.nacos.config.server-addr}
datasource:
# 数据库驱动类MySQL 8.x 用 com.mysql.cj.jdbc.Driver5.x 用 com.mysql.jdbc.Driver
driver-class-name: com.mysql.cj.jdbc.Driver
# 数据库连接 URL替换为你的数据库地址、端口、库名如 user_db
url: jdbc:mysql://rm-f8z6oc5a03331500p8o.mysql.rds.aliyuncs.com:3306/stock_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
# 数据库用户名(默认 root根据实际情况修改
username: root
# 数据库密码(替换为你的 MySQL 密码)
password: Root123456
# 可选:连接池配置(推荐使用 HikariCPSpring Boot 2.x 默认)
hikari:
# 连接池最大连接数
maximum-pool-size: 10
# 连接池最小空闲连接数
minimum-idle: 2
# 连接超时时间(毫秒)
connection-timeout: 30000
# 连接最大存活时间(毫秒)
max-lifetime: 1800000
#rocketmq:
# # NameServer 地址(替换为你的 RocketMQ 服务器IP
# name-server: 127.0.0.1:9876
# consumer:
# # 消费者组名(必须唯一,建议按服务+用途命名)
# group: order-service-consumer
# # 消费模式CONCURRENTLY并发消费默认/ORDERLY顺序消费
# consume-mode: CONCURRENTLY
# # 批量消费最大条数默认1单条消费
# consume-message-batch-max-size: 1
# # 最大重试次数(消费失败后自动重试,超过次数进入死信队列)
# max-reconsume-times: 3