Compare commits
3 Commits
180b8f09f3
...
1b95f4a6c6
| Author | SHA1 | Date |
|---|---|---|
|
|
1b95f4a6c6 | |
|
|
ee8c304284 | |
|
|
85819798ca |
|
|
@ -10,4 +10,5 @@ rebel.xml
|
||||||
## front
|
## front
|
||||||
**/*.lock
|
**/*.lock
|
||||||
|
|
||||||
**/*.exe
|
**/*.exe
|
||||||
|
**/*.exe***
|
||||||
Binary file not shown.
|
|
@ -1,17 +1,48 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IDGenerator 简单的 ID 生成器(类似 Snowflake)
|
/**
|
||||||
|
分布式/多实例运行(重要)
|
||||||
|
如果你有多个 Pod 或服务器,必须在程序启动时给它们分配不同的 ID,否则还是会冲突
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 获取当前机器的编号,比如从配置文件或环境变量读取
|
||||||
|
// 假设这是第 2 号机器
|
||||||
|
myMachineID := int64(2)
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
err := common.InitGenerator(myMachineID)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 之后随处调用
|
||||||
|
println(common.GenerateStringID())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 定义常量 (标准雪花算法配置)
|
||||||
|
const (
|
||||||
|
epoch = int64(1704067200000) // 起始时间戳 2024-01-01
|
||||||
|
workerBits = uint(10) // 机器ID位数
|
||||||
|
sequenceBits = uint(12) // 序列号位数
|
||||||
|
maxWorker = -1 ^ (-1 << workerBits)
|
||||||
|
maxSequence = -1 ^ (-1 << sequenceBits)
|
||||||
|
workerShift = sequenceBits
|
||||||
|
timestampShift = sequenceBits + workerBits
|
||||||
|
)
|
||||||
|
|
||||||
type IDGenerator struct {
|
type IDGenerator struct {
|
||||||
mu sync.RWMutex
|
mu sync.Mutex
|
||||||
lastTime int64
|
lastTime int64
|
||||||
sequence int64
|
workerID int64
|
||||||
machineID int64
|
sequence int64
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -19,56 +50,84 @@ var (
|
||||||
once sync.Once
|
once sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetIDGenerator 获取默认生成器单例
|
// InitGenerator 初始化单例生成器
|
||||||
func GetIDGenerator() *IDGenerator {
|
// 修复:校验逻辑移到 once.Do 外部,防止校验失败消耗掉 once 的执行机会
|
||||||
|
func InitGenerator(workerID int64) error {
|
||||||
|
// 1. 先校验,如果失败直接返回,不要触碰 once
|
||||||
|
if workerID < 0 || workerID > int64(maxWorker) {
|
||||||
|
return errors.New("worker ID excess of limit (0-1023)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 执行初始化
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
defaultGenerator = &IDGenerator{
|
defaultGenerator = &IDGenerator{
|
||||||
machineID: 1,
|
workerID: workerID,
|
||||||
|
lastTime: 0,
|
||||||
|
sequence: 0,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return defaultGenerator
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lazy initialize on first access
|
// getInstance 获取单例
|
||||||
func getInstance() *IDGenerator {
|
func getInstance() *IDGenerator {
|
||||||
|
// 双重检查,虽然 once.Do 是线程安全的,但如果 InitGenerator 没被调用过,
|
||||||
|
// 我们需要确保这里能兜底初始化
|
||||||
if defaultGenerator == nil {
|
if defaultGenerator == nil {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
defaultGenerator = &IDGenerator{
|
defaultGenerator = &IDGenerator{
|
||||||
machineID: 1,
|
workerID: 1, // 默认机器ID,防止未初始化导致 panic
|
||||||
|
lastTime: 0,
|
||||||
|
sequence: 0,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 【关键修复】如果经过上面的逻辑 defaultGenerator 还是 nil
|
||||||
|
// (这种情况极少见,除非 InitGenerator 曾经被错误调用且没有赋值)
|
||||||
|
// 强制创建一个临时的或抛出 panic,避免空指针崩溃
|
||||||
|
if defaultGenerator == nil {
|
||||||
|
// 最后的兜底,防止崩溃
|
||||||
|
return &IDGenerator{workerID: 1}
|
||||||
|
}
|
||||||
|
|
||||||
return defaultGenerator
|
return defaultGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateStringID 全局辅助函数:生成 string 类型 ID
|
// GenerateLongID 全局辅助函数
|
||||||
func GenerateStringID() string {
|
|
||||||
gen := getInstance()
|
|
||||||
if gen == nil {
|
|
||||||
// Fallback: create new instance if singleton fails
|
|
||||||
gen = &IDGenerator{machineID: 1}
|
|
||||||
}
|
|
||||||
return gen.NextIDStr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateLongID 全局辅助函数:生成 long 类型 ID
|
|
||||||
func GenerateLongID() int64 {
|
func GenerateLongID() int64 {
|
||||||
gen := getInstance()
|
return getInstance().NextID()
|
||||||
if gen == nil {
|
|
||||||
gen = &IDGenerator{machineID: 1}
|
|
||||||
}
|
|
||||||
return gen.NextID()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextID 生成下一个 64 位整数 ID
|
// GenerateStringID 全局辅助函数
|
||||||
|
func GenerateStringID() string {
|
||||||
|
return strconv.FormatInt(getInstance().NextID(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextID 生成下一个 ID
|
||||||
func (g *IDGenerator) NextID() int64 {
|
func (g *IDGenerator) NextID() int64 {
|
||||||
|
// 防御性编程:防止 g 为 nil
|
||||||
|
if g == nil {
|
||||||
|
// 如果实例是 nil,尝试获取默认实例
|
||||||
|
if defaultGenerator != nil {
|
||||||
|
g = defaultGenerator
|
||||||
|
} else {
|
||||||
|
// 极端情况,创建一个临时对象(虽然锁不住全局,但能防崩)
|
||||||
|
g = &IDGenerator{workerID: 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g.mu.Lock()
|
g.mu.Lock()
|
||||||
defer g.mu.Unlock()
|
defer g.mu.Unlock()
|
||||||
|
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
|
|
||||||
|
if now < g.lastTime {
|
||||||
|
now = g.lastTime
|
||||||
|
}
|
||||||
|
|
||||||
if now == g.lastTime {
|
if now == g.lastTime {
|
||||||
g.sequence = (g.sequence + 1) & 4095
|
g.sequence = (g.sequence + 1) & int64(maxSequence)
|
||||||
if g.sequence == 0 {
|
if g.sequence == 0 {
|
||||||
for now <= g.lastTime {
|
for now <= g.lastTime {
|
||||||
now = time.Now().UnixMilli()
|
now = time.Now().UnixMilli()
|
||||||
|
|
@ -79,11 +138,6 @@ func (g *IDGenerator) NextID() int64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
g.lastTime = now
|
g.lastTime = now
|
||||||
return now*10000 + g.sequence
|
|
||||||
}
|
|
||||||
|
|
||||||
// NextIDStr 生成字符串类型的 ID
|
return ((now - epoch) << timestampShift) | (g.workerID << workerShift) | g.sequence
|
||||||
func (g *IDGenerator) NextIDStr() string {
|
|
||||||
id := g.NextID()
|
|
||||||
return strconv.FormatInt(id, 10)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@ type UserMajorDTO struct {
|
||||||
// PrivateStudentScore float64 `json:"privateStudentScore"` // 学生折合分(私有)
|
// PrivateStudentScore float64 `json:"privateStudentScore"` // 学生折合分(私有)
|
||||||
// StudentConvertedScore float64 `json:"studentConvertedScore"` // 学生折合分(转换后)
|
// StudentConvertedScore float64 `json:"studentConvertedScore"` // 学生折合分(转换后)
|
||||||
// FirstLevelDiscipline string `json:"firstLevelDiscipline"` // 一级学科 (需确认来源)
|
// FirstLevelDiscipline string `json:"firstLevelDiscipline"` // 一级学科 (需确认来源)
|
||||||
|
|
||||||
|
Province string `json:"province"` // 省份
|
||||||
|
SchoolNature string `json:"schoolNature"` // 院校性质
|
||||||
|
InstitutionType string `json:"institutionType"` // 院校类型
|
||||||
}
|
}
|
||||||
|
|
||||||
// SchoolMajorDTO 院校专业查询结果 DTO
|
// SchoolMajorDTO 院校专业查询结果 DTO
|
||||||
|
|
|
||||||
|
|
@ -125,8 +125,8 @@ func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery)
|
||||||
cm.limitation,
|
cm.limitation,
|
||||||
cm.other_score_limitation,
|
cm.other_score_limitation,
|
||||||
s.province as province,
|
s.province as province,
|
||||||
s.school_nature as schoolNature,
|
s.school_nature,
|
||||||
s.institution_type as institutionType
|
s.institution_type
|
||||||
FROM %s cm
|
FROM %s cm
|
||||||
LEFT JOIN yx_school_child sc ON sc.school_code = cm.school_code
|
LEFT JOIN yx_school_child sc ON sc.school_code = cm.school_code
|
||||||
LEFT JOIN yx_school_research_teaching srt ON srt.school_id = sc.school_id
|
LEFT JOIN yx_school_research_teaching srt ON srt.school_id = sc.school_id
|
||||||
|
|
@ -146,6 +146,7 @@ func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery)
|
||||||
mainSQL += " AND (cm.enroll_probability >= 93)"
|
mainSQL += " AND (cm.enroll_probability >= 93)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainSQL += " ORDER BY cm.enroll_probability DESC"
|
||||||
// 6. 分页参数合法性校验
|
// 6. 分页参数合法性校验
|
||||||
page := query.Page
|
page := query.Page
|
||||||
size := query.Size
|
size := query.Size
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue