您好,抱歉,这是一个非常开放的问题,更像是编码建议。寻找对烧瓶项目使用sqlalchemy会话的最佳实践。找不到可以回答我问题的博客,因此请在这里提问。
我有一个烧瓶应用程序的项目结构,类似于以下内容:
---services
--- service_1.py
--- service_2.py
---models.py
---adapter.py
---app.py
所有业务逻辑都驻留在服务中。服务中的方法调用适配器中的方法以与数据库进行任何交互。
适配器是数据访问层,所有SQL查询都在其中进行。 Adaper代码如下:
from .models import *
class DBAdapter(object):
def __init__(self, session):
self._db_session = get_session() # get a sql alchemy session
def create_customer(**kwargs):
c = Customer(**kwargs)
self._db_session.add(c)
return c
.
.
.
def commit(self):
self.session.commit()
def close_session(self):
self.session.close()
服务看起来像这样:
from ..adapter import DBAdapter
class Service1(object):
def __init__(self, a):
self.a = a
self._db_adapter = DBAdapter()
def do_something(self, x, y):
if x != 10:
self.create_something(x)
self._db_adapter.commit()
self._db_adapter.close_session()
return
self._db_adapter.create_customer(y)
self._db_adapter.create_something_else(x)
self._db_adapter.commit()
self._db_adapter.close_session()
return
现在的问题是如何在每个return语句之前不重复self._db_adapter.close_session()
的情况下关闭会话。需要先在两个位置关闭一次,然后再返回条件。
是否应该以其他方式创建数据访问层DBAdapter
?
我想保持会话整洁并仅在服务初始化时创建它,因此不能将其放在烧瓶中的g对象中,
答案 0 :(得分:2)
Python有上下文管理器来处理类似的事情。考虑这样的事情:
import contextlib
@contextlib.contextmanager
def db_session():
db_adapter = None
try:
db_adapter = DBAdapter();
yield db_adapter
finally:
if db_adapter:
db_adapter.close_session()
现在您可以自动关闭会话:
with db_session() as session:
customer = session.create_customer(...)
if something is wrong:
session.rollback()
return # Exits the `with` scope, so closes session.
customer.set_name('Joe')
session.commit()
# Here session is closed.
或者您可以考虑使用一个even more convenient pattern来为您提交/回滚的
。答案 1 :(得分:2)
让会话/事务充当上下文管理器并封装来自定制/客户端程序的行为:
[BITS 16]
KERNEL_LOAD_SEGMENT EQU 0x100
;set data segment ; the code segment is already set by the jmp in real mode in the bootloader.stage2
mov ax, KERNEL_LOAD_SEGMENT
mov ds, ax
;hide cursor
mov ah, 0x01
mov cx, 0x2607
int 0x10
;move cursor at top left position
mov ah, 0x02
xor bx, bx
xor dx, dx
int 0x10
;clear screen
mov ah, 0x06
xor al, al
xor bx, bx
mov bh, 0x07
xor cx, cx
mov dh, 24
mov dl, 79
int 0x10
mov si, kernel_hello_world_string
call BIOS_print_string
;enable A20 gate
in al, 0x92
or al, 2
out 0x92, al
;disable interrupts
cli
;load gdt
lgdt [gdt_desc]
;set bit 1(32bit protected mode) in cr0
mov eax, cr0
or eax, 1
mov cr0, eax
jmp CODE_SEGMENT:main32
BIOS_print_newline:
; removed for clarity
ret
BIOS_print_string:
; removed for clarity
ret
kernel_hello_world_string:
db "[KERNEL] Hello world! Entering 32-bit protected mode", 0x0
[BITS 32]
gdt_start:
gdt_null_segment:
dq 0
gdt_code_segment:
dw 0xFFFF
dw 0x1000
db 0
db 10011010b
db 11001111b
db 0
gdt_data_segment:
dw 0xFFFF
dw 0x1000
db 0
db 10010010b
db 11001111b
db 0
gdt_end:
gdt_desc:
db gdt_end - gdt_start
dw gdt_start
CODE_SEGMENT equ gdt_code_segment - gdt_start
DATA_SEGMENT equ gdt_data_segment - gdt_start
print32:
; removed for clarity
ret
main32:
jmp $ ;;; WITH THIS JUMP THE REBOOTING IS GONE
mov ax, DATA_SEGMENT
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ebp, 0x2000
mov esp, ebp
mov ebx, message
;call print32
jmp $
message:
db "32 bit protected mode entry point", 0
;pad
times 512 - ($ - $$) db 0
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from contextlib import contextmanager
# at the module level, the global sessionmaker,
# bound to a specific Engine
Session = sessionmaker(bind=engine)
class DBAdapter:
@contextmanager
def get_session(self):
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()