flask - ohsangwon777/flask-sqlalchemy-test GitHub Wiki

๋ชจ๋ธ์˜ ์ƒํƒœ๊ฐ’๋“ค

๋ชจ๋ธ์€ ์—ฌ๋Ÿฌ ์ƒํƒœ๊ฐ’์„ ๊ฐ€์ง€๋ฉฐ session์—์„œ add, commit, delete, flush ๋“ฑ์ด ๋ฐœ์ƒํ–ˆ๋•Œ ์ƒํƒœ๊ฐ’์ด ๋ฐ”๋€๋‹ค.

transient : ์„ธ์„ ์— ์ถ”๊ฐ€๋˜์ง€ ์•Š์€ ๋ชจ๋ธ์˜ ์ƒํƒœ. ModelClass(name='aaa')๋“ฑ์œผ๋กœ ์ƒ์„ฑ๋งŒ ํ•ด๋†“์•˜๊ฑฐ๋‚˜, session์—์„œ ์ œ๊ฑฐ๋˜์—ˆ์„ ๊ฒฝ์šฐ

pending : session.add()๋กœ ์„ธ์…˜์— ์ถ”๊ฐ€ ์˜ˆ์ •์ธ ๋ชจ๋ธ์ด ๊ฐ€์ง€๋Š” ์ƒํƒœ. session.flush()๋ฅผ ํ•˜๊ฒŒ๋˜๋ฉด persistent์ƒํƒœ๋กœ ๋ฐ”๋€๋‹ค.

persistent : ์„ธ์…˜์—๋„ ์กด์žฌํ•˜๊ณ , ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—๋„ ์กด์žฌํ•˜๋Š” ๋ชจ๋ธ์ด ๊ฐ€์ง€๋Š” ์ƒํƒœ. pending์ƒํƒœ ๋ชจ๋ธ์ด flush๋˜๊ฑฐ๋‚˜, ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์ฟผ๋ฆฌ๋กœ ์กฐํšŒํ•ด์˜จ ๊ฒฝ์šฐ

detached : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ƒ์—๋Š” ์กด์žฌํ•˜์ง€๋งŒ ์„ธ์…˜์—๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ƒํƒœ. ์ถ”๊ฐ€๋กœ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ ์‹œํ‚ฌ ์ˆ˜ ์—†๋‹ค.

expired : session.commit()์ด ์‹คํ–‰๋œ ํ›„ ์„ธ์…˜์— ์žˆ๋˜ persistent์ƒํƒœ ๋ชจ๋ธ๋“ค์ด ๊ฐ€์ง€๋Š” ์ƒํƒœ. expired๋กœ ๋งˆํ‚น๋˜๋ฉด ์ƒˆ๋กœ์šด ๊ฐ’์„ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค. expire_on_commit=False์œผ๋กœ ์„ค์ • ํ•  ์ˆ˜ ์žˆ๋‹ค.(ํ ...)

scoped_session

@db_test_api.route('/request_1')
class Request_1(Resource):
    def get(self):

        logger.info('request_1 session : {}'.format(db.session))
        logger.info('request_1 session.identity_map: {}'.format(db.session.identity_map))

        return 200

@db_test_api.route('/request_2')
class Request_2(Resource):
    def get(self):

        logger.info('request_2 session : {}'.format(db.session))
        logger.info('request_2 session.identity_map: {}'.format(db.session.identity_map))

        return 200
[INFO] request_1 session : <sqlalchemy.orm.scoping.scoped_session object at 0x05AD3630>
[INFO] request_2 session : <sqlalchemy.orm.scoping.scoped_session object at 0x05AD3630>
[INFO] request_1 session.identity_map: <sqlalchemy.orm.identity.WeakInstanceDict object at 0x065C8090>
[INFO] request_2 session.identity_map: <sqlalchemy.orm.identity.WeakInstanceDict object at 0x065ACFB0>

flask-sqlalchemy ์ดˆ๊ธฐํ™” ๋ ๋•Œ scoped_session์„ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด์„œ ์„ธํŒ…ํ•ด์ค€๋‹ค.

๊ฐ ๋ฆฌํ€˜์ŠคํŠธ๋ณ„๋กœ session๊ฐ์ฒด๋Š” ๊ฐ™๋‹ค.

ํ•˜์ง€๋งŒ ๊ฐ ๋ฆฌํ€˜์ŠคํŠธ์—์„œ ์กฐํšŒํ•˜๋Š” session๊ฐ์ฒด๋“ค์€ _app_ctx_stack.__ident_func__๋กœ ๊ตฌ๋ถ„๋˜์–ด ๊ฐ๊ฐ ๋‹ค๋ฅธ scope๋ฅผ ๊ฐ€์ง„๋‹ค.

session์˜ identity_map์€ persist ์ƒํƒœ์ธ ๋ชจ๋ธ๋“ค์„ ์ €์žฅํ•œ๋‹ค.

๋‹ค๋ฅธ ์Šค์ฝ”ํ”„์˜ session์€ ์„œ๋กœ ๋‹ค๋ฅธ identity_map์„ ๊ฐ€์ง„๋‹ค.

์„ธ์…˜ ๋ณ€๊ฒฝ๊ฐ’ ์ถ”์ 

