2010-05-14 2 views
14

나는이 코드가 집중적으로 사용되는 서버에서 실행되기 때문에 데이터베이스 연결이 가능한 한 많이 열리지 않도록하고 싶습니다. 여기 사람들은 이미 데이터베이스 연결을 가능한 한 빨리 닫아야한다고 말했습니다. 파이썬에서 코드 블록을 떠나기 전에 데이터베이스 연결이 항상 닫히는 지 확인하는 방법은 무엇입니까?

def do_something_that_needs_database(): 
    dbConnection = MySQLdb.connect(host=args['database_host'], user=args['database_user'], passwd=args['database_pass'], db=args['database_tabl'], cursorclass=MySQLdb.cursors.DictCursor) 
    dbCursor = dbConnection.cursor() 
    dbCursor.execute('SELECT COUNT(*) total FROM table') 
    row = dbCursor.fetchone() 
    if row['total'] == 0: 
     print 'error: table have no records' 
     dbCursor.execute('UPDATE table SET field="%s"', whatever_value) 
     return None 
    print 'table is ok' 
    dbCursor.execute('UPDATE table SET field="%s"', another_value) 

    # a lot more of workflow done here 

    dbConnection.close() 

    # even more stuff would come below 

은 그게 아니 행이 I'm still really not sure how it works 그래도, 테이블에 존재하지 않는 경우 데이터베이스 연결을 열 잎 생각합니다.

어쨌든, 내가 열 수있는 의미에서 나쁜 디자인 어쩌면 execute 각 작은 블록 후 DB 연결을 닫습니다. 그리고 물론, 내가 가지고 걱정하지 않고 DB를 그냥 ... 바로이 경우에 return 전에

close을 추가 할 수 있습니다하지만 어떻게 난 항상 제대로 닫을 수 return, 또는 raise, 또는 continue, 또는 중간에 뭐든간에? ExitingCodeBlock에 아무것도 비슷한는 예외가 나는 생각하지 않는다

def do_something_that_needs_database(): 
    dbConnection = MySQLdb.connect(host=args['database_host'], user=args['database_user'], passwd=args['database_pass'], db=args['database_tabl'], cursorclass=MySQLdb.cursors.DictCursor) 
    try: 
     dbCursor = dbConnection.cursor() 
     dbCursor.execute('SELECT COUNT(*) total FROM table') 
     row = dbCursor.fetchone() 
     if row['total'] == 0: 
      print 'error: table have no records' 
      dbCursor.execute('UPDATE table SET field="%s"', whatever_value) 
      return None 
     print 'table is ok' 
     dbCursor.execute('UPDATE table SET field="%s"', another_value) 
     # again, that same lot of line codes done here 
    except ExitingCodeBlock: 
     closeDb(dbConnection) 
    # still, that "even more stuff" from before would come below 

을 : 나는 분명히 작동하지 않는 다음과 같은 제안,처럼, try를 사용하여 유사한 코드 블록처럼 뭔가를 생각하고 있어요 이 내가 아는 그래도의 else을 시도,하지만 난 파이썬은 이미 비슷한 기능을 가지고 희망 ...

을 아니면 누군가가 나에게 패러다임의 이동을 제안 할 수 있으며,이 끔찍 말해 매우 나를 짓을하지 않을 조언 그. 어쩌면 이것은 걱정하지 않아도되고 MySQLdb가 처리 할 수있는 것일 수도 있습니다. 그렇지 않습니까?

답변

20

전통적인 접근 방식은 try/finally 성명 :

def do_something_that_needs_database(): 
    dbConnection = MySQLdb.connect(host=args['database_host'], user=args['database_user'], passwd=args['database_pass'], db=args['database_tabl'], cursorclass=MySQLdb.cursors.DictCursor) 
    try: 
     # as much work as you want, including return, raising exceptions, _whatever_ 
    finally: 
     closeDb(dbConnection) 

파이썬 2.6 (2입니다.5 from __future__ import with_statement), 대안이 있습니다 (비록 try/finally이 여전히 완벽하게 작동합니다!) : with.

with somecontext as whatever: 
    # the work goes here 

컨텍스트 엔트리에서 실행되는 __enter__ 방법을 가지고 (당신이 원하는 경우, 위의 whatever을 반환) 및 종료시 실행되는 __exit__ 방법. 우아함에도 불구하고 원하는 방식으로 작동하는 기존 컨텍스트가 없기 때문에 빌드를 수행하는 데 필요한 작업은 (으로 2.6으로 축소되었지만) 좋은 오래된 try/finally가 가장 좋습니다.

는 2.6을 가지고 contextlib을 시도 할 경우,이합니다 ... 시도/마지막을 "숨길"하는 당신이 그것을 할 수있는 한 방법입니다 :

def do_something_that_needs_database(): 
    with dbconnect(host=args['database_host'], user=args['database_user'], 
        passwd=args['database_pass'], db=args['database_tabl'], 
        cursorclass=MySQLdb.cursors.DictCursor) as dbConnection: 
     # as much work as you want, including return, raising exceptions, _whatever_ 
:

import contextlib 

@contextlib.contextmanager 
def dbconnect(**kwds): 
    dbConnection = MySQLdb.connect(**kwds) 
    try: 
    yield dbConnection 
    finally: 
    closeDb(dbConnection) 

는 다음과 같이 사용할 수

많은 것을 사용하려고 할 때 가치가있을 수 있습니다. 반복적으로 try/finally를 여러 번 반복해서 사용하지 않으려 고합니다.

+0

여러분과 Michael이 답변을 편집 한 후에 우리는 매우 유사하고 완전한 2 가지를 선택했습니다 ... 선택할 수 없습니다. – cregox

6

MySQLdb가 지원하는 경우 "with"문을 사용할 수 있습니다. "with"문은 그 이유만으로도 존재합니다. 그러나 객체가 작동하려면 __enter__ 및 __exit__을 정의해야합니다. 문의 예를 들어

... 파일을 읽기/쓰기를 들어, 당신은 할 수 있습니다 마지막으로

with open('filename','r') as file: 
    for line in file: 
     # processing.... 
# File automatically closed afterwards or if there was an exception thrown 

그것을 지원하지 않는 경우, 당신은 항상 시도 사용할 수 있습니다 ... 등 지역 :

try: 
    # Do some processing 
finally: 
    # Cleanup 

최종적으로 절에 상관없이 실행되지 않습니다 방법을 시도 완료 (가 성공적인 완료, 또는 예외가 전파하지만 잡은, 또는 예외가 발생되고 전파 계속 여부).

+0

나는 최근에 pyodbc로 시도해 보았지만 제대로 작동하지 않았지만 운이 좋을 수도 있습니다. –

+1

특정 객체가 이미 그것을 지원하지 않는다면 wrapper에서 적절한 호출을 작성하기가 너무 어렵지 않아야합니다. 인용 된 펩은 파일을 어떻게 처리하는지 보여줍니다. –

+1

매우 흥미로운 일이지만, MySQLdb가 지원하지 않는다고 생각합니다. Python 2.5가 아닙니다. – cregox

관련 문제