springbootAI 1.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spring/__init__.py +66 -0
- spring/ai/__init__.py +78 -0
- spring/ai/advisors.py +139 -0
- spring/ai/annotations.py +74 -0
- spring/ai/autoconfig.py +481 -0
- spring/ai/core.py +391 -0
- spring/ai/etl.py +188 -0
- spring/ai/memory.py +109 -0
- spring/ai/observability.py +129 -0
- spring/ai/providers.py +789 -0
- spring/ai/resilience.py +258 -0
- spring/ai/tools.py +106 -0
- spring/ai/vectorstore.py +303 -0
- spring/annotations/__init__.py +188 -0
- spring/annotations/cache.py +126 -0
- spring/annotations/cloud.py +207 -0
- spring/annotations/conditional.py +272 -0
- spring/annotations/core.py +864 -0
- spring/annotations/messaging.py +107 -0
- spring/aop/__init__.py +4 -0
- spring/aop/cloud_aop.py +404 -0
- spring/aop/comprehensive_aop.py +1015 -0
- spring/aop/method_interceptor.py +19 -0
- spring/aop/proxy_factory.py +55 -0
- spring/cloud/__init__.py +76 -0
- spring/cloud/discovery.py +364 -0
- spring/cloud/feign.py +469 -0
- spring/cloud/gateway.py +452 -0
- spring/cloud/load_balancer.py +149 -0
- spring/cloud/seata.py +557 -0
- spring/cloud/sentinel.py +525 -0
- spring/cloud/tracer.py +337 -0
- spring/config/__init__.py +21 -0
- spring/config/binding.py +206 -0
- spring/config/config_loader.py +405 -0
- spring/context/__init__.py +13 -0
- spring/context/application_context.py +589 -0
- spring/context/bean_definition.py +70 -0
- spring/context/bean_factory.py +1052 -0
- spring/context/registry.py +58 -0
- spring/context/scanner.py +106 -0
- spring/core/__init__.py +3 -0
- spring/core/graceful_shutdown.py +196 -0
- spring/core/typing_utils.py +50 -0
- spring/csv/__init__.py +52 -0
- spring/csv/annotations.py +402 -0
- spring/csv/converters.py +69 -0
- spring/csv/easy_csv.py +95 -0
- spring/csv/exceptions.py +27 -0
- spring/csv/reader.py +195 -0
- spring/csv/writer.py +155 -0
- spring/data/__init__.py +54 -0
- spring/data/page.py +181 -0
- spring/data/repository.py +274 -0
- spring/data/specification.py +228 -0
- spring/datasource/__init__.py +66 -0
- spring/datasource/annotations.py +133 -0
- spring/datasource/context.py +69 -0
- spring/datasource/dynamic.py +148 -0
- spring/event/__init__.py +7 -0
- spring/event/publisher.py +69 -0
- spring/excel/__init__.py +51 -0
- spring/excel/annotations.py +405 -0
- spring/excel/converters.py +231 -0
- spring/excel/easy_excel.py +94 -0
- spring/excel/exceptions.py +31 -0
- spring/excel/reader.py +254 -0
- spring/excel/style.py +95 -0
- spring/excel/writer.py +197 -0
- spring/i18n/__init__.py +97 -0
- spring/i18n/accessor.py +94 -0
- spring/i18n/auto_config.py +177 -0
- spring/i18n/holder.py +106 -0
- spring/i18n/locale.py +152 -0
- spring/i18n/locale_resolver.py +367 -0
- spring/i18n/message_source.py +250 -0
- spring/i18n/middleware.py +79 -0
- spring/i18n/properties.py +168 -0
- spring/i18n/sources.py +255 -0
- spring/logging/__init__.py +1 -0
- spring/logging/loguru_logger.py +228 -0
- spring/main.py +378 -0
- spring/messaging/__init__.py +1 -0
- spring/messaging/rabbitmq.py +302 -0
- spring/monitoring/__init__.py +1 -0
- spring/monitoring/prometheus.py +199 -0
- spring/orm/__init__.py +258 -0
- spring/orm/database.py +222 -0
- spring/orm/ddl_auto.py +1217 -0
- spring/orm/migration.py +419 -0
- spring/orm/mybatis_integration.py +400 -0
- spring/orm/pymybatis/__init__.py +86 -0
- spring/orm/pymybatis/annotations/__init__.py +30 -0
- spring/orm/pymybatis/annotations/annotations.py +332 -0
- spring/orm/pymybatis/cache/__init__.py +47 -0
- spring/orm/pymybatis/cache/cache.py +371 -0
- spring/orm/pymybatis/cache/redis_cache.py +434 -0
- spring/orm/pymybatis/circuit_breaker/__init__.py +21 -0
- spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +424 -0
- spring/orm/pymybatis/configuration.py +525 -0
- spring/orm/pymybatis/core/__init__.py +10 -0
- spring/orm/pymybatis/core/sql_session.py +1382 -0
- spring/orm/pymybatis/core/sql_session_factory.py +76 -0
- spring/orm/pymybatis/dialect/__init__.py +9 -0
- spring/orm/pymybatis/dialect/dialect.py +445 -0
- spring/orm/pymybatis/dynamic_sql/__init__.py +9 -0
- spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +900 -0
- spring/orm/pymybatis/interceptor/__init__.py +31 -0
- spring/orm/pymybatis/interceptor/interceptor.py +427 -0
- spring/orm/pymybatis/mapper/__init__.py +9 -0
- spring/orm/pymybatis/mapper/mapper.py +540 -0
- spring/orm/pymybatis/metrics/__init__.py +41 -0
- spring/orm/pymybatis/metrics/metrics.py +595 -0
- spring/orm/pymybatis/pool/__init__.py +9 -0
- spring/orm/pymybatis/pool/connection_pool.py +711 -0
- spring/orm/pymybatis/security/__init__.py +19 -0
- spring/orm/pymybatis/security/access_control.py +415 -0
- spring/orm/pymybatis/security/password_encoder.py +293 -0
- spring/orm/pymybatis/security/sensitive_data_masker.py +326 -0
- spring/orm/pymybatis/security/sql_injection_detector.py +675 -0
- spring/orm/pymybatis/transaction/__init__.py +9 -0
- spring/orm/pymybatis/transaction/transaction.py +288 -0
- spring/orm/pymybatis/type_handler/__init__.py +37 -0
- spring/orm/pymybatis/type_handler/type_handler.py +473 -0
- spring/orm/pymybatis/version.py +9 -0
- spring/orm/pymybatis/xml_parser/__init__.py +9 -0
- spring/orm/pymybatis/xml_parser/xml_parser.py +761 -0
- spring/retry/__init__.py +12 -0
- spring/retry/retry_annotations.py +71 -0
- spring/retry/retry_decorator.py +155 -0
- spring/scheduling/__init__.py +3 -0
- spring/scheduling/scheduler.py +389 -0
- spring/security/__init__.py +39 -0
- spring/security/jwt_utils.py +281 -0
- spring/security/replay_protection.py +206 -0
- spring/security/secret_manager.py +226 -0
- spring/security/security_aop.py +248 -0
- spring/security/security_context.py +172 -0
- spring/test/__init__.py +45 -0
- spring/test/slicing.py +341 -0
- spring/tracing/__init__.py +11 -0
- spring/tracing/skywalking.py +229 -0
- spring/tx/__init__.py +52 -0
- spring/tx/events.py +172 -0
- spring/tx/synchronization.py +143 -0
- spring/utils/__init__.py +5 -0
- spring/utils/banner.py +32 -0
- spring/utils/logger.py +73 -0
- spring/utils/redis_client.py +526 -0
- spring/validation/__init__.py +55 -0
- spring/validation/aop.py +141 -0
- spring/validation/constraints.py +357 -0
- spring/validation/exceptions.py +55 -0
- spring/validation/validator.py +139 -0
- spring/web/__init__.py +12 -0
- spring/web/actuator.py +319 -0
- spring/web/exception_handler.py +61 -0
- spring/web/health.py +399 -0
- spring/web/interceptor.py +91 -0
- spring/web/result.py +44 -0
- spring/web/swagger.py +601 -0
- spring/web/web_context.py +755 -0
- spring/websocket/__init__.py +86 -0
- spring/websocket/annotations.py +169 -0
- spring/websocket/broker.py +238 -0
- spring/websocket/exceptions.py +26 -0
- spring/websocket/handler.py +243 -0
- spring/websocket/router.py +526 -0
- spring/websocket/session.py +216 -0
- springbootai-1.8.0.dist-info/METADATA +2796 -0
- springbootai-1.8.0.dist-info/RECORD +175 -0
- springbootai-1.8.0.dist-info/WHEEL +5 -0
- springbootai-1.8.0.dist-info/entry_points.txt +2 -0
- springbootai-1.8.0.dist-info/licenses/LICENSE +7 -0
- springbootai-1.8.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prometheus监控模块
|
|
3
|
+
提供指标暴露和采集功能
|
|
4
|
+
"""
|
|
5
|
+
from prometheus_client import (
|
|
6
|
+
CollectorRegistry,
|
|
7
|
+
Counter,
|
|
8
|
+
Gauge,
|
|
9
|
+
Histogram,
|
|
10
|
+
Summary,
|
|
11
|
+
generate_latest,
|
|
12
|
+
CONTENT_TYPE_LATEST,
|
|
13
|
+
)
|
|
14
|
+
from prometheus_client.exposition import start_http_server
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
import time
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger("Spring.Monitoring.Prometheus")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PrometheusMetrics:
|
|
23
|
+
"""Prometheus指标管理器"""
|
|
24
|
+
|
|
25
|
+
_instance = None
|
|
26
|
+
_lock = __import__('threading').Lock()
|
|
27
|
+
|
|
28
|
+
def __new__(cls, *args, **kwargs):
|
|
29
|
+
if cls._instance is None:
|
|
30
|
+
with cls._lock:
|
|
31
|
+
if cls._instance is None:
|
|
32
|
+
cls._instance = super().__new__(cls)
|
|
33
|
+
return cls._instance
|
|
34
|
+
|
|
35
|
+
def __init__(self, namespace: str = "spring", subsystem: str = "python"):
|
|
36
|
+
if hasattr(self, '_initialized'):
|
|
37
|
+
return
|
|
38
|
+
self.namespace = namespace
|
|
39
|
+
self.subsystem = subsystem
|
|
40
|
+
self._registry = CollectorRegistry()
|
|
41
|
+
self._metric_registry = self._registry
|
|
42
|
+
if os.getenv('PROMETHEUS_MULTIPROC_DIR'):
|
|
43
|
+
from prometheus_client import multiprocess
|
|
44
|
+
multiprocess.MultiProcessCollector(self._registry)
|
|
45
|
+
# Metrics write their values to multiprocess files and must not also
|
|
46
|
+
# register live collectors in the exposition registry.
|
|
47
|
+
self._metric_registry = None
|
|
48
|
+
self._metrics: dict = {}
|
|
49
|
+
self._initialized = True
|
|
50
|
+
|
|
51
|
+
def configure(self, namespace: str, subsystem: str) -> None:
|
|
52
|
+
if self._metrics and (namespace != self.namespace or subsystem != self.subsystem):
|
|
53
|
+
raise RuntimeError("Prometheus namespace/subsystem cannot change after metrics are created")
|
|
54
|
+
self.namespace = namespace
|
|
55
|
+
self.subsystem = subsystem
|
|
56
|
+
|
|
57
|
+
def create_counter(self, name: str, documentation: str, labelnames: list = None) -> Counter:
|
|
58
|
+
"""
|
|
59
|
+
创建计数器指标
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
name: 指标名称
|
|
63
|
+
documentation: 指标描述
|
|
64
|
+
labelnames: 标签名称列表
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Counter对象
|
|
68
|
+
"""
|
|
69
|
+
key = f"{self.namespace}_{self.subsystem}_{name}"
|
|
70
|
+
if key not in self._metrics:
|
|
71
|
+
self._metrics[key] = Counter(
|
|
72
|
+
name=name,
|
|
73
|
+
documentation=documentation,
|
|
74
|
+
labelnames=labelnames or [],
|
|
75
|
+
namespace=self.namespace,
|
|
76
|
+
subsystem=self.subsystem,
|
|
77
|
+
registry=self._metric_registry,
|
|
78
|
+
)
|
|
79
|
+
return self._metrics[key]
|
|
80
|
+
|
|
81
|
+
def create_gauge(self, name: str, documentation: str, labelnames: list = None) -> Gauge:
|
|
82
|
+
"""
|
|
83
|
+
创建仪表盘指标
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
name: 指标名称
|
|
87
|
+
documentation: 指标描述
|
|
88
|
+
labelnames: 标签名称列表
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Gauge对象
|
|
92
|
+
"""
|
|
93
|
+
key = f"{self.namespace}_{self.subsystem}_{name}"
|
|
94
|
+
if key not in self._metrics:
|
|
95
|
+
self._metrics[key] = Gauge(
|
|
96
|
+
name=name,
|
|
97
|
+
documentation=documentation,
|
|
98
|
+
labelnames=labelnames or [],
|
|
99
|
+
namespace=self.namespace,
|
|
100
|
+
subsystem=self.subsystem,
|
|
101
|
+
registry=self._metric_registry,
|
|
102
|
+
)
|
|
103
|
+
return self._metrics[key]
|
|
104
|
+
|
|
105
|
+
def create_histogram(self, name: str, documentation: str, labelnames: list = None,
|
|
106
|
+
buckets: list = None) -> Histogram:
|
|
107
|
+
"""
|
|
108
|
+
创建直方图指标
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
name: 指标名称
|
|
112
|
+
documentation: 指标描述
|
|
113
|
+
labelnames: 标签名称列表
|
|
114
|
+
buckets: 桶边界列表
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Histogram对象
|
|
118
|
+
"""
|
|
119
|
+
key = f"{self.namespace}_{self.subsystem}_{name}"
|
|
120
|
+
if key not in self._metrics:
|
|
121
|
+
self._metrics[key] = Histogram(
|
|
122
|
+
name=name,
|
|
123
|
+
documentation=documentation,
|
|
124
|
+
labelnames=labelnames or [],
|
|
125
|
+
buckets=buckets or Histogram.DEFAULT_BUCKETS,
|
|
126
|
+
namespace=self.namespace,
|
|
127
|
+
subsystem=self.subsystem,
|
|
128
|
+
registry=self._metric_registry,
|
|
129
|
+
)
|
|
130
|
+
return self._metrics[key]
|
|
131
|
+
|
|
132
|
+
def create_summary(self, name: str, documentation: str, labelnames: list = None,
|
|
133
|
+
objectives: dict = None) -> Summary:
|
|
134
|
+
"""
|
|
135
|
+
创建摘要指标
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
name: 指标名称
|
|
139
|
+
documentation: 指标描述
|
|
140
|
+
labelnames: 标签名称列表
|
|
141
|
+
objectives: 分位数目标
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Summary对象
|
|
145
|
+
"""
|
|
146
|
+
key = f"{self.namespace}_{self.subsystem}_{name}"
|
|
147
|
+
if key not in self._metrics:
|
|
148
|
+
self._metrics[key] = Summary(
|
|
149
|
+
name=name,
|
|
150
|
+
documentation=documentation,
|
|
151
|
+
labelnames=labelnames or [],
|
|
152
|
+
objectives=objectives or Summary.DEFAULT_OBJECTIVES,
|
|
153
|
+
namespace=self.namespace,
|
|
154
|
+
subsystem=self.subsystem,
|
|
155
|
+
registry=self._metric_registry,
|
|
156
|
+
)
|
|
157
|
+
return self._metrics[key]
|
|
158
|
+
|
|
159
|
+
def get_metrics(self) -> dict:
|
|
160
|
+
"""获取所有指标"""
|
|
161
|
+
return self._metrics
|
|
162
|
+
|
|
163
|
+
def get_registry(self) -> CollectorRegistry:
|
|
164
|
+
"""获取指标注册表"""
|
|
165
|
+
return self._registry
|
|
166
|
+
|
|
167
|
+
def generate_metrics_data(self) -> bytes:
|
|
168
|
+
"""生成Prometheus格式的指标数据"""
|
|
169
|
+
return generate_latest(self._registry)
|
|
170
|
+
|
|
171
|
+
def start_server(self, port: int = 8000):
|
|
172
|
+
"""
|
|
173
|
+
启动Prometheus指标暴露HTTP服务器
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
port: 监听端口
|
|
177
|
+
"""
|
|
178
|
+
start_http_server(port, registry=self._registry)
|
|
179
|
+
logger.info(f"Prometheus metrics server started on port {port}")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# 创建全局Prometheus指标管理器实例
|
|
183
|
+
prometheus_metrics = PrometheusMetrics()
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def init_prometheus(config: dict) -> None:
|
|
187
|
+
"""
|
|
188
|
+
初始化Prometheus配置
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
config: 配置字典,包含namespace, subsystem, port等
|
|
192
|
+
"""
|
|
193
|
+
prometheus_metrics.configure(
|
|
194
|
+
namespace=config.get('namespace', 'spring'),
|
|
195
|
+
subsystem=config.get('subsystem', 'python'),
|
|
196
|
+
)
|
|
197
|
+
# 默认通过主应用 /actuator/prometheus 暴露,避免多 worker 争抢端口。
|
|
198
|
+
if config.get('standalone_server', False):
|
|
199
|
+
prometheus_metrics.start_server(config.get('port', 8000))
|
spring/orm/__init__.py
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Spring ORM模块
|
|
3
|
+
集成PyMyBatis作为核心ORM框架
|
|
4
|
+
提供SQL与代码分离、事务管理、连接池等企业级数据库能力
|
|
5
|
+
|
|
6
|
+
支持两种数据访问模式:
|
|
7
|
+
1. Mapper模式(推荐):使用@Mapper注解和SQL注解定义数据访问接口
|
|
8
|
+
2. Repository模式:使用SQLAlchemy的ORM方式进行数据访问
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# 导入SQLAlchemy数据库管理器(可选)
|
|
12
|
+
try:
|
|
13
|
+
from spring.orm.database import (
|
|
14
|
+
DatabaseManager,
|
|
15
|
+
Base,
|
|
16
|
+
BaseEntity,
|
|
17
|
+
User,
|
|
18
|
+
AuditLog,
|
|
19
|
+
init_database,
|
|
20
|
+
)
|
|
21
|
+
except ImportError:
|
|
22
|
+
# SQLAlchemy未安装,这些类不可用
|
|
23
|
+
DatabaseManager = None
|
|
24
|
+
Base = None
|
|
25
|
+
BaseEntity = None
|
|
26
|
+
User = None
|
|
27
|
+
AuditLog = None
|
|
28
|
+
init_database = None
|
|
29
|
+
|
|
30
|
+
# 从pymybatis导入核心类
|
|
31
|
+
from spring.orm.pymybatis import (
|
|
32
|
+
Configuration,
|
|
33
|
+
build_session_factory,
|
|
34
|
+
SqlSessionFactory,
|
|
35
|
+
SqlSession,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# 导入Spring与MyBatis集成注解和工具
|
|
39
|
+
from spring.orm.mybatis_integration import (
|
|
40
|
+
Mapper,
|
|
41
|
+
MapperScan,
|
|
42
|
+
MyBatisConfigurer,
|
|
43
|
+
init_mybatis,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# 导入注解
|
|
47
|
+
from spring.orm.pymybatis.annotations import (
|
|
48
|
+
Select,
|
|
49
|
+
Insert,
|
|
50
|
+
Update,
|
|
51
|
+
Delete,
|
|
52
|
+
SelectProvider,
|
|
53
|
+
InsertProvider,
|
|
54
|
+
UpdateProvider,
|
|
55
|
+
DeleteProvider,
|
|
56
|
+
ResultMap,
|
|
57
|
+
Result,
|
|
58
|
+
Options,
|
|
59
|
+
Param,
|
|
60
|
+
CacheNamespace,
|
|
61
|
+
DataSource,
|
|
62
|
+
Transactional as MapperTransactional,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# 导入安全模块
|
|
66
|
+
from spring.orm.pymybatis.security import (
|
|
67
|
+
SensitiveDataMasker,
|
|
68
|
+
PasswordEncoder,
|
|
69
|
+
SQLInjectionDetector,
|
|
70
|
+
RoleBasedAccessControl,
|
|
71
|
+
RowLevelAccessControl,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# 导入缓存模块
|
|
75
|
+
from spring.orm.pymybatis.cache import (
|
|
76
|
+
LRUCache,
|
|
77
|
+
SecondLevelCache,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# 导入事务模块
|
|
81
|
+
from spring.orm.pymybatis.transaction import (
|
|
82
|
+
TransactionIsolationLevel,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# 导入拦截器模块
|
|
86
|
+
from spring.orm.pymybatis.interceptor import (
|
|
87
|
+
Interceptor,
|
|
88
|
+
LogInterceptor,
|
|
89
|
+
PerformanceInterceptor,
|
|
90
|
+
SecurityInterceptor,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# 导入类型处理器
|
|
94
|
+
from spring.orm.pymybatis.type_handler import (
|
|
95
|
+
TypeHandler,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# 导入数据库方言
|
|
99
|
+
from spring.orm.pymybatis.dialect import (
|
|
100
|
+
Dialect,
|
|
101
|
+
get_dialect,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# 导入连接池
|
|
105
|
+
from spring.orm.pymybatis.pool import (
|
|
106
|
+
create_connection_pool,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# 导入动态SQL处理器
|
|
110
|
+
from spring.orm.pymybatis.dynamic_sql import (
|
|
111
|
+
DynamicSQLProcessor,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# 导入XML解析器
|
|
115
|
+
from spring.orm.pymybatis.xml_parser import (
|
|
116
|
+
XmlParser,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# 导入熔断器
|
|
120
|
+
from spring.orm.pymybatis.circuit_breaker import (
|
|
121
|
+
CircuitBreaker,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# 导入指标监控
|
|
125
|
+
from spring.orm.pymybatis.metrics import (
|
|
126
|
+
MetricsCollector,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# 导入数据库迁移(Flyway风格)
|
|
130
|
+
from spring.orm.migration import (
|
|
131
|
+
MigrationManager,
|
|
132
|
+
MigrationError,
|
|
133
|
+
MigrationState,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# 导入DDL自动建表(JPA hibernate.ddl-auto风格)
|
|
137
|
+
from spring.orm.ddl_auto import (
|
|
138
|
+
DdlAutoManager,
|
|
139
|
+
DdlAutoMode,
|
|
140
|
+
EntityTable,
|
|
141
|
+
Table,
|
|
142
|
+
Column,
|
|
143
|
+
Id,
|
|
144
|
+
Version,
|
|
145
|
+
Transient,
|
|
146
|
+
Index,
|
|
147
|
+
entity,
|
|
148
|
+
table as table_decorator,
|
|
149
|
+
column as column_decorator,
|
|
150
|
+
id_column as id_column_decorator,
|
|
151
|
+
version_column,
|
|
152
|
+
version_column as version_column_decorator,
|
|
153
|
+
transient_field,
|
|
154
|
+
transient_field as transient_field_decorator,
|
|
155
|
+
init_ddl_auto,
|
|
156
|
+
get_ddl_manager,
|
|
157
|
+
OptimisticLockExecutor,
|
|
158
|
+
OptimisticLockError,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# 版本信息
|
|
162
|
+
from spring.orm.pymybatis.version import __version__
|
|
163
|
+
|
|
164
|
+
__all__ = [
|
|
165
|
+
# SQLAlchemy数据库管理器
|
|
166
|
+
'DatabaseManager',
|
|
167
|
+
'Base',
|
|
168
|
+
'BaseEntity',
|
|
169
|
+
'User',
|
|
170
|
+
'AuditLog',
|
|
171
|
+
'init_database',
|
|
172
|
+
# PyMyBatis核心类
|
|
173
|
+
'Configuration',
|
|
174
|
+
'build_session_factory',
|
|
175
|
+
'SqlSessionFactory',
|
|
176
|
+
'SqlSession',
|
|
177
|
+
# Spring集成注解
|
|
178
|
+
'Mapper',
|
|
179
|
+
'MapperScan',
|
|
180
|
+
'MyBatisConfigurer',
|
|
181
|
+
'init_mybatis',
|
|
182
|
+
# 注解
|
|
183
|
+
'Select',
|
|
184
|
+
'Insert',
|
|
185
|
+
'Update',
|
|
186
|
+
'Delete',
|
|
187
|
+
'SelectProvider',
|
|
188
|
+
'InsertProvider',
|
|
189
|
+
'UpdateProvider',
|
|
190
|
+
'DeleteProvider',
|
|
191
|
+
'ResultMap',
|
|
192
|
+
'Result',
|
|
193
|
+
'Options',
|
|
194
|
+
'Param',
|
|
195
|
+
'CacheNamespace',
|
|
196
|
+
'DataSource',
|
|
197
|
+
'MapperTransactional',
|
|
198
|
+
# 安全模块
|
|
199
|
+
'SensitiveDataMasker',
|
|
200
|
+
'PasswordEncoder',
|
|
201
|
+
'SQLInjectionDetector',
|
|
202
|
+
'RoleBasedAccessControl',
|
|
203
|
+
'RowLevelAccessControl',
|
|
204
|
+
# 缓存模块
|
|
205
|
+
'LRUCache',
|
|
206
|
+
'SecondLevelCache',
|
|
207
|
+
# 事务模块
|
|
208
|
+
'TransactionIsolationLevel',
|
|
209
|
+
# 拦截器模块
|
|
210
|
+
'Interceptor',
|
|
211
|
+
'LogInterceptor',
|
|
212
|
+
'PerformanceInterceptor',
|
|
213
|
+
'SecurityInterceptor',
|
|
214
|
+
# 类型处理器
|
|
215
|
+
'TypeHandler',
|
|
216
|
+
# 数据库方言
|
|
217
|
+
'Dialect',
|
|
218
|
+
'get_dialect',
|
|
219
|
+
# 连接池
|
|
220
|
+
'create_connection_pool',
|
|
221
|
+
# 动态SQL
|
|
222
|
+
'DynamicSQLProcessor',
|
|
223
|
+
# XML解析器
|
|
224
|
+
'XmlParser',
|
|
225
|
+
# 熔断器
|
|
226
|
+
'CircuitBreaker',
|
|
227
|
+
# 指标监控
|
|
228
|
+
'MetricsCollector',
|
|
229
|
+
# 数据库迁移
|
|
230
|
+
'MigrationManager',
|
|
231
|
+
'MigrationError',
|
|
232
|
+
'MigrationState',
|
|
233
|
+
# DDL自动建表
|
|
234
|
+
'DdlAutoManager',
|
|
235
|
+
'DdlAutoMode',
|
|
236
|
+
'EntityTable',
|
|
237
|
+
'Table',
|
|
238
|
+
'Column',
|
|
239
|
+
'Id',
|
|
240
|
+
'Version',
|
|
241
|
+
'Transient',
|
|
242
|
+
'Index',
|
|
243
|
+
'entity',
|
|
244
|
+
'table_decorator',
|
|
245
|
+
'column_decorator',
|
|
246
|
+
'id_column_decorator',
|
|
247
|
+
'version_column',
|
|
248
|
+
'version_column_decorator',
|
|
249
|
+
'transient_field',
|
|
250
|
+
'transient_field_decorator',
|
|
251
|
+
'init_ddl_auto',
|
|
252
|
+
'get_ddl_manager',
|
|
253
|
+
# JPA @Version 乐观锁执行器
|
|
254
|
+
'OptimisticLockExecutor',
|
|
255
|
+
'OptimisticLockError',
|
|
256
|
+
# 版本
|
|
257
|
+
'__version__',
|
|
258
|
+
]
|
spring/orm/database.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""
|
|
2
|
+
数据库ORM模块
|
|
3
|
+
集成SQLAlchemy实现企业级数据库操作
|
|
4
|
+
"""
|
|
5
|
+
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, Boolean, Text, ForeignKey
|
|
6
|
+
from sqlalchemy.orm import declarative_base, sessionmaker, Session, relationship, scoped_session
|
|
7
|
+
from sqlalchemy.exc import SQLAlchemyError
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("Spring.ORM")
|
|
12
|
+
|
|
13
|
+
# 创建Base类
|
|
14
|
+
Base = declarative_base()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DatabaseManager:
|
|
18
|
+
"""数据库管理器"""
|
|
19
|
+
|
|
20
|
+
_instance = None
|
|
21
|
+
_lock = __import__('threading').Lock()
|
|
22
|
+
|
|
23
|
+
def __new__(cls, *args, **kwargs):
|
|
24
|
+
if cls._instance is None:
|
|
25
|
+
with cls._lock:
|
|
26
|
+
if cls._instance is None:
|
|
27
|
+
cls._instance = super().__new__(cls)
|
|
28
|
+
return cls._instance
|
|
29
|
+
|
|
30
|
+
def __init__(self, db_url: str = "sqlite:///./test.db", echo: bool = False):
|
|
31
|
+
if hasattr(self, '_initialized'):
|
|
32
|
+
return
|
|
33
|
+
self.db_url = db_url
|
|
34
|
+
self.echo = echo
|
|
35
|
+
self._engine = None
|
|
36
|
+
self._session_factory = None
|
|
37
|
+
self._scoped_session = None
|
|
38
|
+
self._initialized = True
|
|
39
|
+
|
|
40
|
+
def connect(self) -> None:
|
|
41
|
+
"""连接数据库"""
|
|
42
|
+
try:
|
|
43
|
+
self._engine = create_engine(self.db_url, echo=self.echo)
|
|
44
|
+
|
|
45
|
+
# 创建Session工厂
|
|
46
|
+
self._session_factory = sessionmaker(
|
|
47
|
+
bind=self._engine,
|
|
48
|
+
autocommit=False,
|
|
49
|
+
autoflush=False,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# 创建线程安全的Scoped Session
|
|
53
|
+
self._scoped_session = scoped_session(self._session_factory)
|
|
54
|
+
|
|
55
|
+
logger.info(f"Connected to database: {self.db_url}")
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logger.error(f"Failed to connect to database: {e}")
|
|
58
|
+
raise
|
|
59
|
+
|
|
60
|
+
def get_engine(self):
|
|
61
|
+
"""获取数据库引擎"""
|
|
62
|
+
if self._engine is None:
|
|
63
|
+
self.connect()
|
|
64
|
+
return self._engine
|
|
65
|
+
|
|
66
|
+
def get_session(self) -> Session:
|
|
67
|
+
"""获取数据库会话"""
|
|
68
|
+
if self._scoped_session is None:
|
|
69
|
+
self.connect()
|
|
70
|
+
return self._scoped_session()
|
|
71
|
+
|
|
72
|
+
def create_all(self):
|
|
73
|
+
"""创建所有表"""
|
|
74
|
+
engine = self.get_engine()
|
|
75
|
+
Base.metadata.create_all(engine)
|
|
76
|
+
logger.info("All tables created")
|
|
77
|
+
|
|
78
|
+
def drop_all(self):
|
|
79
|
+
"""删除所有表"""
|
|
80
|
+
engine = self.get_engine()
|
|
81
|
+
Base.metadata.drop_all(engine)
|
|
82
|
+
logger.info("All tables dropped")
|
|
83
|
+
|
|
84
|
+
def execute(self, statement, *args, **kwargs):
|
|
85
|
+
"""执行SQL语句"""
|
|
86
|
+
session = self.get_session()
|
|
87
|
+
try:
|
|
88
|
+
result = session.execute(statement, *args, **kwargs)
|
|
89
|
+
session.commit()
|
|
90
|
+
return result
|
|
91
|
+
except SQLAlchemyError as e:
|
|
92
|
+
session.rollback()
|
|
93
|
+
logger.error(f"SQL execution failed: {e}")
|
|
94
|
+
raise
|
|
95
|
+
finally:
|
|
96
|
+
session.close()
|
|
97
|
+
|
|
98
|
+
def insert(self, model):
|
|
99
|
+
"""插入数据"""
|
|
100
|
+
session = self.get_session()
|
|
101
|
+
try:
|
|
102
|
+
session.add(model)
|
|
103
|
+
session.commit()
|
|
104
|
+
session.refresh(model)
|
|
105
|
+
return model
|
|
106
|
+
except SQLAlchemyError as e:
|
|
107
|
+
session.rollback()
|
|
108
|
+
logger.error(f"Insert failed: {e}")
|
|
109
|
+
raise
|
|
110
|
+
finally:
|
|
111
|
+
session.close()
|
|
112
|
+
|
|
113
|
+
def update(self, model):
|
|
114
|
+
"""更新数据"""
|
|
115
|
+
session = self.get_session()
|
|
116
|
+
try:
|
|
117
|
+
# 使用merge处理脱管对象
|
|
118
|
+
merged_model = session.merge(model)
|
|
119
|
+
session.commit()
|
|
120
|
+
session.refresh(merged_model)
|
|
121
|
+
# 更新原始对象的属性
|
|
122
|
+
for attr in ['id', 'created_at', 'updated_at'] + [c.name for c in model.__table__.columns]:
|
|
123
|
+
if hasattr(merged_model, attr):
|
|
124
|
+
setattr(model, attr, getattr(merged_model, attr))
|
|
125
|
+
return model
|
|
126
|
+
except SQLAlchemyError as e:
|
|
127
|
+
session.rollback()
|
|
128
|
+
logger.error(f"Update failed: {e}")
|
|
129
|
+
raise
|
|
130
|
+
finally:
|
|
131
|
+
session.close()
|
|
132
|
+
|
|
133
|
+
def delete(self, model):
|
|
134
|
+
"""删除数据"""
|
|
135
|
+
session = self.get_session()
|
|
136
|
+
try:
|
|
137
|
+
session.delete(model)
|
|
138
|
+
session.commit()
|
|
139
|
+
except SQLAlchemyError as e:
|
|
140
|
+
session.rollback()
|
|
141
|
+
logger.error(f"Delete failed: {e}")
|
|
142
|
+
raise
|
|
143
|
+
finally:
|
|
144
|
+
session.close()
|
|
145
|
+
|
|
146
|
+
def query(self, model):
|
|
147
|
+
"""创建查询对象"""
|
|
148
|
+
session = self.get_session()
|
|
149
|
+
return session.query(model)
|
|
150
|
+
|
|
151
|
+
def flush(self):
|
|
152
|
+
"""刷新会话"""
|
|
153
|
+
session = self.get_session()
|
|
154
|
+
session.flush()
|
|
155
|
+
|
|
156
|
+
def commit(self):
|
|
157
|
+
"""提交事务"""
|
|
158
|
+
session = self.get_session()
|
|
159
|
+
session.commit()
|
|
160
|
+
|
|
161
|
+
def rollback(self):
|
|
162
|
+
"""回滚事务"""
|
|
163
|
+
session = self.get_session()
|
|
164
|
+
session.rollback()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# 创建全局数据库管理器实例
|
|
168
|
+
db_manager = DatabaseManager()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def init_database(config: dict) -> None:
|
|
172
|
+
"""
|
|
173
|
+
初始化数据库配置
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
config: 配置字典,包含url, echo等
|
|
177
|
+
"""
|
|
178
|
+
global db_manager
|
|
179
|
+
db_manager = DatabaseManager(
|
|
180
|
+
db_url=config.get('url', 'sqlite:///./test.db'),
|
|
181
|
+
echo=config.get('echo', False)
|
|
182
|
+
)
|
|
183
|
+
db_manager.connect()
|
|
184
|
+
|
|
185
|
+
# 创建所有表
|
|
186
|
+
db_manager.create_all()
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# ==================== 基础实体类 ====================
|
|
190
|
+
|
|
191
|
+
class BaseEntity(Base):
|
|
192
|
+
"""基础实体类"""
|
|
193
|
+
__abstract__ = True
|
|
194
|
+
|
|
195
|
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
196
|
+
created_at = Column(DateTime, default=datetime.now, nullable=False)
|
|
197
|
+
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, nullable=False)
|
|
198
|
+
deleted = Column(Boolean, default=False, nullable=False)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class User(BaseEntity):
|
|
202
|
+
"""用户实体"""
|
|
203
|
+
__tablename__ = 'users'
|
|
204
|
+
|
|
205
|
+
username = Column(String(50), unique=True, nullable=False)
|
|
206
|
+
password = Column(String(255), nullable=False)
|
|
207
|
+
email = Column(String(100), unique=True, nullable=False)
|
|
208
|
+
phone = Column(String(20))
|
|
209
|
+
role = Column(String(50), default='USER')
|
|
210
|
+
status = Column(Integer, default=1)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class AuditLog(BaseEntity):
|
|
214
|
+
"""审计日志实体"""
|
|
215
|
+
__tablename__ = 'audit_logs'
|
|
216
|
+
|
|
217
|
+
action = Column(String(100), nullable=False)
|
|
218
|
+
target = Column(String(200))
|
|
219
|
+
detail = Column(Text)
|
|
220
|
+
operator = Column(String(100))
|
|
221
|
+
status = Column(String(20), default='SUCCESS')
|
|
222
|
+
duration = Column(Float)
|