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.
Files changed (175) hide show
  1. spring/__init__.py +66 -0
  2. spring/ai/__init__.py +78 -0
  3. spring/ai/advisors.py +139 -0
  4. spring/ai/annotations.py +74 -0
  5. spring/ai/autoconfig.py +481 -0
  6. spring/ai/core.py +391 -0
  7. spring/ai/etl.py +188 -0
  8. spring/ai/memory.py +109 -0
  9. spring/ai/observability.py +129 -0
  10. spring/ai/providers.py +789 -0
  11. spring/ai/resilience.py +258 -0
  12. spring/ai/tools.py +106 -0
  13. spring/ai/vectorstore.py +303 -0
  14. spring/annotations/__init__.py +188 -0
  15. spring/annotations/cache.py +126 -0
  16. spring/annotations/cloud.py +207 -0
  17. spring/annotations/conditional.py +272 -0
  18. spring/annotations/core.py +864 -0
  19. spring/annotations/messaging.py +107 -0
  20. spring/aop/__init__.py +4 -0
  21. spring/aop/cloud_aop.py +404 -0
  22. spring/aop/comprehensive_aop.py +1015 -0
  23. spring/aop/method_interceptor.py +19 -0
  24. spring/aop/proxy_factory.py +55 -0
  25. spring/cloud/__init__.py +76 -0
  26. spring/cloud/discovery.py +364 -0
  27. spring/cloud/feign.py +469 -0
  28. spring/cloud/gateway.py +452 -0
  29. spring/cloud/load_balancer.py +149 -0
  30. spring/cloud/seata.py +557 -0
  31. spring/cloud/sentinel.py +525 -0
  32. spring/cloud/tracer.py +337 -0
  33. spring/config/__init__.py +21 -0
  34. spring/config/binding.py +206 -0
  35. spring/config/config_loader.py +405 -0
  36. spring/context/__init__.py +13 -0
  37. spring/context/application_context.py +589 -0
  38. spring/context/bean_definition.py +70 -0
  39. spring/context/bean_factory.py +1052 -0
  40. spring/context/registry.py +58 -0
  41. spring/context/scanner.py +106 -0
  42. spring/core/__init__.py +3 -0
  43. spring/core/graceful_shutdown.py +196 -0
  44. spring/core/typing_utils.py +50 -0
  45. spring/csv/__init__.py +52 -0
  46. spring/csv/annotations.py +402 -0
  47. spring/csv/converters.py +69 -0
  48. spring/csv/easy_csv.py +95 -0
  49. spring/csv/exceptions.py +27 -0
  50. spring/csv/reader.py +195 -0
  51. spring/csv/writer.py +155 -0
  52. spring/data/__init__.py +54 -0
  53. spring/data/page.py +181 -0
  54. spring/data/repository.py +274 -0
  55. spring/data/specification.py +228 -0
  56. spring/datasource/__init__.py +66 -0
  57. spring/datasource/annotations.py +133 -0
  58. spring/datasource/context.py +69 -0
  59. spring/datasource/dynamic.py +148 -0
  60. spring/event/__init__.py +7 -0
  61. spring/event/publisher.py +69 -0
  62. spring/excel/__init__.py +51 -0
  63. spring/excel/annotations.py +405 -0
  64. spring/excel/converters.py +231 -0
  65. spring/excel/easy_excel.py +94 -0
  66. spring/excel/exceptions.py +31 -0
  67. spring/excel/reader.py +254 -0
  68. spring/excel/style.py +95 -0
  69. spring/excel/writer.py +197 -0
  70. spring/i18n/__init__.py +97 -0
  71. spring/i18n/accessor.py +94 -0
  72. spring/i18n/auto_config.py +177 -0
  73. spring/i18n/holder.py +106 -0
  74. spring/i18n/locale.py +152 -0
  75. spring/i18n/locale_resolver.py +367 -0
  76. spring/i18n/message_source.py +250 -0
  77. spring/i18n/middleware.py +79 -0
  78. spring/i18n/properties.py +168 -0
  79. spring/i18n/sources.py +255 -0
  80. spring/logging/__init__.py +1 -0
  81. spring/logging/loguru_logger.py +228 -0
  82. spring/main.py +378 -0
  83. spring/messaging/__init__.py +1 -0
  84. spring/messaging/rabbitmq.py +302 -0
  85. spring/monitoring/__init__.py +1 -0
  86. spring/monitoring/prometheus.py +199 -0
  87. spring/orm/__init__.py +258 -0
  88. spring/orm/database.py +222 -0
  89. spring/orm/ddl_auto.py +1217 -0
  90. spring/orm/migration.py +419 -0
  91. spring/orm/mybatis_integration.py +400 -0
  92. spring/orm/pymybatis/__init__.py +86 -0
  93. spring/orm/pymybatis/annotations/__init__.py +30 -0
  94. spring/orm/pymybatis/annotations/annotations.py +332 -0
  95. spring/orm/pymybatis/cache/__init__.py +47 -0
  96. spring/orm/pymybatis/cache/cache.py +371 -0
  97. spring/orm/pymybatis/cache/redis_cache.py +434 -0
  98. spring/orm/pymybatis/circuit_breaker/__init__.py +21 -0
  99. spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +424 -0
  100. spring/orm/pymybatis/configuration.py +525 -0
  101. spring/orm/pymybatis/core/__init__.py +10 -0
  102. spring/orm/pymybatis/core/sql_session.py +1382 -0
  103. spring/orm/pymybatis/core/sql_session_factory.py +76 -0
  104. spring/orm/pymybatis/dialect/__init__.py +9 -0
  105. spring/orm/pymybatis/dialect/dialect.py +445 -0
  106. spring/orm/pymybatis/dynamic_sql/__init__.py +9 -0
  107. spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +900 -0
  108. spring/orm/pymybatis/interceptor/__init__.py +31 -0
  109. spring/orm/pymybatis/interceptor/interceptor.py +427 -0
  110. spring/orm/pymybatis/mapper/__init__.py +9 -0
  111. spring/orm/pymybatis/mapper/mapper.py +540 -0
  112. spring/orm/pymybatis/metrics/__init__.py +41 -0
  113. spring/orm/pymybatis/metrics/metrics.py +595 -0
  114. spring/orm/pymybatis/pool/__init__.py +9 -0
  115. spring/orm/pymybatis/pool/connection_pool.py +711 -0
  116. spring/orm/pymybatis/security/__init__.py +19 -0
  117. spring/orm/pymybatis/security/access_control.py +415 -0
  118. spring/orm/pymybatis/security/password_encoder.py +293 -0
  119. spring/orm/pymybatis/security/sensitive_data_masker.py +326 -0
  120. spring/orm/pymybatis/security/sql_injection_detector.py +675 -0
  121. spring/orm/pymybatis/transaction/__init__.py +9 -0
  122. spring/orm/pymybatis/transaction/transaction.py +288 -0
  123. spring/orm/pymybatis/type_handler/__init__.py +37 -0
  124. spring/orm/pymybatis/type_handler/type_handler.py +473 -0
  125. spring/orm/pymybatis/version.py +9 -0
  126. spring/orm/pymybatis/xml_parser/__init__.py +9 -0
  127. spring/orm/pymybatis/xml_parser/xml_parser.py +761 -0
  128. spring/retry/__init__.py +12 -0
  129. spring/retry/retry_annotations.py +71 -0
  130. spring/retry/retry_decorator.py +155 -0
  131. spring/scheduling/__init__.py +3 -0
  132. spring/scheduling/scheduler.py +389 -0
  133. spring/security/__init__.py +39 -0
  134. spring/security/jwt_utils.py +281 -0
  135. spring/security/replay_protection.py +206 -0
  136. spring/security/secret_manager.py +226 -0
  137. spring/security/security_aop.py +248 -0
  138. spring/security/security_context.py +172 -0
  139. spring/test/__init__.py +45 -0
  140. spring/test/slicing.py +341 -0
  141. spring/tracing/__init__.py +11 -0
  142. spring/tracing/skywalking.py +229 -0
  143. spring/tx/__init__.py +52 -0
  144. spring/tx/events.py +172 -0
  145. spring/tx/synchronization.py +143 -0
  146. spring/utils/__init__.py +5 -0
  147. spring/utils/banner.py +32 -0
  148. spring/utils/logger.py +73 -0
  149. spring/utils/redis_client.py +526 -0
  150. spring/validation/__init__.py +55 -0
  151. spring/validation/aop.py +141 -0
  152. spring/validation/constraints.py +357 -0
  153. spring/validation/exceptions.py +55 -0
  154. spring/validation/validator.py +139 -0
  155. spring/web/__init__.py +12 -0
  156. spring/web/actuator.py +319 -0
  157. spring/web/exception_handler.py +61 -0
  158. spring/web/health.py +399 -0
  159. spring/web/interceptor.py +91 -0
  160. spring/web/result.py +44 -0
  161. spring/web/swagger.py +601 -0
  162. spring/web/web_context.py +755 -0
  163. spring/websocket/__init__.py +86 -0
  164. spring/websocket/annotations.py +169 -0
  165. spring/websocket/broker.py +238 -0
  166. spring/websocket/exceptions.py +26 -0
  167. spring/websocket/handler.py +243 -0
  168. spring/websocket/router.py +526 -0
  169. spring/websocket/session.py +216 -0
  170. springbootai-1.8.0.dist-info/METADATA +2796 -0
  171. springbootai-1.8.0.dist-info/RECORD +175 -0
  172. springbootai-1.8.0.dist-info/WHEEL +5 -0
  173. springbootai-1.8.0.dist-info/entry_points.txt +2 -0
  174. springbootai-1.8.0.dist-info/licenses/LICENSE +7 -0
  175. springbootai-1.8.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,434 @@