@db_test_api.route('/request_1')
class Request_1(Resource):
    def get(self):

        new_model = SessionTestModel(name='lee', desc='hoho')
        db.session.add(new_model)

        model_han = SessionTestModel.query.filter_by(name='han').first()
        model_han.desc = 'jehyun-moded'

        model_oh = SessionTestModel.query.filter_by(name='oh').first()
        db.session.delete(model_oh)

        logger.info('session.new : {}'.format(db.session.new))
        logger.info('session.dirty : {}'.format(db.session.dirty))
        logger.info('session.deleted : {}'.format(db.session.deleted))

        db.session.flush()
        logger.info('session.flush()ํ˜ธ์ถœ')

        logger.info('session.new : {}'.format(db.session.new))
        logger.info('session.dirty : {}'.format(db.session.dirty))
        logger.info('session.deleted : {}'.format(db.session.deleted))

        return 200
[INFO] session.new : IdentitySet([<SessionTestModel (transient 113757904)>])
[INFO] session.dirty : IdentitySet([<SessionTestModel 16>])
[INFO] session.deleted : IdentitySet([<SessionTestModel 1>])
[INFO] session.flush()ํ˜ธ์ถœ
[INFO] session.new : IdentitySet([])
[INFO] session.dirty : IdentitySet([])
[INFO] session.deleted : IdentitySet([])

ํ•œ ์Šค์ฝ”ํ”„์˜ ์„ธ์…˜์— ์ถ”๊ฐ€, ๋ณ€๊ฒฝ, ์‚ญ์ œ๋˜๋Š” ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค๋“ค์€ ์„ธ์…˜์˜ new, dirty, deleted์†์„ฑ๊ฐ’์œผ๋กœ ์ถ”์ /ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

new : session.add()๋กœ pending์ƒํƒœ์ธ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค๋“ค

dirty : ์†์„ฑ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ persistent์ƒํƒœ์ธ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค๋“ค

deleted : session.delete()๋กœ detached ์˜ˆ์ •์ธ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค๋“ค

flush, commit(commit์„ ํ•˜๋ฉด ๋ฐ˜๋“œ์‹œ ์ง์ „์— flush๋ฅผ ์ˆ˜ํ–‰)์‹œ ์„ธ์…˜์˜ ๋ณ€๊ฒฝ๊ฐ’์ด ์ ์šฉ๋œ๋‹ค.

flush๋ž€

@db_test_api.route('/request_1')
class Request_1(Resource):
    def get(self):

        new_model = SessionTestModel(name='han', desc='jehyun')

        db.session.add(new_model)

        logger.info('session.new : {}'.format(db.session.new))

        model = SessionTestModel.query.filter_by(name='han').first()

        logger.info('model : {}'.format(model))

        return 200
[INFO] session.new : IdentitySet([<SessionTestModel (transient 115920592)>])
[INFO] model : None
@db_test_api.route('/request_1')
class Request_1(Resource):
    def get(self):

        new_model = SessionTestModel(name='han', desc='jehyun')

        db.session.add(new_model)

        logger.info('session.new : {}'.format(db.session.new))

        # ํ”Œ๋Ÿฌ์‹œ
        db.session.flush()

        model = SessionTestModel.query.filter_by(name='han').first()

        logger.info('model : {}'.format(model))

        return 200
[INFO] session.new : IdentitySet([<SessionTestModel (transient 121364144)>])
[INFO] model : <SessionTestModel 15>
@db_test_api.route('/request_1')
class Request_1(Resource):
    def get(self):

        new_model = SessionTestModel(name='lee', desc='hoho')
        db.session.add(new_model)

        model_han = SessionTestModel.query.filter_by(name='han').first()
        model_han.desc = 'jehyun-moded'

        model_oh = SessionTestModel.query.filter_by(name='oh').first()
        db.session.delete(model_oh)

        for value in db.session.identity_map.values():
            
            logger.info(value)


        db.session.flush()
        logger.info('session.flush() ํ˜ธ์ถœ')

        for value in db.session.identity_map.values():
            
            logger.info(value)

        return 200
[INFO] <SessionTestModel 16> <-- SessionTestModel.query.filter_by(name='han').first() ์กฐํšŒ ํ›„ ์ˆ˜์ •
[INFO] <SessionTestModel 1> <-- SessionTestModel.query.filter_by(name='oh').first() ์กฐํšŒ ํ›„ ์‚ญ์ œ ์˜ˆ์•ฝ
[INFO] session.flush() ํ˜ธ์ถœ
[INFO] <SessionTestModel 16> <-- SessionTestModel.query.filter_by(name='han').first() ์ˆ˜์ •๋œ ๋ชจ๋ธ
[INFO] <SessionTestModel 24> <-- SessionTestModel(name='lee', desc='hoho') ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๋ชจ๋ธ 
                                 SessionTestModel.query.filter_by(name='oh').first() ๋Š” ์‚ญ์ œ๋จ

flush๋ฅผ ํ–ˆ์„๋•Œ๋Š” ์„ธ์…˜์˜ ORM ๋งคํ•‘์ด ๊ฐฑ์‹ ๋œ๋‹ค.

flush๋ฅผ ํ•ด๋„ DB์—๋Š” ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.