2017-01-30 29 views
0

在以下可執行代碼中,您看到一個SessionScope()類。在main()中,用戶可以登錄到他的MySQL數據庫服務器。我們在課堂上看看。有兩種神奇的方法(__enter__, __exit__), ,它允許我用with -statement輕鬆使用對象。在此聲明中,您還會看到該程序使用會話。當__exit__() - 方法調用 時,會話關閉。但是我們知道會將連接返回到Engine的連接池。這意味着,它不會直接關閉連接,因爲連接是共享的,所以 。到現在爲止還挺好。在GUI一側,用戶可以選擇註銷。那麼,讓我們想象一下:經過非常非常非常長的數據庫工作,用戶希望連接真正關閉,但他不希望程序自行關閉。稍後,用戶可能會再次登錄並繼續工作。在此之前,該程序仍在運行,但未連接到數據庫 。用戶不再需要連接。Python 2.7.6:如何正確清理類?

這意味着對於python,我們不再需要SessionScope()類。在我的情況下,我們可以用del session_scope刪除/清理這個類。我的想法是重新實現__del__() - 方法。在這種方法中,我想 關閉連接池的所有連接。如果這個類被清除/刪除,所有的連接都應該斷開,這就是爲什麼我使用log_out()函數中的del的原因。

這是正確的方法嗎?

TA,你Sophus

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy.exc import SQLAlchemyError 

class SessionScope(object): 
    def __init__(self, dbms, dbdriver, dbuser, dbuser_pwd, db_server_host, dbport, db_name): 

     self.dbms = dbms 
     self.dbdriver = dbdriver 
     self.dbuser = dbuser 
     self.dbuser_pwd = dbuser_pwd 
     self.db_server_host = db_server_host 
     self.dbport = dbport 
     self.db_name = db_name 

     url = '{}+{}://{}:{}@{}:{}/{}'.format(
      self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name) 

     self.engine = create_engine(url, encoding='utf8', echo=True) 

     # store a sessionmaker for this db connection object 
     self._Session = sessionmaker(bind=self.engine) 
     self.session = None 

    def __enter__(self): 
     self.session = self._Session() 
     return self._Session() 

    def __exit__(self, exception, exc_value, traceback): 

     try: 
      if exception: 
       self.session.rollback() 
      else: 
       self.session.commit() 
     finally: 

      self.session.close() 
      self.session = None 

    def __del__(self): 
     self.engine.dispose() 

def log_out(session_scope): 
    del session_scope 

def main(): 
    dbm_system = raw_input("Which DBMS? (type for e.g. mysql): ") 
    dbm_driver = raw_input("Which db-driver? (type for e.g. pymysql): ") 
    db_host = raw_input("Server-Host: ") 
    db_user = raw_input("Database-user: ") 
    db_passwd = raw_input("User-Password: ") 
    db_name = raw_input("Database Name: ") 
    db_port = raw_input("Port: ") 

    try: 
     session_scope = SessionScope(dbm_system, dbm_driver, db_user, \ 
        db_passwd, db_host, db_port, db_name) 

     with session_scope as session: 
      # Its just for testing. 
      print session.execute("SELECT VERSION();") 

     log_out(session_scope) 

    except SQLAlchemyError as err: 
     print "ERROR", err[0] 


if __name__ == '__main__': 
    main() 

編輯#1:

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy.exc import SQLAlchemyError 

class SessionScope(object): 
    def __init__(self, engine): 

     self.engine = engine 

     # store a sessionmaker for this db connection object 
     self._Session = sessionmaker(bind=self.engine) 
     self.session = None 

    def __enter__(self): 
     self.session = self._Session() 
     return self._Session() 

    def __exit__(self, exception, exc_value, traceback): 

     try: 
      if exception: 
       self.session.rollback() 
      else: 
       self.session.commit() 
     finally: 

      self.session.close() 
      self.session = None 

class Engine(object): 
    def __init__(self, dbms, dbdriver, dbuser, dbuser_pwd, db_server_host, dbport, db_name): 

     self.dbms = dbms 
     self.dbdriver = dbdriver 
     self.dbuser = dbuser 
     self.dbuser_pwd = dbuser_pwd 
     self.db_server_host = db_server_host 
     self.dbport = dbport 
     self.db_name = db_name 

     url = '{}+{}://{}:{}@{}:{}/{}'.format(
      self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name) 

     self._Engine = create_engine(url, encoding='utf8', echo=True) 

    def __enter__(self): 
     return self._Engine 

    def __exit__(self, exception, exc_value, traceback): 
     ''' 
      Make sure the dbconnection gets closed 
     ''' 
     self._Engine.dispose() 

logged_in = True 

def main(): 

    dbm_system = raw_input("Which DBMS? (type for e.g. mysql): ") 
    dbm_driver = raw_input("Which db-driver? (type for e.g. pymysql): ") 
    db_host = raw_input("Server-Host: ") 
    db_user = raw_input("Database-user: ") 
    db_passwd = raw_input("User-Password: ") 
    db_name = raw_input("Database Name: ") 
    db_port = raw_input("Port: ") 

    try: 
     with Engine(dbm_system, dbm_driver, db_user, \ 
        db_passwd, db_host, db_port, db_name) as engine: 

      while logged_in: 
       with SessionScope(engine) as session: 
        # Its just for testing. 
        print session.execute("SELECT VERSION();") 

    except SQLAlchemyError as err: 
     print "ERROR", err[0] 


if __name__ == '__main__': 
    main() 

回答

2

__del__方法不喜歡的工作。當用戶執行del some_instance時不會調用它,但是當解釋器的垃圾回收器看到沒有對該對象的實時引用時。你的log_out方法什麼都不做,因爲它所刪除的引用是爲了將會話作爲參數傳遞給它而創建的(外部引用仍然存在)。

我懷疑你真的想擁有兩個不同的類,它們都支持上下文管理器協議。這可以讓你有兩個嵌套的with語句,它們貫穿整個登錄並且只持續每個數據庫會話的長度。事情是這樣的:

with Engine() as engine: 
    while logged_in: 
     with Session(engine) as session: 
      do_stuff() 

您可能需要外with,使您註銷後,該程序不會退出身邊另一個循環。

+0

Blckknght:首先,TA爲你提供幫助。我編輯了我的代碼的新版本(編輯#1)。這是你的意思嗎?那麼在這個新版本中,程序一直執行直到'logged_in'爲False。實際上是不可行的,因爲用戶進行了操縱。實際上我認爲while循環就足夠了,對吧? – Sophus