Commit on 2025/08/06 周三 22:17:46.88
This commit is contained in:
parent
b3275c206e
commit
bb082e5dc3
@ -90,3 +90,51 @@ if (V == A) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
如何多线程循环打印1-100数字?
|
||||
|
||||
```java
|
||||
public class AlternatePrint {
|
||||
private static int count = 1;
|
||||
private static final Object lock = new Object();
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Thread(() -> {
|
||||
while (count <= 100) {
|
||||
synchronized (lock) {
|
||||
if (count % 2 == 1) {
|
||||
System.out.println(Thread.currentThread().getName() + ": " + count++);
|
||||
lock.notify();
|
||||
} else {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, "Thread-1").start();
|
||||
|
||||
new Thread(() -> {
|
||||
while (count <= 100) {
|
||||
synchronized (lock) {
|
||||
if (count % 2 == 0) {
|
||||
System.out.println(Thread.currentThread().getName() + ": " + count++);
|
||||
lock.notify();
|
||||
} else {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, "Thread-2").start();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
@ -183,6 +183,8 @@ public class RandomDemo {
|
||||
|
||||
子序列:字符串中**按顺序选取的一段字符**,可以不连续。
|
||||
|
||||
子数组:等于连续子序列
|
||||
|
||||
异位词:字母相同、字母频率相同、顺序不同,如`"listen"` 和 `"silent"`
|
||||
|
||||
|
||||
@ -1175,6 +1177,22 @@ public class QuickSort {
|
||||
|
||||
|
||||
|
||||
**Java随机**
|
||||
|
||||
```java
|
||||
mport java.util.Random;
|
||||
|
||||
public class RandomDemo {
|
||||
public static void main(String[] args) {
|
||||
Random random = new Random();
|
||||
int num = random.nextInt(6); // 生成 [0, 5] 的随机整数
|
||||
System.out.println(num);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 快速选择
|
||||
|
||||
时间复杂度: O(n)
|
||||
@ -1183,58 +1201,53 @@ public class QuickSort {
|
||||
public class QuickSelect {
|
||||
|
||||
/**
|
||||
* 在 nums[low..high] 区间内,寻找排序后下标为 k 的元素(第 k 小)
|
||||
* 对 arr 在 [low..high] 范围内,使用“挖坑填坑”分区,返回枢轴的最终位置
|
||||
*/
|
||||
public int quickselect(int[] nums, int low, int high, int k) {
|
||||
// 区间内只有一个元素,直接返回
|
||||
if (low == high) {
|
||||
return nums[low];
|
||||
}
|
||||
|
||||
// 选取区间第一个元素作为枢轴
|
||||
int pivot = nums[low];
|
||||
private int partition(int[] arr, int low, int high) {
|
||||
int pivot = arr[low];
|
||||
int left = low, right = high;
|
||||
|
||||
// “挖坑填坑”分区:左边填小于 pivot 的值,右边填大于 pivot 的值
|
||||
while (left < right) {
|
||||
// 从右向左找第一个 < pivot 的
|
||||
while (left < right && nums[right] >= pivot) {
|
||||
while (left < right && arr[right] >= pivot) {
|
||||
right--;
|
||||
}
|
||||
nums[left] = nums[right]; // 填到左“坑”
|
||||
|
||||
// 从左向右找第一个 > pivot 的
|
||||
while (left < right && nums[left] <= pivot) {
|
||||
arr[left] = arr[right];
|
||||
while (left < right && arr[left] <= pivot) {
|
||||
left++;
|
||||
}
|
||||
nums[right] = nums[left]; // 填到右“坑”
|
||||
}
|
||||
|
||||
// 把 pivot 放回最终位置
|
||||
nums[left] = pivot;
|
||||
|
||||
// 根据 pivot 位置与 k 比较,决定去哪一边继续
|
||||
if (left == k) {
|
||||
return nums[left];
|
||||
} else if (k < left) {
|
||||
return quickselect(nums, low, left - 1, k);
|
||||
} else {
|
||||
return quickselect(nums, left + 1, high, k);
|
||||
arr[right] = arr[left];
|
||||
}
|
||||
arr[left] = pivot;
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数组中第 k 大的元素
|
||||
* @param nums 输入数组
|
||||
* @param k 1-based,第 k 大
|
||||
* 在 arr[low..high] 区间内,寻找第 k 小元素(k 从 0 开始)
|
||||
*/
|
||||
public int quickselect(int[] arr, int low, int high, int k) {
|
||||
if (low <= high) {
|
||||
int pivotPos = partition(arr, low, high);
|
||||
if (pivotPos == k) {
|
||||
return arr[pivotPos];
|
||||
} else if (k < pivotPos) {
|
||||
return quickselect(arr, low, pivotPos - 1, k);
|
||||
} else {
|
||||
return quickselect(arr, pivotPos + 1, high, k);
|
||||
}
|
||||
}
|
||||
// 理论上不会走到这里,除非 k 越界
|
||||
throw new IllegalArgumentException("k is out of bounds");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数组中第 k 大的元素(k 从 1 开始)
|
||||
*/
|
||||
public int findKthLargest(int[] nums, int k) {
|
||||
int n = nums.length;
|
||||
// 第 k 大对应第 (n - k) 小
|
||||
// 第 k 大就是第 (n - k) 小
|
||||
return quickselect(nums, 0, n - 1, n - k);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
260
科研/草稿.md
260
科研/草稿.md
@ -1,79 +1,103 @@
|
||||
### 收缩矩阵的逐次特征值提取方法
|
||||
|
||||
#### 1. 初始矩阵性质
|
||||
对于实对称矩阵 $A \in \mathbb{R}^{N \times N}$,当满足:
|
||||
- 非对角元素 $a_{ij}$ 独立同分布
|
||||
- 均值 $\mathbb{E}[a_{ij}] = \mu$
|
||||
- 方差 $\text{Var}(a_{ij}) = \sigma^2$
|
||||
- 对角元素 $a_{ii} = 0$
|
||||
|
||||
其最大特征值 $\lambda_1$ 服从高斯分布:
|
||||
### 定理2
|
||||
多智能体随机网络矩阵奇异值信号系统具有线性特征。
|
||||
|
||||
#### 证明
|
||||
根据定理1,奇异值序列$\sigma_{\tilde{\kappa}}(A_t)$服从高斯分布$\mathcal{N}(m_{\tilde{\kappa}}, 2\sigma_{\tilde{\kappa}}^2)$,其协方差结构满足:
|
||||
$$
|
||||
\mathbb{E}[\lambda_1] (N-1)\mu + \frac{\sigma^2}{\mu}, \quad \text{Var}(\lambda_1) = 2\sigma^2
|
||||
\gamma_{\tilde{\kappa}}(h) = 2\sigma_{\tilde{\kappa}}^2\delta_h^0
|
||||
$$
|
||||
|
||||
#### 2. 收缩操作定义
|
||||
通过秩一修正实现矩阵收缩:
|
||||
定义中心化变量:
|
||||
$$
|
||||
A^{(k+1)} = A^{(k)} - \lambda_k u_k u_k^T
|
||||
\tilde{\sigma}_t = \sigma_{\tilde{\kappa}}(A_t) - m_{\tilde{\kappa}}
|
||||
$$
|
||||
可表示为:
|
||||
$$
|
||||
\tilde{\sigma}_t = \sqrt{2}\sigma_{\tilde{\kappa}}\varepsilon_t, \quad \varepsilon_t \overset{i.i.d.}{\sim} \mathcal{N}(0,1)
|
||||
$$
|
||||
|
||||
#### 线性系统验证
|
||||
该系统为MA(0)过程,系统增益$h_0 = \sqrt{2}\sigma_{\tilde{\kappa}}$,满足:
|
||||
1. **齐次性**:
|
||||
$$a\tilde{\sigma}_t = h_0(a\varepsilon_t)$$
|
||||
2. **叠加性**:
|
||||
$$\tilde{\sigma}_t^{(1)} + \tilde{\sigma}_t^{(2)} = h_0(\varepsilon_t^{(1)} + \varepsilon_t^{(2)})$$
|
||||
|
||||
#### 结论
|
||||
奇异值序列的完整表示:
|
||||
$$
|
||||
\sigma_{\tilde{\kappa}}(A_t) = m_{\tilde{\kappa}} + h_0\varepsilon_t
|
||||
$$
|
||||
其中:
|
||||
- $\lambda_k$ 为当前矩阵 $A^{(k)}$ 的最大特征值
|
||||
- $u_k$ 为对应特征向量(单位范数)
|
||||
- 初始条件 $A^{(1)} = A$
|
||||
- $m_{\tilde{\kappa}}$为稳态偏置项
|
||||
- $h_0\varepsilon_t$为线性系统响应
|
||||
|
||||
#### 3. 特征值递推关系
|
||||
第 $k$ 大特征值可通过收缩矩阵提取:
|
||||
根据线性系统定义(需引用文献),同时满足齐次性与可加性即构成线性系统,故得证。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
### ② 定理2修订(线性系统特征)
|
||||
|
||||
#### 原MA(0)情形回顾
|
||||
|
||||
当$\gamma_k(h)=2\sigma_k^2\delta_h$时,
|
||||
$$
|
||||
\lambda_k(A) = \lambda_1(A^{(k)})
|
||||
\tilde{\sigma}_t=\sigma_k(A_t)-m_k=\sqrt{2}\sigma_k\varepsilon_t, \quad \varepsilon_t \overset{i.i.d.}{\sim} \mathcal{N}(0,1)
|
||||
$$
|
||||
|
||||
若收缩后矩阵 $A^{(k)}$ 保持:
|
||||
- 非对角元素均值 $\mu_k$
|
||||
- 方差 $\sigma_k^2$
|
||||
#### 新协方差结构下的表示
|
||||
|
||||
则特征值统计量满足:
|
||||
当$\gamma_k(h)=C_h$(允许$C_h\neq0$),根据Wiener-Kolmogorov表示定理:
|
||||
$$
|
||||
\begin{cases}
|
||||
\mathbb{E}[\lambda_k] = (N-k)\mu_k + \frac{\sigma_k^2}{\mu_k} \\
|
||||
\text{Var}(\lambda_k) = 2\sigma_k^2
|
||||
\end{cases}
|
||||
\tilde{\sigma}_t=\sum_{h=-\infty}^{+\infty} b_h w_{t-h} \tag{1}
|
||||
$$
|
||||
其中$\{b_h\}\in\ell^2$满足:
|
||||
$$
|
||||
\gamma_k(h)=\sum_{\ell=-\infty}^{+\infty} b_\ell b_{\ell+h} \tag{2}
|
||||
$$
|
||||
|
||||
#### 4. 实现步骤
|
||||
1. **初始化**:设 $A^{(1)} = A$,$k=1$
|
||||
2. **迭代过程**:
|
||||
```python
|
||||
while k <= K:
|
||||
# 计算当前最大特征对
|
||||
λ, u = eigsh(A^{(k)}, k=1)
|
||||
|
||||
# 记录统计量
|
||||
λ_sequence[k] = λ
|
||||
|
||||
# 执行收缩
|
||||
A^{(k+1)} = A^{(k)} - λ * u @ u.T
|
||||
|
||||
# 验证新矩阵性质
|
||||
μ_k = np.mean(A^{(k+1)}[off_diag])
|
||||
σ²_k = np.var(A^{(k+1)}[off_diag])
|
||||
|
||||
k += 1
|
||||
#### 线性系统验证
|
||||
|
||||
$\sigma_1$.
|
||||
设系统传递函数$H(z)=\sum_h b_h z^{-h}$:
|
||||
|
||||
1. **齐次性**
|
||||
$$
|
||||
a\tilde{\sigma}_t=a\sum_h b_h w_{t-h}=\sum_h b_h (a w_{t-h})=H(z)\{a w_t\}
|
||||
$$
|
||||
|
||||
2. **叠加性**
|
||||
$$
|
||||
\tilde{\sigma}_t^{(1)}+\tilde{\sigma}_t^{(2)}=\sum_h b_h(w_{t-h}^{(1)}+w_{t-h}^{(2)})=H(z)\{w_t^{(1)}+w_t^{(2)}\}
|
||||
$$
|
||||
|
||||
故$\{\sigma_k(A_t)\}$仍是LTI系统输出,但系统响应$\{b_h\}$需通过(2)式确定。
|
||||
|
||||
---
|
||||
|
||||
您说得对,在奇异值分解(SVD)中,通常用 **u** 和 **v** 来表示左右奇异向量。以下是修正后的Markdown格式表示:
|
||||
### 性质对比
|
||||
|
||||
对于随机网络矩阵 `A`,设奇异值从大到小依次为 `{\sigma _1},{\sigma _2}, \ldots ,{\sigma _n}`,对应的左、右奇异向量分别为 ${u}_1, {u}_2, \ldots, {u}_n$ 和 ${v}_1, {v}_2, \ldots,{v}_n$。
|
||||
|
||||
或者更紧凑地表示为:
|
||||
`A = \sum_{i=1}^n \sigma_i \mathbf{u}_i \mathbf{v}_i^\top`
|
||||
|
||||
需要其他数学符号表示或格式调整可以随时告诉我!
|
||||
| 性质 | $\gamma_k(h)=2\sigma_k^2\delta_h$ | $\gamma_k(h)=C_h$ |
|
||||
| -------- | --------------------------------- | -------------------------------- |
|
||||
| 宽平稳 | ✅ | ✅ |
|
||||
| 白噪声 | ✅ | ❌ |
|
||||
| 系统类型 | MA(0) | 通用LTI(可能MA($\infty$)) |
|
||||
| 谱密度 | $S(f)=2\sigma_k^2$ | $S(f)=\sum_h C_h e^{-j2\pi f h}$ |
|
||||
|
||||
|
||||
|
||||
@ -81,18 +105,126 @@ $\sigma_1$.
|
||||
|
||||
|
||||
|
||||
不必大动干戈,只要把“等号”换成“近似”等价写法,或显式加上误差项,就足够严谨。下面给出两种常见做法,你任选其一即可——
|
||||
### 随机网络稳态奇异值的平稳性证明
|
||||
|
||||
| 写法 | 建议格式 | 说明 |
|
||||
| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| **近似号写法** | E[σ1]≈(N−1)μ+v+σ2μ,Var[σ1]≈2σ2E[\sigma_1]\approx (N-1)\mu+v+\dfrac{\sigma^2}{\mu},\qquad \operatorname{Var}[\sigma_1]\approx 2\sigma^2 | 直接用 “≈” 表明这是 N→∞N\to\infty 的主导项;与前面“可在 O(1/N)O(1/\sqrt N) 范围内逼近高斯”完全呼应。 |
|
||||
| **误差项写法** | E[σ1]=(N−1)μ+v+σ2μ+O (1N),Var[σ1]=2σ2+O (1N)E[\sigma_1]=(N-1)\mu+v+\dfrac{\sigma^2}{\mu}+O\!\left(\tfrac{1}{N}\right),\qquad \operatorname{Var}[\sigma_1]=2\sigma^2+O\!\left(\tfrac{1}{N}\right) | 把小量显式写成 O(1/N)O(1/N)。这样保留等号,同时说明误差级别,更“硬核”一些。 |
|
||||
#### 1. 稳态奇异值分布特性
|
||||
|
||||
> **为什么推荐修改?**
|
||||
>
|
||||
> - 你的正文已经说“在 O(1/N)O(1/\sqrt N) 的范围内可被高斯分布逼近”,说明后续公式仅是渐近主项。直接用 “=” 容易让读者误以为 **完全等于** 主项。
|
||||
> - 只要在公式里加 “≈” 或 “+O(\cdot)” 就能避免歧义,而且和引用的 F & K 定理保持一致。
|
||||
当随机网络进入稳态后,其矩阵序列$\{A_t\}$的任意奇异值$\sigma_k(A_t)$服从高斯分布:
|
||||
$$
|
||||
\sigma_k(A_t) \sim \mathcal{N}(m_k, \gamma_k(0))
|
||||
$$
|
||||
其中参数满足:
|
||||
|
||||
其余内容(条件、符号、文字描述)都没问题,不必再改。
|
||||
- **均值**:$m_k = (N-1)\mu_k + v_k + \frac{\sigma_k^2}{\mu_k}$
|
||||
($N$为网络规模,$\mu_k,v_k,\sigma_k$为网络参数)
|
||||
- **方差**:$\gamma_k(0) = 2\sigma_k^2$
|
||||
|
||||
$\approx$
|
||||
#### 2. 宽平稳性验证
|
||||
|
||||
对任意时刻$t$:
|
||||
|
||||
1. **均值稳定性**:
|
||||
$$
|
||||
\mathbb{E}[\sigma_k(A_t)] = m_k \quad \text{(常数)}
|
||||
$$
|
||||
|
||||
2. **协方差结构**:
|
||||
|
||||
- 当$h=0$时:
|
||||
$$
|
||||
\text{Cov}(\sigma_k(A_t), \sigma_k(A_t)) = \gamma_k(0)
|
||||
$$
|
||||
|
||||
- 当$h \neq 0$时:
|
||||
$$
|
||||
\text{Cov}(\sigma_k(A_t), \sigma_k(A_{t+h})) = \gamma_k(h)=0
|
||||
$$
|
||||
(由稳态下矩阵的独立性保证)
|
||||
|
||||
#### 3. 结论
|
||||
|
||||
自协方差函数$\gamma_k(h)$仅依赖于时滞$h$,因此奇异值信号序列$\{\sigma_k(A_t)\}$满足宽平稳过程的定义。
|
||||
|
||||
---
|
||||
|
||||
**注**:本证明基于以下假设:
|
||||
|
||||
1. 网络规模$N$足够大,使得高斯逼近有效
|
||||
2. 稳态下矩阵序列$\{A_t\}$具有独立性
|
||||
|
||||
|
||||
|
||||
### 定理2
|
||||
多智能体随机网络矩阵奇异值信号系统具有线性特征。
|
||||
|
||||
#### 证明
|
||||
根据定理1,奇异值序列$\sigma_{\tilde{\kappa}}(A_t)$服从高斯分布$\mathcal{N}(m_{\tilde{\kappa}}, 2\sigma_{\tilde{\kappa}}^2)$,其协方差结构满足:
|
||||
$$
|
||||
\gamma_{\tilde{\kappa}}(h) = 2\sigma_{\tilde{\kappa}}^2\delta_h^0
|
||||
$$
|
||||
|
||||
定义中心化变量:
|
||||
$$
|
||||
\tilde{\sigma}_t = \sigma_{\tilde{\kappa}}(A_t) - m_{\tilde{\kappa}}
|
||||
$$
|
||||
可表示为:
|
||||
$$
|
||||
\tilde{\sigma}_t = \sqrt{2}\sigma_{\tilde{\kappa}}\varepsilon_t, \quad \varepsilon_t \overset{i.i.d.}{\sim} \mathcal{N}(0,1)
|
||||
$$
|
||||
|
||||
#### 线性系统验证
|
||||
该系统为MA(0)过程,系统增益$h_0 = \sqrt{2}\sigma_{\tilde{\kappa}}$,满足:
|
||||
1. **齐次性**:
|
||||
$$a\tilde{\sigma}_t = h_0(a\varepsilon_t)$$
|
||||
2. **叠加性**:
|
||||
$$\tilde{\sigma}_t^{(1)} + \tilde{\sigma}_t^{(2)} = h_0(\varepsilon_t^{(1)} + \varepsilon_t^{(2)})$$
|
||||
|
||||
#### 结论
|
||||
奇异值序列的完整表示:
|
||||
$$
|
||||
\sigma_{\tilde{\kappa}}(A_t) = m_{\tilde{\kappa}} + h_0\varepsilon_t
|
||||
$$
|
||||
其中:
|
||||
- $m_{\tilde{\kappa}}$为稳态偏置项
|
||||
- $h_0\varepsilon_t$为线性系统响应
|
||||
|
||||
根据线性系统定义(需引用文献),同时满足齐次性与可加性即构成线性系统,故得证。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
……由协方差结构 γ_k(h)=2σ_k^2δ_h^0 可知,中心化变量
|
||||
$$
|
||||
\tilde σ_t = σ_k(A_t)-m_k,\qquad
|
||||
\mathbb E[\tilde σ_t]=0,\; \mathrm{Cov}(\tilde σ_t,\tilde σ_{t+h})=
|
||||
2σ_k^{2}\delta_h^{0}.
|
||||
$$
|
||||
|
||||
**根据 Wold 分解定理①**,任何零均值、纯非确定性的宽平稳过程都可以唯一表示为
|
||||
|
||||
$$
|
||||
\tilde σ_t=\sum_{j=0}^{\infty}ψ_j\;ε_{t-j},
|
||||
\qquad ε_t\stackrel{i.i.d.}{\sim}\mathcal N(0,1),\
|
||||
\sum_{j=0}^{\infty}|ψ_j|^2<\infty.
|
||||
$$
|
||||
|
||||
而在本情形下 $\gamma_k(h)=0\,(h\neq 0)$,因此
|
||||
$$
|
||||
ψ_0=\sqrt{2}\,σ_k,\quad ψ_j=0\;(j\ge 1),
|
||||
$$
|
||||
退化为一个 **MA(0)** 过程:
|
||||
$$
|
||||
\boxed{\;\tilde σ_t=\sqrt{2}\,σ_k\,ε_t\;}
|
||||
$$
|
||||
……
|
||||
|
10
论文/高飞论文.md
10
论文/高飞论文.md
@ -58,6 +58,10 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 证明主特征值序列平稳
|
||||
|
||||
#### **(1) 均值恒定性的推导**
|
||||
@ -530,3 +534,9 @@ LSTM 的隐藏状态 $h_i \in \mathbb{R}^{d'' \times 1}$(其中 $d''$ 为 LSTM
|
||||
|
||||
该论文可能有点问题,每个节点只能预测自身未来位置,无法获取全局位置信息。如果先LSTM后GCN可能可以!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
242
项目/拼团交易系统.md
242
项目/拼团交易系统.md
@ -14,7 +14,11 @@
|
||||
|
||||
用户锁单-》支付宝付款-》成功后return_url设置了用户支付完毕后跳转回哪个地址是给前端用户看的; alipay_notify_url设置了支付成功后alipay调用你的后端哪个接口。
|
||||
|
||||
这里有小商城和拼团系统,notify_url指拼团系统中拼团达到指定人数后,通知小商城的地址,这里用rabbitmq。然后小商场将订单中相应拼团的status都设置为deal_done。然后小商场内部也再发一个'支付成功'消息,主要用于通知这些拼团对应的订单进入下一环节:发货(感觉'支付成功'取名不够直观)。
|
||||
这里有小商城和拼团系统,notify_url指拼团系统中拼团达到指定人数后,通知小商城的HTTP地址,但是如果notify_type为MQ,则notify_url为空,并且notify_mq非空,指明是拼团成功通知还是用户退单通知。
|
||||
|
||||
若为拼团成功通知,小商场将订单中相应拼团的status都设置为deal_done,然后小商场内部也再发一个'支付成功'消息,主要用于通知这些拼团对应的订单进入下一环节:发货(感觉'支付成功'取名不够直观)。
|
||||
|
||||
若为用户退单通知,小商场需处理退款业务。
|
||||
|
||||
|
||||
|
||||
@ -378,45 +382,130 @@ EndNode.apply() → 组装结果并返回 TrialBalanceEntity
|
||||
|
||||
<img src="https://pic.bitday.top/i/2025/07/25/hgggjo-0.png" alt="image-20250725105608390" style="zoom:67%;" />
|
||||
|
||||
逆向的流程,要分析用户是在哪个流程节点下进行中断行为。包括3个场景;
|
||||
逆向的流程,要分析用户是在哪个流程节点下进行退单行为。包括3个场景;
|
||||
|
||||
**已锁单、未支付**
|
||||
**已锁单、未支付**:redis恢复量+1,mysql中锁单量-1
|
||||
|
||||
- **用户行为**:完成锁单后未发起支付。
|
||||
- **结果**:订单超时自动关单。
|
||||
- 补偿
|
||||
- 若用户在临界时刻支付,则需执行“逆向退款”流程——退还支付金额并告知“优惠已过期,请重新参与”。
|
||||
- 否则该订单自动失效,释放拼团名额给后续用户。
|
||||
**已锁单、已支付,但拼团未成团**:redis恢复量+1,mysql中锁单量、完成量-1,退款
|
||||
|
||||
**已锁单、已支付,但拼团未成团**
|
||||
|
||||
- **用户行为**:完成支付,组团人数不足暂未成团。
|
||||
|
||||
- 补偿策略
|
||||
|
||||
(可配置优先级):
|
||||
|
||||
1. **先退拼团,再退款,**
|
||||
2. **先退款,再退拼团**
|
||||
|
||||
- 具体执行哪种方式,可由拼团活动策略决定——“优先保障个人”或“优先保障成团”。
|
||||
|
||||
**已锁单、已支付,且拼团已成团**
|
||||
|
||||
- **用户行为**:支付成功,且组团人数已凑齐。
|
||||
- 补偿流程
|
||||
- 先退还用户支付金额;
|
||||
- 再撤销对应的拼团完成量。
|
||||
- **注意**:已成团订单视为“已完成含退单”,仍然成团、不再开放新用户参与,确保团队成团状态一致。
|
||||
**已锁单、已支付,且拼团已成团**:redis恢复量无需+1,因为成团之后不开放给别人;mysql中锁单量、完成量-1,退款,拼团设置为'已完成含退单'状态,但拼团中所有人都退单,更新为失败!
|
||||
|
||||
|
||||
|
||||
### 策略模板应用
|
||||
### 核心流程说明
|
||||
|
||||
根据订单状态和拼团状态动态选择退单策略。
|
||||
#### 阶段一:退单操作流程
|
||||
1. 客户**主动提交**退单请求
|
||||
|
||||
2. 通过责任链模式处理:数据加载Node(查询订单) → 重复检查Node(防止重复退单) → 策略执行Node
|
||||
|
||||
3. 策略选择
|
||||
|
||||
根据订单状态和拼团状态选择对应退单策略(三种之一)
|
||||
|
||||
4. 执行退单
|
||||
|
||||
更新**数据库**操作(锁单量、完成量、拼团状态、订单状态...)
|
||||
|
||||
5. 消息通知 + 任务补偿
|
||||
|
||||
发送MQ退单消息通知(未支付退单、已支付未成团...三种消息 notify_category)
|
||||
|
||||
将消息写入notify_task表,定时任务扫描未成功处理的消息,以做补偿兜底。
|
||||
|
||||
#### 阶段二:库存恢复流程
|
||||
6. 消息监听
|
||||
|
||||
MQ**监听器接收**退单成功消息
|
||||
|
||||
7. 服务调用
|
||||
|
||||
调用恢复库存服务
|
||||
|
||||
8. 策略选择
|
||||
|
||||
根据退单类型选择对应策略(已成团的无需恢复了,反正新用户也无法再参与该拼团)
|
||||
|
||||
9. 库存恢复
|
||||
|
||||
执行Redis库存恢复操作(带分布式锁保护)
|
||||
|
||||
---
|
||||
|
||||
### 设计模式应用
|
||||
|
||||
1. **责任链模式**
|
||||
|
||||
`TradeRefundRuleFilterFactory` 构建的过滤链:
|
||||
`DataNodeFilter` → `UniqueRefundNodeFilter` → `RefundOrderNodeFilter`
|
||||
|
||||
2. **策略模式**
|
||||
|
||||
- 策略接口:`RefundOrderStrategy`
|
||||
|
||||
- 实现策略:
|
||||
|
||||
`Unpaid2RefundStrategy`(未付款退单的流程)
|
||||
`Paid2RefundStrategy`(已付款退单)
|
||||
`PaidTeam2RefundStrategy`(已成团退单)
|
||||
|
||||
3. **工厂模式**
|
||||
|
||||
`TradeRefundRuleFilterFactory` 负责组装责任链
|
||||
|
||||
4. **模板方法模式**
|
||||
|
||||
`AbstractRefundOrderStrategy` 提供:
|
||||
|
||||
- 公共方法封装 (发送退单MQ消息、库存恢复redis)
|
||||
- 依赖注入支持
|
||||
|
||||
|
||||
|
||||
### 退单触发入口
|
||||
|
||||
1)用户主动退单
|
||||
|
||||
2)定时任务,定时任务扫描锁单但未结算的订单,若支付时间超过设定值,对这笔订单执行退单操作。
|
||||
|
||||
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph mall["小型支付商城"]
|
||||
style mall fill:#ffffff,stroke:#333,stroke-width:2
|
||||
A[AliPayController<br/>发起退单申请]:::blue
|
||||
C[订单状态扭转<br/>退单中]:::grey
|
||||
E[RefundSuccessTopicListener<br/>接收MQ消息<br/>执行退款和订单状态变更]:::green
|
||||
end
|
||||
|
||||
subgraph pdd["拼团系统"]
|
||||
style pdd fill:#ffffff,stroke:#333,stroke-width:2
|
||||
B[MarketTradeController<br/>接收退单申请]:::yellow
|
||||
D[TradeRefundOrderService<br/>退单策略处理]:::red
|
||||
F[TradeRepository<br/>发送MQ消息]:::purple
|
||||
G([MQ消息队列<br/>退单成功消息]):::orange
|
||||
H[RefundSuccessTopicListener<br/>接收MQ消息<br/>恢复库存]:::green
|
||||
end
|
||||
|
||||
A -- "1. 发起退单请求" --> B
|
||||
B -- "2. 处理退单" --> D
|
||||
D -- "3. 发送MQ消息" --> F
|
||||
F -- "4. 发布消息 (异步+本地消息表补偿)" --> G
|
||||
F -- "5. 返回结果" --> C
|
||||
G -- "6. 消费消息 (恢复库存)" --> H
|
||||
G -. "7. 消费消息 (执行退款)" .-> E
|
||||
|
||||
classDef blue fill:#dbe9ff,stroke:#6fa1ff,stroke-width:1;
|
||||
classDef grey fill:#e5e5e5,stroke:#9e9e9e,stroke-width:1;
|
||||
classDef green fill:#d6f2d6,stroke:#76b076,stroke-width:1;
|
||||
classDef yellow fill:#fef3cd,stroke:#f5c700,stroke-width:1;
|
||||
classDef red fill:#f8d7da,stroke:#e55353,stroke-width:1;
|
||||
classDef purple fill:#e4dbf9,stroke:#9370db,stroke-width:1;
|
||||
classDef orange fill:#ffecca,stroke:#ffa500,stroke-width:1;
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 收获
|
||||
@ -459,6 +548,60 @@ public class PayActivityEntity {
|
||||
|
||||
|
||||
|
||||
### 单例模式
|
||||
|
||||
**懒汉**
|
||||
|
||||
```java
|
||||
public class LazySingleton {
|
||||
private static volatile LazySingleton instance;
|
||||
|
||||
private LazySingleton() {}
|
||||
|
||||
public static LazySingleton getInstance() {
|
||||
if (instance == null) { // 第一次检查
|
||||
synchronized (LazySingleton.class) {
|
||||
if (instance == null) { // 第二次检查
|
||||
instance = new LazySingleton();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**饿汉**
|
||||
|
||||
```java
|
||||
public class EagerSingleton {
|
||||
// 类加载时就初始化实例
|
||||
private static final EagerSingleton INSTANCE = new EagerSingleton();
|
||||
|
||||
// 私有构造函数
|
||||
private EagerSingleton() {
|
||||
// 防止反射创建实例
|
||||
if (INSTANCE != null) {
|
||||
throw new IllegalStateException("Singleton already initialized");
|
||||
}
|
||||
}
|
||||
|
||||
// 全局访问点
|
||||
public static EagerSingleton getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
// 防止反序列化破坏单例
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 模板方法
|
||||
|
||||
**核心思想**:
|
||||
@ -770,7 +913,7 @@ while 循环:
|
||||
|
||||
### 规则树流程
|
||||
|
||||
!
|
||||

|
||||
|
||||
**整体分层思路**
|
||||
|
||||
@ -1562,6 +1705,8 @@ public boolean tryOccupy(String counterKey,
|
||||
}
|
||||
```
|
||||
|
||||
本项目有两层防护:第一层是下单前的人数/库存校验,比较基础,由于前端可能更新不及时,显示还差X人拼团,但用户点进去时已达人数的情况。第二层是真正的并发保证,即**Redis 原子操作** + **后置校验/补偿**。
|
||||
|
||||
|
||||
|
||||
### `Supplier<T>`
|
||||
@ -1828,3 +1973,38 @@ output {
|
||||
|
||||
|
||||
|
||||
### RPC微服务调用
|
||||
|
||||
1.父Pom统一版本
|
||||
|
||||
```xml
|
||||
<!-- 统一锁版本,避免不同模块写不同小版本 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-bom</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2.pay-mall-infrustruct(Consumer)group-buying-sys-trigger (Provider)引入依赖
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<!-- Dubbo 核心 + Spring Boot 自动装配 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Nacos 注册中心扩展 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-nacos</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
```
|
||||
|
||||
****
|
||||
|
101
项目/智能协同云图库.md
101
项目/智能协同云图库.md
@ -129,6 +129,103 @@ AI扩图
|
||||
|
||||
4、一些小问题的优化:比如 WebSocket 连接建立之后,如果用户退出了登录,这时 WebSocket 的连接是没有断开的。不过影响并不大,可以思考下怎么处理。
|
||||
|
||||
## 踩坑
|
||||
|
||||
#### **精度损失和日期格式转换问题**
|
||||
|
||||
##### **前端 → 后端**
|
||||
|
||||
**日期**
|
||||
|
||||
前端把日期格式化成后端期待的纯日期**字符串**,例如 `"2025-08-14"`,后端 DTO 用 `LocalDate` 接收(配合 `@JsonFormat(pattern="yyyy-MM-dd")`),Jackson 反序列化成 `LocalDate`。
|
||||
|
||||
**精度:**
|
||||
|
||||
JavaScript 的 `number` 类型只能安全地表示到 2^53−1(约 9×10^15)的整数,超过这个范围就会丢失精度,用 `number` 传给后端时末尾只能补0;
|
||||
|
||||
解决办法:前端 ID 当做字符串传给后端。
|
||||
|
||||
Spring MVC 会自动调用 `Long.parseLong("1951619197178556418")` 并赋值给你方法签名里的 `long id`(即还是写作long来接收,不变)
|
||||
|
||||
|
||||
|
||||
##### **后端 → 前端**
|
||||
|
||||
**日期:**
|
||||
|
||||
后端用 `LocalDate` / `LocalDateTime` 之类的 Java 8 类型,经过 Jackson 序列化为指定格式的字符串(比如 `"yyyy-MM-dd"` / `"yyyy-MM-dd HH:mm:ss"`)供前端消费,避免时间戳或默认格式的不一致。
|
||||
|
||||
**精度:**
|
||||
|
||||
Java 的 `long` 可能超过 JavaScript `number` 的安全范围(2^53−1),直接以数字输出会丢失精度。必须把 `long`/`Long` 序列化成**字符串**(例如 ID 输出为 `"1951648800160399362"`),前端拿到字符串再展示。
|
||||
|
||||
|
||||
|
||||
对 Jackson 用作 Spring 的 HTTP 消息转换器的 `ObjectMapper` 进行配置(日期格式、Java 8 时间支持、Long 转字符串等)示例代码:
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class JacksonConfig {
|
||||
|
||||
private static final String DATE_FORMAT = "yyyy-MM-dd";
|
||||
private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
private static final String TIME_FORMAT = "HH:mm:ss";
|
||||
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
|
||||
return builder -> {
|
||||
builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
builder.simpleDateFormat(DATETIME_FORMAT);
|
||||
builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
|
||||
JavaTimeModule javaTime = new JavaTimeModule();
|
||||
javaTime.addSerializer(LocalDateTime.class,
|
||||
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATETIME_FORMAT)));
|
||||
javaTime.addSerializer(LocalDate.class,
|
||||
new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
|
||||
javaTime.addSerializer(LocalTime.class,
|
||||
new LocalTimeSerializer(DateTimeFormatter.ofPattern(TIME_FORMAT)));
|
||||
javaTime.addDeserializer(LocalDateTime.class,
|
||||
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATETIME_FORMAT)));
|
||||
javaTime.addDeserializer(LocalDate.class,
|
||||
new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
|
||||
javaTime.addDeserializer(LocalTime.class,
|
||||
new LocalTimeDeserializer(DateTimeFormatter.ofPattern(TIME_FORMAT)));
|
||||
|
||||
SimpleModule longToString = new SimpleModule();
|
||||
longToString.addSerializer(Long.class, ToStringSerializer.instance);
|
||||
longToString.addSerializer(Long.TYPE, ToStringSerializer.instance);
|
||||
|
||||
builder.modules(javaTime, longToString);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**数据库密码加密**
|
||||
|
||||
加密存储确保即使数据库泄露,攻击者也不能轻易获取用户原始密码。
|
||||
|
||||
spring security中提供了一个加密类**BCryptPasswordEncoder**。
|
||||
|
||||
它采用[哈希算法](https://so.csdn.net/so/search?q=哈希算法&spm=1001.2101.3001.7020) SHA-256 +随机盐+密钥对密码进行加密。加密算法是一种**可逆**的算法,而哈希算法是一种**不可逆**的算法。
|
||||
|
||||
因为有随机盐的存在,所以**相同的明文密码**经过加密后的密码是**不一样**的,盐在加密的密码中是有记录的,所以需要对比的时候,springSecurity是可以从中获取到盐的
|
||||
|
||||
验证密码 **matches**
|
||||
|
||||
```java
|
||||
// 使用 matches 方法来对比明文密码和存储的哈希密码
|
||||
boolean judge= passwordEncoder.matches(rawPassword, user.getPassword());
|
||||
```
|
||||
|
||||
注意,`matches`的第一个参数**必须** 是 “**原始明文**”,第二个参数 **必须** 是 “**已经加密过的密文**”!!!**顺序不能反!!!**
|
||||
|
||||
|
||||
|
||||
## 收获
|
||||
@ -453,7 +550,9 @@ public String info() {
|
||||
}
|
||||
```
|
||||
|
||||
#### 多账号体系
|
||||
|
||||
|
||||
#### passwordEncoder多账号体系
|
||||
|
||||
若项目中存在两套权限校验体系。一套是 user 表的,分为普通用户和管理员;另一套是对团队空间的权限进行校验。
|
||||
|
||||
|
10
项目/苍穹外卖.md
10
项目/苍穹外卖.md
@ -834,15 +834,15 @@ net start winnat
|
||||
|
||||
直接部署开发完毕的前端代码,准备:
|
||||
|
||||
0.创建docker网络:`docker network create sky-net`
|
||||
0)创建docker网络:`docker network create sky-net`
|
||||
|
||||
1.静态资源html文件夹(npm run build 打包源码获得)
|
||||
1)静态资源html文件夹(npm run build 打包源码获得)
|
||||
|
||||
2.nginx.conf
|
||||
2)nginx.conf
|
||||
|
||||

|
||||
|
||||
注意把nginx.conf中的server改为Docker 容器(或服务)在**同一网络中**的主机名,如
|
||||
注意把nginx.conf中的server改为Docker 容器(或服务)在**同一网络中**的服务名,如
|
||||
|
||||
```nginx
|
||||
upstream webservers {
|
||||
@ -852,7 +852,7 @@ upstream webservers {
|
||||
|
||||
因为同一个网络下的服务名会自动注册DNS,进行地址解析!
|
||||
|
||||
3.docker-compose文件
|
||||
3)docker-compose文件
|
||||
|
||||
```yml
|
||||
version: "3.8"
|
||||
|
Loading…
x
Reference in New Issue
Block a user