1
+ """
2
+ PyMyBatis Redis二级缓存模块
3
+
4
+ 实现基于Redis的分布式二级缓存,支持多实例部署时的数据一致性
5
+
6
+ 核心特性:
7
+ - Redis作为缓存后端
8
+ - 支持缓存过期时间
9
+ - 支持缓存失效通知(Redis Pub/Sub)
10
+ - 支持表级别的缓存失效
11
+ - 可配置的序列化方式
12
+ """
13
+
14
+ import json
15
+ import hashlib
16
+ import logging
17
+ from typing import Dict, Any, Optional, List
18
+ from enum import Enum
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class SerializationType(Enum):
24
+ """序列化类型"""
25
+ JSON = 'json'
26
+ PICKLE = 'pickle'
27
+
28
+
29
+ class RedisSecondLevelCache:
30
+ """
31
+ Redis二级缓存实现
32
+
33
+ 基于Redis实现的分布式缓存,支持多实例部署时的数据一致性。
34
+ 通过Redis Pub/Sub机制实现缓存失效通知。
35
+
36
+ 配置参数:
37
+ - host: Redis主机地址
38
+ - port: Redis端口
39
+ - db: Redis数据库编号
40
+ - password: Redis密码
41
+ - timeout: 连接超时时间
42
+ - ttl: 默认缓存过期时间(秒)
43
+ - serialization: 序列化方式(json/pickle)
44
+ - channel_prefix: Pub/Sub频道前缀
45
+ """
46
+
47
+ def __init__(self,
48
+ host: str = 'localhost',
49
+ port: int = 6379,
50
+ db: int = 0,
51
+ password: Optional[str] = None,
52
+ timeout: int = 10,
53
+ ttl: int = 300,
54
+ serialization: str = 'json',
55
+ channel_prefix: str = 'pymybatis:cache:'):
56
+ """
57
+ 初始化Redis二级缓存
58
+
59
+ Args:
60
+ host: Redis主机地址
61
+ port: Redis端口
62
+ db: Redis数据库编号
63
+ password: Redis密码
64
+ timeout: 连接超时时间(秒)
65
+ ttl: 默认缓存过期时间(秒)
66
+ serialization: 序列化方式(json/pickle)
67
+ channel_prefix: Pub/Sub频道前缀
68
+ """
69
+ self.host = host
70
+ self.port = port
71
+ self.db = db
72
+ self.password = password
73
+ self.timeout = timeout
74
+ self.ttl = ttl
75
+ self.serialization = SerializationType(serialization.lower())
76
+ self.channel_prefix = channel_prefix
77
+
78
+ # Redis连接
79
+ self._redis = None
80
+ self._pubsub = None
81
+ self._pubsub_thread = None
82
+
83
+ # 本地缓存(用于减少Redis访问)
84
+ self._local_cache: Dict[str, Any] = {}
85
+
86
+ # 启动缓存失效通知监听器
87
+ self._start_pubsub_listener()
88
+
89
+ def _connect(self):
90
+ """建立Redis连接"""
91
+ if self._redis is None:
92
+ try:
93
+ import redis
94
+ self._redis = redis.Redis(
95
+ host=self.host,
96
+ port=self.port,
97
+ db=self.db,
98
+ password=self.password,
99
+ socket_timeout=self.timeout,
100
+ decode_responses=False # 使用字节模式
101
+ )
102
+ logger.info(f"Redis连接成功: {self.host}:{self.port}/{self.db}")
103
+ except ImportError:
104
+ raise ImportError("请安装redis: pip install redis")
105
+ except Exception as e:
106
+ logger.error(f"Redis连接失败: {e}")
107
+ raise
108
+
109
+ return self._redis
110
+
111
+ def _serialize(self, value: Any) -> bytes:
112
+ """序列化值"""
113
+ if self.serialization == SerializationType.JSON:
114
+ return json.dumps(value, ensure_ascii=False).encode('utf-8')
115
+ else:
116
+ import pickle
117
+ return pickle.dumps(value)
118
+
119
+ def _deserialize(self, value: bytes) -> Any:
120
+ """反序列化值"""
121
+ if value is None:
122
+ return None
123
+
124
+ if self.serialization == SerializationType.JSON:
125
+ try:
126
+ return json.loads(value.decode('utf-8'))
127
+ except (json.JSONDecodeError, UnicodeDecodeError):
128
+ logger.warning("JSON反序列化失败,尝试pickle")
129
+ import pickle
130
+ return pickle.loads(value)
131
+ else:
132
+ import pickle
133
+ return pickle.loads(value)
134
+
135
+ def _generate_key(self, table_name: str, params: Dict[str, Any]) -> str:
136
+ """
137
+ 生成缓存key
138
+
139
+ Args:
140
+ table_name: 表名
141
+ params: 参数
142
+
143
+ Returns:
144
+ 缓存key
145
+ """
146
+ key = f"{table_name}_"
147
+ if params:
148
+ sorted_params = sorted(params.items())
149
+ key += str(sorted_params)
150
+ return hashlib.sha256(key.encode()).hexdigest()
151
+
152
+ def get(self, table_name: str, params: Dict[str, Any]) -> Optional[Any]:
153
+ """
154
+ 获取缓存
155
+
156
+ Args:
157
+ table_name: 表名
158
+ params: 查询参数
159
+
160
+ Returns:
161
+ 缓存值,不存在返回None
162
+ """
163
+ key = self._generate_key(table_name, params)
164
+ full_key = f"{self.channel_prefix}{key}"
165
+
166
+ # 先从本地缓存查找
167
+ if key in self._local_cache:
168
+ logger.debug(f"本地缓存命中: {full_key}")
169
+ return self._local_cache[key]
170
+
171
+ try:
172
+ redis = self._connect()
173
+ value = redis.get(full_key)
174
+ if value is not None:
175
+ result = self._deserialize(value)
176
+ # 更新本地缓存
177
+ self._local_cache[key] = result
178
+ logger.debug(f"Redis缓存命中: {full_key}")
179
+ return result
180
+ except Exception as e:
181
+ logger.error(f"Redis缓存读取失败: {e}")
182
+
183
+ return None
184
+
185
+ def put(self, table_name: str, params: Dict[str, Any], value: Any) -> None:
186
+ """
187
+ 设置缓存
188
+
189
+ Args:
190
+ table_name: 表名
191
+ params: 查询参数
192
+ value: 缓存值
193
+ """
194
+ key = self._generate_key(table_name, params)
195
+ full_key = f"{self.channel_prefix}{key}"
196
+
197
+ # 更新本地缓存
198
+ self._local_cache[key] = value
199
+
200
+ try:
201
+ redis = self._connect()
202
+ serialized_value = self._serialize(value)
203
+
204
+ if self.ttl > 0:
205
+ redis.setex(full_key, self.ttl, serialized_value)
206
+ else:
207
+ redis.set(full_key, serialized_value)
208
+
209
+ # 记录table_name到key的映射(用于缓存失效)
210
+ table_key = f"{self.channel_prefix}table:{table_name}"
211
+ redis.sadd(table_key, key)
212
+
213
+ logger.debug(f"Redis缓存设置成功: {full_key}")
214
+ except Exception as e:
215
+ logger.error(f"Redis缓存写入失败: {e}")
216
+
217
+ def invalidate_table(self, table_name: str) -> None:
218
+ """
219
+ 使指定表的所有缓存失效(广播通知)
220
+
221
+ Args:
222
+ table_name: 表名
223
+ """
224
+ try:
225
+ redis = self._connect()
226
+
227
+ # 获取该表所有缓存key
228
+ table_key = f"{self.channel_prefix}table:{table_name}"
229
+ keys = redis.smembers(table_key)
230
+
231
+ # 删除所有相关缓存
232
+ for key in keys:
233
+ full_key = f"{self.channel_prefix}{key.decode()}"
234
+ redis.delete(full_key)
235
+ # 更新本地缓存
236
+ self._local_cache.pop(key.decode(), None)
237
+
238
+ # 删除表映射
239
+ redis.delete(table_key)
240
+
241
+ # 发布缓存失效通知
242
+ channel = f"{self.channel_prefix}invalidate"
243
+ message = json.dumps({'table_name': table_name})
244
+ redis.publish(channel, message)
245
+
246
+ logger.info(f"Redis缓存失效: 表 {table_name},共 {len(keys)} 个缓存项")
247
+ except Exception as e:
248
+ logger.error(f"Redis缓存失效失败: {e}")
249
+
250
+ def invalidate_key(self, table_name: str, params: Dict[str, Any]) -> None:
251
+ """
252
+ 使指定缓存项失效
253
+
254
+ Args:
255
+ table_name: 表名
256
+ params: 查询参数
257
+ """
258
+ key = self._generate_key(table_name, params)
259
+ full_key = f"{self.channel_prefix}{key}"
260
+
261
+ # 更新本地缓存
262
+ self._local_cache.pop(key, None)
263
+
264
+ try:
265
+ redis = self._connect()
266
+ redis.delete(full_key)
267
+
268
+ # 从表映射中移除
269
+ table_key = f"{self.channel_prefix}table:{table_name}"
270
+ redis.srem(table_key, key)
271
+
272
+ logger.debug(f"Redis缓存项失效: {full_key}")
273
+ except Exception as e:
274
+ logger.error(f"Redis缓存项失效失败: {e}")
275
+
276
+ def invalidate_all(self) -> None:
277
+ """使所有缓存失效"""
278
+ try:
279
+ redis = self._connect()
280
+
281
+ # 获取所有缓存key
282
+ pattern = f"{self.channel_prefix}*"
283
+ keys = redis.keys(pattern)
284
+
285
+ # 删除所有缓存
286
+ if keys:
287
+ redis.delete(*keys)
288
+
289
+ # 清空本地缓存
290
+ self._local_cache.clear()
291
+
292
+ # 发布缓存失效通知
293
+ channel = f"{self.channel_prefix}invalidate"
294
+ message = json.dumps({'table_name': '__ALL__'})
295
+ redis.publish(channel, message)
296
+
297
+ logger.info(f"Redis缓存全部失效,共 {len(keys)} 个缓存项")
298
+ except Exception as e:
299
+ logger.error(f"Redis缓存全部失效失败: {e}")
300
+
301
+ def clear(self) -> None:
302
+ """清空缓存(同invalidate_all)"""
303
+ self.invalidate_all()
304
+
305
+ def size(self) -> int:
306
+ """获取缓存大小"""
307
+ try:
308
+ redis = self._connect()
309
+ pattern = f"{self.channel_prefix}[0-9a-f]*"
310
+ keys = redis.keys(pattern)
311
+ return len(keys)
312
+ except Exception as e:
313
+ logger.error(f"Redis缓存大小获取失败: {e}")
314
+ return 0
315
+
316
+ def get_stats(self) -> Dict[str, Any]:
317
+ """
318
+ 获取缓存统计信息
319
+
320
+ Returns:
321
+ 统计信息字典
322
+ """
323
+ try:
324
+ redis = self._connect()
325
+ info = redis.info()
326
+
327
+ return {
328
+ 'type': 'redis',
329
+ 'host': self.host,
330
+ 'port': self.port,
331
+ 'db': self.db,
332
+ 'ttl': self.ttl,
333
+ 'serialization': self.serialization.value,
334
+ 'local_cache_size': len(self._local_cache),
335
+ 'redis_keys_count': self.size(),
336
+ 'redis_info': {
337
+ 'used_memory': info.get('used_memory_human', 'N/A'),
338
+ 'used_cpu_sys': info.get('used_cpu_sys', 'N/A'),
339
+ 'connected_clients': info.get('connected_clients', 'N/A'),
340
+ 'keyspace_hits': info.get('keyspace_hits', 'N/A'),
341
+ 'keyspace_misses': info.get('keyspace_misses', 'N/A')
342
+ }
343
+ }
344
+ except Exception as e:
345
+ logger.error(f"Redis缓存统计获取失败: {e}")
346
+ return {
347
+ 'type': 'redis',
348
+ 'host': self.host,
349
+ 'port': self.port,
350
+ 'db': self.db,
351
+ 'ttl': self.ttl,
352
+ 'serialization': self.serialization.value,
353
+ 'local_cache_size': len(self._local_cache),
354
+ 'error': str(e)
355
+ }
356
+
357
+ def _start_pubsub_listener(self):
358
+ """启动缓存失效通知监听器"""
359
+ if self._pubsub_thread is not None:
360
+ return
361
+
362
+ try:
363
+ import threading
364
+
365
+ def listener():
366
+ redis = self._connect()
367
+ self._pubsub = redis.pubsub()
368
+ channel = f"{self.channel_prefix}invalidate"
369
+ self._pubsub.subscribe(channel)
370
+
371
+ logger.info(f"Redis缓存失效通知监听器已启动: {channel}")
372
+
373
+ for message in self._pubsub.listen():
374
+ if message['type'] == 'message':
375
+ try:
376
+ data = json.loads(message['data'].decode('utf-8'))
377
+ table_name = data.get('table_name')
378
+
379
+ if table_name == '__ALL__':
380
+ # 全部失效
381
+ self._local_cache.clear()
382
+ logger.info("收到缓存全部失效通知")
383
+ else:
384
+ # 特定表失效
385
+ # 移除该表相关的本地缓存
386
+ keys_to_remove = []
387
+ for key in self._local_cache:
388
+ if key.startswith(table_name):
389
+ keys_to_remove.append(key)
390
+ for key in keys_to_remove:
391
+ self._local_cache.pop(key, None)
392
+ logger.info(f"收到缓存失效通知: 表 {table_name}")
393
+ except Exception as e:
394
+ logger.error(f"处理缓存失效通知失败: {e}")
395
+
396
+ self._pubsub_thread = threading.Thread(target=listener, daemon=True)
397
+ self._pubsub_thread.start()
398
+ except Exception as e:
399
+ logger.error(f"启动缓存失效通知监听器失败: {e}")
400
+
401
+ def close(self):
402
+ """关闭Redis连接"""
403
+ if self._pubsub:
404
+ self._pubsub.close()
405
+
406
+ if self._redis:
407
+ self._redis.close()
408
+ logger.info("Redis连接已关闭")
409
+
410
+ def __del__(self):
411
+ """析构函数,确保连接被关闭"""
412
+ self.close()
413
+
414
+
415
+ def create_redis_cache(config: Dict[str, Any]) -> RedisSecondLevelCache:
416
+ """
417
+ 根据配置创建Redis缓存实例
418
+
419
+ Args:
420
+ config: Redis配置字典
421
+
422
+ Returns:
423
+ Redis缓存实例
424
+ """
425
+ return RedisSecondLevelCache(
426
+ host=config.get('host', 'localhost'),
427
+ port=config.get('port', 6379),
428
+ db=config.get('db', 0),
429
+ password=config.get('password'),
430
+ timeout=config.get('timeout', 10),
431
+ ttl=config.get('ttl', 300),
432
+ serialization=config.get('serialization', 'json'),
433
+ channel_prefix=config.get('channel_prefix', 'pymybatis:cache:')
434
+ )
@@ -0,0 +1,21 @@
1
+ """
2
+ PyMyBatis熔断降级模块
3
+
4
+ 实现数据库连接熔断机制,防止数据库故障导致的级联失败
5
+ """
6
+
7
+ from .circuit_breaker import (
8
+ CircuitBreaker,
9
+ CircuitBreakerState,
10
+ CircuitBreakerError,
11
+ DatabaseCircuitBreaker,
12
+ with_circuit_breaker
13
+ )
14
+
15
+ __all__ = [
16
+ 'CircuitBreaker',
17
+ 'CircuitBreakerState',
18
+ 'CircuitBreakerError',
19
+ 'DatabaseCircuitBreaker',
20
+ 'with_circuit_breaker'
21
+ ]