【问题标题】:Do I need to refresh the sqlalchemy connection object to be able to insert data to newly created table?我是否需要刷新 sqlalchemy 连接对象才能将数据插入到新创建的表中?
【发布时间】:2020-06-09 14:03:15
【问题描述】:

我是 sqlalchemy 的初学者。

我在_core.py

中的连接功能
from sqlalchemy import create_engine
from methodtools import lru_cache


@lru_cache(maxsize=16)
def get_engine(db="homelan"):
    qs = 'mysql+pymysql://user:pwd@localhost/{db}'.format(db=db)
    engine = create_engine(qs)
    connection = engine.connect()
    return engine, connection

如果我创建的特定主机的表不存在,则在我的代码中。如下图:

server_status.py

class HostStatusManager(object):

    keep_record = 10 # days

    """This class contains methods to manage the status of the host
    registered in database for supervision or monitoring purpose.
    """

    def __init__(self, ip_address):
        super(HostStatusManager, self).__init__()
        self._ip = ip_address
        engine, connection = _core.get_engine()
        self._engine = engine
        self._connection = connection
        self._host_table = None
        self._host_table_name = None
        if not self.host_status_table_exists():
            self._host_table = self._create_table()



    def get_status(self):
        """Gets the latest status of the host whether online or offline.
        """
        columns = self._host_table.columns
        print("Cols: ".format(columns))
        select_field = getattr(columns, "status")
        query = db.select(
                [select_field]
            ).order_by(
                db.desc(
                    getattr(columns, "id")
                    )
                ).limit(1)
        _log.debug(query)
        ResultProxy = self._connection.execute(query)
        ResultSet = ResultProxy.fetchall()
        if ResultSet:
            return ResultSet[0][0]
        _log.warning("No existing status found from {0}.".format(
            self._host_table
            )
        )

    def set_status(self, data):
        query = db.insert(self._host_table).values(**data)
        results = self._connection.execute(query)

如果我直接调用 set_status 它工作正常,但 get_status 抛出错误说:

pymysql.err.InternalError: (1412, '表定义已更改, 请重试交易')

【问题讨论】:

    标签: python sqlalchemy pymysql


    【解决方案1】:

    您不应该使用 lru 缓存来存储连接,而应该使用引擎的内置连接池。然后,每次需要与数据库通信时,向引擎请求连接,并在完成后关闭连接。默认情况下,引擎将有一个大小为 5 的池。

    from sqlalchemy import create_engine
    
    def get_engine(db="homelan"):
        qs = 'mysql+pymysql://user:pwd@localhost/{db}'.format(db=db)
        engine = create_engine(qs)
        return engine
    
    
    class HostStatusManager(object):
    
        keep_record = 10 # days
    
        """This class contains methods to manage the status of the host
        registered in database for supervision or monitoring purpose.
        """
    
        def __init__(self, ip_address):
            super(HostStatusManager, self).__init__()
            self._ip = ip_address
            engine, connection = _core.get_engine()
            self._engine = engine
            self._host_table = None
            self._host_table_name = None
            if not self.host_status_table_exists():
                self._host_table = self._create_table()
    
    
    
        def get_status(self):
            """Gets the latest status of the host whether online or offline.
            """
            columns = self._host_table.columns
            print("Cols: ".format(columns))
            select_field = getattr(columns, "status")
            query = db.select(
                    [select_field]
                ).order_by(
                    db.desc(
                        getattr(columns, "id")
                        )
                    ).limit(1)
            _log.debug(query)
            connection = self._engine.connect()
            try:
                ResultProxy = connection.execute(query)
                ResultSet = ResultProxy.fetchall()
                if ResultSet:
                    return ResultSet[0][0]
                _log.warning("No existing status found from {0}.".format(
                    self._host_table
                    )
                )
            finally:
                connection.close()
    
        def set_status(self, data):
            query = db.insert(self._host_table).values(**data)
            connection = self._engine.connect()
            try:
                results = connection.execute(query)
            finally:
                connection.close()
    
    

    【讨论】:

    • 我应该在新表创建后立即调用connection = self._engine.get_connection(),而不是尝试处理?
    • PS:我试过了:connection = self._engine.get_connection() 得到了这个错误 > AttributeError: 'Engine' object has no attribute 'get_connection'
    • 对不起,engine.connect()。我会解决的。
    • 谢谢已经用过了,try block 也不能没有 except。
    • 您说默认池大小为 5,这是否意味着对于现有连接,除非关闭,否则它仅限于 5 个事务?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    相关资源
    最近更新 更多