|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
# @Time : 2023/6/22 21:55
|
|
|
|
|
# @Author : old tom
|
|
|
|
|
# @File : sql_executor.py
|
|
|
|
|
# @Project : futool-db-lite
|
|
|
|
|
# @Desc : 获取游标,执行SQL
|
|
|
|
|
from sqlalchemy import text, CursorResult
|
|
|
|
|
from transaction.connect_transaction import Transaction
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SQLExecutorError(Exception):
|
|
|
|
|
def __init__(self, msg):
|
|
|
|
|
Exception.__init__(self, msg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SQLExecutor(object):
|
|
|
|
|
def __init__(self, tx: Transaction):
|
|
|
|
|
self._tx = tx
|
|
|
|
|
self._conn = tx.get_connection()
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def _format_sql(sql):
|
|
|
|
|
return text(sql)
|
|
|
|
|
|
|
|
|
|
def query(self, sql) -> CursorResult:
|
|
|
|
|
"""
|
|
|
|
|
关于auto begin官方文档给出的解释 https://docs.sqlalchemy.org/en/20/core/connections.html#commit-as-you-go
|
|
|
|
|
auto begin会导致出现: can't call begin() here unless rollback() or commit() is called first.
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
return self._conn.execute(self._format_sql(sql))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise SQLExecutorError(msg=f'{e}')
|
|
|
|
|
finally:
|
|
|
|
|
self._conn.commit()
|
|
|
|
|
|
|
|
|
|
def query_by_stream(self, sql, stream_size) -> CursorResult:
|
|
|
|
|
"""
|
|
|
|
|
流式查询
|
|
|
|
|
:param sql: sql
|
|
|
|
|
:param stream_size: 每次返回数据量
|
|
|
|
|
:return:
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
return self._conn.execution_options(yield_per=stream_size).execute(self._format_sql(sql))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise SQLExecutorError(msg=f'{e}')
|
|
|
|
|
finally:
|
|
|
|
|
self._conn.commit()
|
|
|
|
|
|
|
|
|
|
def execute_update(self, sql) -> int:
|
|
|
|
|
try:
|
|
|
|
|
rt = self._conn.execute(self._format_sql(sql))
|
|
|
|
|
return rt.rowcount
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise SQLExecutorError(msg=f'{e}')
|
|
|
|
|
|
|
|
|
|
def execute_batch(self, sql_template, data, batch_size=1000) -> int:
|
|
|
|
|
"""
|
|
|
|
|
批量执行
|
|
|
|
|
conn.exec_driver_sql(
|
|
|
|
|
"INSERT INTO table (id, value) VALUES (:id, :value)",
|
|
|
|
|
[{"id":1, "value":"v1"}, {"id":2, "value":"v2"}]
|
|
|
|
|
)
|
|
|
|
|
:return:
|
|
|
|
|
"""
|
|
|
|
|
return self._conn.exec_driver_sql(sql_template, data,
|
|
|
|
|
execution_options={'insertmanyvalues_page_size': batch_size})
|
|
|
|
|
|
|
|
|
|
def get_connection(self):
|
|
|
|
|
return self._conn
|
|
|
|
|
|
|
|
|
|
def get_transaction(self):
|
|
|
|
|
return self._tx
|