database-smartools 1.0.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.
- database-smartools/__init__.py +18 -0
- database-smartools/api/__init__.py +18 -0
- database-smartools/api/etl.py +160 -0
- database-smartools/database/__init__.py +18 -0
- database-smartools/database/dameng_extend.py +65 -0
- database-smartools/database/db_handler.py +676 -0
- database-smartools/database/mysql_extend.py +396 -0
- database-smartools/database/oceanbase_extend.py +55 -0
- database-smartools/database/oracle_extend.py +27 -0
- database-smartools/database/postgre_extend.py +396 -0
- database-smartools/main.py +86 -0
- database-smartools/module/__init__.py +18 -0
- database-smartools/module/function.py +115 -0
- database-smartools/utils/__init__.py +18 -0
- database-smartools/utils/config.py +56 -0
- database-smartools/utils/debug.py +72 -0
- database-smartools/utils/file.py +42 -0
- database-smartools/utils/http.py +74 -0
- database-smartools/utils/logger.py +237 -0
- database-smartools/utils/output.py +31 -0
- database-smartools/utils/texter.py +186 -0
- database-smartools/utils/timer.py +52 -0
- database-tools/__init__.py +18 -0
- database-tools/api/__init__.py +18 -0
- database-tools/api/etl.py +160 -0
- database-tools/database/__init__.py +18 -0
- database-tools/database/dameng_extend.py +65 -0
- database-tools/database/db_handler.py +676 -0
- database-tools/database/mysql_extend.py +396 -0
- database-tools/database/oceanbase_extend.py +55 -0
- database-tools/database/oracle_extend.py +27 -0
- database-tools/database/postgre_extend.py +396 -0
- database-tools/main.py +86 -0
- database-tools/module/__init__.py +18 -0
- database-tools/module/function.py +115 -0
- database-tools/utils/__init__.py +18 -0
- database-tools/utils/config.py +56 -0
- database-tools/utils/debug.py +72 -0
- database-tools/utils/file.py +42 -0
- database-tools/utils/http.py +74 -0
- database-tools/utils/logger.py +237 -0
- database-tools/utils/output.py +31 -0
- database-tools/utils/texter.py +186 -0
- database-tools/utils/timer.py +52 -0
- database_smartools-1.0.0.dist-info/METADATA +84 -0
- database_smartools-1.0.0.dist-info/RECORD +50 -0
- database_smartools-1.0.0.dist-info/WHEEL +5 -0
- database_smartools-1.0.0.dist-info/licenses/LICENSE +13 -0
- database_smartools-1.0.0.dist-info/top_level.txt +1 -0
- model/__init__.py +12 -0
@@ -0,0 +1,396 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
@项目名称 : python-main
|
4
|
+
@文件名称 : mysql_extend.py
|
5
|
+
@创建人 : zhongbinjie
|
6
|
+
@创建时间 : 2025/6/7 19:06
|
7
|
+
@文件说明 :
|
8
|
+
@企业名称 : 深圳市赢和信息技术有限公司
|
9
|
+
@Copyright:2025-2035, 深圳市赢和信息技术有限公司. All rights Reserved.
|
10
|
+
"""
|
11
|
+
|
12
|
+
from sqlalchemy import create_engine
|
13
|
+
import cx_Oracle
|
14
|
+
from utils import config, logger, texter
|
15
|
+
import numpy as np
|
16
|
+
|
17
|
+
# 获取数据池
|
18
|
+
cx_Oracle.init_oracle_client(lib_dir=config.MAP['db_lib']) # 替换为你的Instant Client路径
|
19
|
+
POOL_MAP = {}
|
20
|
+
|
21
|
+
|
22
|
+
def get_pool():
|
23
|
+
pool = cx_Oracle.SessionPool(user=config.MAP['db_user'],
|
24
|
+
password=config.MAP['db_password'],
|
25
|
+
dsn=cx_Oracle.makedsn(config.MAP['db_host'], config.MAP['db_port'],
|
26
|
+
config.MAP['db_name']),
|
27
|
+
min=2, max=15, increment=1, threaded=False)
|
28
|
+
return pool
|
29
|
+
|
30
|
+
|
31
|
+
def get_pool_by_key(db_key, refresh=False):
|
32
|
+
global POOL_MAP
|
33
|
+
scan_db_conf = f"""
|
34
|
+
SELECT user_name,pass_word,url FROM task_template_data_source WHERE db_key = :db_key
|
35
|
+
"""
|
36
|
+
params = {"db_key": db_key}
|
37
|
+
pool = get_pool()
|
38
|
+
conn, message = get_conn(pool)
|
39
|
+
select_result, select_message = select(conn, scan_db_conf, params)
|
40
|
+
if not select_result:
|
41
|
+
return None, select_message
|
42
|
+
db_conf = select_result['data'][0]
|
43
|
+
user_name = db_conf['user_name']
|
44
|
+
pass_word = db_conf['pass_word']
|
45
|
+
url = db_conf['url']
|
46
|
+
|
47
|
+
url_map = texter.parse_jdbc_url(url)
|
48
|
+
pool = None
|
49
|
+
if db_key not in POOL_MAP.keys() or refresh:
|
50
|
+
if url_map['type'] == 'oracle':
|
51
|
+
try:
|
52
|
+
pool = cx_Oracle.SessionPool(user=user_name,
|
53
|
+
password=pass_word,
|
54
|
+
dsn=cx_Oracle.makedsn(url_map['host'], url_map['port'],
|
55
|
+
url_map['database']),
|
56
|
+
min=2, max=15, increment=1, threaded=False)
|
57
|
+
except Exception as e:
|
58
|
+
message = f"实例化数据库连接池失败,错误信息:{e}"
|
59
|
+
logger.error(message)
|
60
|
+
|
61
|
+
return None, message
|
62
|
+
|
63
|
+
POOL_MAP[db_key] = {
|
64
|
+
"pool": pool,
|
65
|
+
"db_type": url_map['type']
|
66
|
+
}
|
67
|
+
logger.debug(f"创建新的连接池,db_key: {db_key}")
|
68
|
+
else:
|
69
|
+
pool = POOL_MAP[db_key][0]
|
70
|
+
logger.debug(f"使用已有连接池,db_key: {db_key}")
|
71
|
+
return pool, ""
|
72
|
+
|
73
|
+
|
74
|
+
def close_pool(pool):
|
75
|
+
pool.close()
|
76
|
+
logger.debug(f"关闭连接池")
|
77
|
+
|
78
|
+
|
79
|
+
def get_conn(pool):
|
80
|
+
message = ""
|
81
|
+
try:
|
82
|
+
conn = pool.acquire()
|
83
|
+
logger.debug(f"从连接池中获取数据库连接")
|
84
|
+
return conn, message
|
85
|
+
except Exception as e:
|
86
|
+
message = f'获取数据连接异常,错误信息:{e}'
|
87
|
+
logger.error(f'获取数据连接异常,错误信息:{e}')
|
88
|
+
return None, message
|
89
|
+
|
90
|
+
|
91
|
+
def get_conn_map(pool_map):
|
92
|
+
message = ""
|
93
|
+
try:
|
94
|
+
conn = pool_map['pool'].acquire()
|
95
|
+
db_type = pool_map['db_type']
|
96
|
+
conn_map = {
|
97
|
+
"conn": conn,
|
98
|
+
"db_type": db_type
|
99
|
+
}
|
100
|
+
logger.debug(f"从连接池中获取数据库连接和数据库类型")
|
101
|
+
return conn_map, message
|
102
|
+
except Exception as e:
|
103
|
+
message = f'获取数据连接异常,错误信息:{e}'
|
104
|
+
logger.error(f'获取数据连接异常,错误信息:{e}')
|
105
|
+
return None, message
|
106
|
+
|
107
|
+
|
108
|
+
def get_engine():
|
109
|
+
url = f'oracle+cx_oracle://{config.DB_USER}:{config.DB_PASSWORD}@{config.DB_HOST}:{config.DB_PORT}/?service_name={config.DB_NAME}'
|
110
|
+
engine = create_engine(url,
|
111
|
+
pool_size=30,
|
112
|
+
max_overflow=20,
|
113
|
+
pool_timeout=30,
|
114
|
+
pool_recycle=1800,
|
115
|
+
pool_pre_ping=True)
|
116
|
+
|
117
|
+
return engine
|
118
|
+
|
119
|
+
|
120
|
+
def close_engine(engine):
|
121
|
+
engine.dispose()
|
122
|
+
|
123
|
+
|
124
|
+
def close_conn(pool, conn):
|
125
|
+
if isinstance(pool, dict):
|
126
|
+
pool = pool['pool']
|
127
|
+
|
128
|
+
if isinstance(conn, dict):
|
129
|
+
conn = conn['conn']
|
130
|
+
pool.release(conn)
|
131
|
+
logger.debug(f"从连接池中释放数据库连接")
|
132
|
+
return conn
|
133
|
+
|
134
|
+
|
135
|
+
def commit(conn):
|
136
|
+
if isinstance(conn, dict):
|
137
|
+
conn = conn['conn']
|
138
|
+
conn.commit()
|
139
|
+
logger.debug(f"数据库连接-提交事务")
|
140
|
+
return
|
141
|
+
|
142
|
+
|
143
|
+
def rollback(conn):
|
144
|
+
if isinstance(conn, dict):
|
145
|
+
conn = conn['conn']
|
146
|
+
conn.rollback()
|
147
|
+
logger.debug(f"数据库连接-回滚事务")
|
148
|
+
return
|
149
|
+
|
150
|
+
|
151
|
+
def select(conn, sql, params=None):
|
152
|
+
result = None
|
153
|
+
message = ""
|
154
|
+
with conn.cursor() as cursor:
|
155
|
+
try:
|
156
|
+
if params:
|
157
|
+
rs = cursor.execute(sql, params).fetchall()
|
158
|
+
result = {
|
159
|
+
'data': rs,
|
160
|
+
'desc': cursor.description
|
161
|
+
}
|
162
|
+
else:
|
163
|
+
rs = cursor.execute(sql).fetchall()
|
164
|
+
result = {
|
165
|
+
'data': rs,
|
166
|
+
'desc': cursor.description
|
167
|
+
}
|
168
|
+
|
169
|
+
logger.debug(f"[数据查询]sql: {sql}, 参数列表: {params}")
|
170
|
+
|
171
|
+
except Exception as e:
|
172
|
+
message = f"[数据查询]异常:{e}"
|
173
|
+
logger.error(message)
|
174
|
+
return None, message
|
175
|
+
|
176
|
+
# print(result)
|
177
|
+
data = []
|
178
|
+
for row in result['data']:
|
179
|
+
item_map = {}
|
180
|
+
for index, item in enumerate(row):
|
181
|
+
if result['desc'][index][1] == cx_Oracle.DATETIME and item is not None:
|
182
|
+
item = item.strftime("%Y-%m-%d %H:%M:%S")
|
183
|
+
|
184
|
+
item_map[result['desc'][index][0].lower()] = item
|
185
|
+
data.append(item_map)
|
186
|
+
result['data'] = data
|
187
|
+
return result, message
|
188
|
+
|
189
|
+
|
190
|
+
def select_by_map(conn_map, sql, params=None):
|
191
|
+
result = None
|
192
|
+
message = ""
|
193
|
+
conn = conn_map['conn']
|
194
|
+
with conn.cursor() as cursor:
|
195
|
+
try:
|
196
|
+
if params:
|
197
|
+
rs = cursor.execute(sql, params).fetchall()
|
198
|
+
result = {
|
199
|
+
'data': rs,
|
200
|
+
'desc': cursor.description
|
201
|
+
}
|
202
|
+
else:
|
203
|
+
rs = cursor.execute(sql).fetchall()
|
204
|
+
result = {
|
205
|
+
'data': rs,
|
206
|
+
'desc': cursor.description
|
207
|
+
}
|
208
|
+
|
209
|
+
logger.debug(f"[数据查询]sql: {sql}, 参数列表: {params}")
|
210
|
+
|
211
|
+
column_types = []
|
212
|
+
for desc in result['desc']:
|
213
|
+
column_types.append(desc[1])
|
214
|
+
result['data_types'] = column_types
|
215
|
+
|
216
|
+
except Exception as e:
|
217
|
+
message = f"[数据查询]异常:{e}"
|
218
|
+
logger.error(message)
|
219
|
+
return None, message
|
220
|
+
|
221
|
+
# print(result)
|
222
|
+
data = []
|
223
|
+
for row in result['data']:
|
224
|
+
item_map = {}
|
225
|
+
for index, item in enumerate(row):
|
226
|
+
# if result['desc'][index][1] == cx_Oracle.DATETIME and item is not None:
|
227
|
+
# item = item.strftime("%Y-%m-%d")
|
228
|
+
|
229
|
+
if result['desc'][index][1] == cx_Oracle.TIMESTAMP and item is not None:
|
230
|
+
item = item.strftime("%Y-%m-%d %H:%M:%S")
|
231
|
+
|
232
|
+
item_map[result['desc'][index][0].lower()] = item
|
233
|
+
|
234
|
+
data.append(item_map)
|
235
|
+
result['data'] = data
|
236
|
+
return result, message
|
237
|
+
|
238
|
+
|
239
|
+
def delete(conn, sql, params=None):
|
240
|
+
message = ""
|
241
|
+
with conn.cursor() as cursor:
|
242
|
+
try:
|
243
|
+
if params:
|
244
|
+
cursor.execute(sql, params)
|
245
|
+
else:
|
246
|
+
cursor.execute(sql)
|
247
|
+
|
248
|
+
logger.debug(f"[数据删除]sql: {sql}, 参数列表: {params}")
|
249
|
+
except Exception as e:
|
250
|
+
message = f"[数据删除]异常:{e}"
|
251
|
+
logger.error(message)
|
252
|
+
return False, message
|
253
|
+
|
254
|
+
return True, message
|
255
|
+
|
256
|
+
|
257
|
+
def delete_by_map(conn_map, sql, params=None):
|
258
|
+
message = ""
|
259
|
+
conn = conn_map['conn']
|
260
|
+
with conn.cursor() as cursor:
|
261
|
+
try:
|
262
|
+
if params:
|
263
|
+
cursor.execute(sql, params)
|
264
|
+
else:
|
265
|
+
cursor.execute(sql)
|
266
|
+
|
267
|
+
logger.debug(f"[数据删除]sql: {sql}, 参数列表: {params}")
|
268
|
+
except Exception as e:
|
269
|
+
message = f"[数据删除]异常:{e}"
|
270
|
+
logger.error(message)
|
271
|
+
return False, message
|
272
|
+
|
273
|
+
return True, message
|
274
|
+
|
275
|
+
|
276
|
+
def update(conn, sql, params=None):
|
277
|
+
message = ""
|
278
|
+
with conn.cursor() as cursor:
|
279
|
+
try:
|
280
|
+
if params:
|
281
|
+
cursor.execute(sql, params)
|
282
|
+
else:
|
283
|
+
cursor.execute(sql)
|
284
|
+
|
285
|
+
logger.debug(f"[数据更新]sql: {sql}, 参数列表: {params}")
|
286
|
+
except Exception as e:
|
287
|
+
message = f"[数据更新]异常:{e}"
|
288
|
+
logger.error(message)
|
289
|
+
return False, message
|
290
|
+
return True, message
|
291
|
+
|
292
|
+
|
293
|
+
def update_by_map(conn_map, sql, params=None):
|
294
|
+
message = ""
|
295
|
+
conn = conn_map['conn']
|
296
|
+
with conn.cursor() as cursor:
|
297
|
+
try:
|
298
|
+
if params:
|
299
|
+
cursor.execute(sql, params)
|
300
|
+
else:
|
301
|
+
cursor.execute(sql)
|
302
|
+
|
303
|
+
logger.debug(f"[数据更新]sql: {sql}, 参数列表: {params}")
|
304
|
+
except Exception as e:
|
305
|
+
message = f"[数据更新]异常:{e}"
|
306
|
+
logger.info(message)
|
307
|
+
return False, message
|
308
|
+
return True, message
|
309
|
+
|
310
|
+
|
311
|
+
def insert(conn, sql, params=None):
|
312
|
+
message = ""
|
313
|
+
with conn.cursor() as cursor:
|
314
|
+
try:
|
315
|
+
if params:
|
316
|
+
cursor.execute(sql, params)
|
317
|
+
else:
|
318
|
+
cursor.execute(sql)
|
319
|
+
|
320
|
+
logger.debug(f"[数据库新增]sql: {sql}, 参数列表: {params}")
|
321
|
+
|
322
|
+
except Exception as e:
|
323
|
+
message = f"[数据库新增]异常:{e}"
|
324
|
+
logger.error(message)
|
325
|
+
return False, message
|
326
|
+
|
327
|
+
return True, message
|
328
|
+
|
329
|
+
|
330
|
+
def insert_by_map(conn_map, sql, params=None):
|
331
|
+
message = ""
|
332
|
+
conn = conn_map['conn']
|
333
|
+
with conn.cursor() as cursor:
|
334
|
+
try:
|
335
|
+
if params:
|
336
|
+
cursor.execute(sql, params)
|
337
|
+
else:
|
338
|
+
cursor.execute(sql)
|
339
|
+
|
340
|
+
logger.debug(f"[数据库新增]sql: {sql}, 参数列表: {params}")
|
341
|
+
|
342
|
+
except Exception as e:
|
343
|
+
message = f"[数据库新增]异常:{e}"
|
344
|
+
logger.error(message)
|
345
|
+
return False, message
|
346
|
+
|
347
|
+
return True, message
|
348
|
+
|
349
|
+
|
350
|
+
def insert_by_dataframe(conn_map, df, table_name):
|
351
|
+
message = ""
|
352
|
+
conn = conn_map
|
353
|
+
if isinstance(conn_map, dict):
|
354
|
+
conn = conn_map['conn']
|
355
|
+
|
356
|
+
columns = df.columns.tolist() # 获得dataframe的列名
|
357
|
+
data_to_insert = [tuple(row) for row in df.to_numpy()] # dataframe转换numpy
|
358
|
+
print(data_to_insert)
|
359
|
+
with conn.cursor() as cursor:
|
360
|
+
try:
|
361
|
+
sql = df_insert2db(columns, save_table_name=table_name)
|
362
|
+
logger.debug(f"[数据库新增][dataframe]sql: {sql}")
|
363
|
+
batch_size = int(config.MAP['batch_size'])
|
364
|
+
for i in range(0, len(data_to_insert), batch_size):
|
365
|
+
batch_data = data_to_insert[i: i + batch_size]
|
366
|
+
print(batch_data)
|
367
|
+
logger.debug(f"[分批写入][dataframe]当前载入至第{min(i + batch_size, len(data_to_insert))}行。")
|
368
|
+
cursor.executemany(sql, batch_data)
|
369
|
+
conn.commit() # 批量执行query_sql, 每批次提交一次
|
370
|
+
|
371
|
+
except Exception as e:
|
372
|
+
message = f"[数据库新增][dataframe]异常:{e}"
|
373
|
+
logger.error(message)
|
374
|
+
conn.rollback()
|
375
|
+
return False, message
|
376
|
+
|
377
|
+
return True, message
|
378
|
+
|
379
|
+
|
380
|
+
def df_insert2db(columns, save_table_name):
|
381
|
+
"""
|
382
|
+
Args:
|
383
|
+
columns: 以列表的形式
|
384
|
+
save_table_name: 保存table的名字
|
385
|
+
Returns:直接的insert到Oracle的sql语句,字符串格式
|
386
|
+
"""
|
387
|
+
s = ''
|
388
|
+
for i in range(len(columns)):
|
389
|
+
s = s + columns[i] + '-'
|
390
|
+
sql_columns = s.replace('-', ',')[:-1] # 不要最后输出的逗号
|
391
|
+
sql_number_str = ''
|
392
|
+
for i in range(1, len(columns) + 1, 1):
|
393
|
+
sql_number_str = sql_number_str + ':' + str(i) + ',' # ':1,:2,:3,:4,:5,:6'
|
394
|
+
sql_number_str = sql_number_str[:-1]
|
395
|
+
query_sql = 'insert into ' + save_table_name + '(' + sql_columns + ') values(' + sql_number_str + ') '
|
396
|
+
return query_sql
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
@项目名称 : yhfin-data-agent
|
4
|
+
@文件名称 : oceanbase_extend.py
|
5
|
+
@创建人 : zhongbinjie
|
6
|
+
@创建时间 : 2025/8/14 18:42
|
7
|
+
@文件说明 :
|
8
|
+
@企业名称 : 深圳市赢和信息技术有限公司
|
9
|
+
@Copyright:2025-2035, 深圳市赢和信息技术有限公司. All rights Reserved.
|
10
|
+
"""
|
11
|
+
import jaydebeapi
|
12
|
+
|
13
|
+
def formatter(result):
|
14
|
+
data = []
|
15
|
+
if not result or not result['data']:
|
16
|
+
return data
|
17
|
+
for index, row in enumerate(result['data']):
|
18
|
+
item_map = {}
|
19
|
+
for index, item in enumerate(row):
|
20
|
+
#
|
21
|
+
# if result['desc'][index][1] == jaydebeapi.DATETIME and item is not None:
|
22
|
+
# item = texter.convert_to_oracle_datetime(item, 'TIMESTAMP')
|
23
|
+
#
|
24
|
+
# if result['desc'][index][1] == jaydebeapi.DATE and item is not None:
|
25
|
+
# item = texter.convert_to_oracle_datetime(item, 'DATE')
|
26
|
+
|
27
|
+
# if result['desc'][index][1] not in ['VARCHAR2', 'DATE']:
|
28
|
+
# print(result['desc'][index][1])
|
29
|
+
item_map[result['desc'][index][0].lower()] = item
|
30
|
+
data.append(item_map)
|
31
|
+
|
32
|
+
return data
|
33
|
+
|
34
|
+
def test_connect_oceanbase(url, user, password, driver, jarFile):
|
35
|
+
"""
|
36
|
+
测试连接 OceanBase 数据库
|
37
|
+
:param url: 数据库连接字符串
|
38
|
+
:param user: 用户名
|
39
|
+
:param password: 密码
|
40
|
+
:param driver: 驱动类名
|
41
|
+
:param jarFile: 驱动 JAR 文件路径
|
42
|
+
:return:
|
43
|
+
"""
|
44
|
+
sqlStr = """select 1 from dual"""
|
45
|
+
conn = jaydebeapi.connect(driver, url, [user, password], jarFile)
|
46
|
+
return conn
|
47
|
+
|
48
|
+
|
49
|
+
def test():
|
50
|
+
print()
|
51
|
+
|
52
|
+
|
53
|
+
if __name__ == '__main__':
|
54
|
+
# sqlStr = "SELECT * FROM user_tab_columns WHERE table_name = 'T_CHECK_LOG_TEST'"
|
55
|
+
None
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
@项目名称 : python-main
|
4
|
+
@文件名称 : oracle_extend.py
|
5
|
+
@创建人 : zhongbinjie
|
6
|
+
@创建时间 : 2025/6/7 19:06
|
7
|
+
@文件说明 :
|
8
|
+
@企业名称 : 深圳市赢和信息技术有限公司
|
9
|
+
@Copyright:2025-2035, 深圳市赢和信息技术有限公司. All rights Reserved.
|
10
|
+
"""
|
11
|
+
|
12
|
+
import oracledb
|
13
|
+
def formatter(result):
|
14
|
+
data = []
|
15
|
+
for row in result['data']:
|
16
|
+
item_map = {}
|
17
|
+
for index, item in enumerate(row):
|
18
|
+
# if result['desc'][index][1] == cx_Oracle.DATETIME and item is not None:
|
19
|
+
# item = item.strftime("%Y-%m-%d")
|
20
|
+
|
21
|
+
if result['desc'][index][1] == oracledb.TIMESTAMP and item is not None:
|
22
|
+
item = item.strftime("%Y-%m-%d %H:%M:%S")
|
23
|
+
|
24
|
+
item_map[result['desc'][index][0].lower()] = item
|
25
|
+
|
26
|
+
data.append(item_map)
|
27
|
+
return data
|