Kokuthunyelwe kwangaphambilini , sifunde ukuthi kwenzekani uma umsebenzi ohlotshiswe nge transaction.atomic
ibizwa nangokuthi kwenzekani with transaction.atomic()
. Ngokufigqiwe:
BEGIN;
ithunyelwa ku-DB (uma i-DB kuyi-PSL noma okunye okuhlukile kwe-SQL).
Manje, sizoxoxa ngokuthi yini okufanele uyifake ku-transaction nokuthi yini okufanele uyigweme. Ngenxa yokuziphatha okulandelayo kokwenziwe, imisebenzi ethile iyingozi uma ibekwe kubhulokhi yokwenziwe.
Qhubeka ufunda ukuze uthole ezinye izindlela nezibonelo zamakhodi.
Ingozi eyinhloko ukuthi okwenziwayo kubamba amalokhi kuze kube kwenziwa ukuze kuvinjelwe ukusebenza okungqubuzanayo kumathebula nemigqa futhi kuvumele okwenziwayo ukuthi kubuyiseleke emuva - lokhu kubalulekile ukwenza imisebenzi ye-DB kumsebenzi we-athomu. Lokhu kusho ukuthengiselana okuthatha isikhathi eside okusebenza kumathebula amaningi noma ambalwa abucayi kungase kubangele ukuphuma ngokuvala izingidi nokuvimbela ukufundwa/ukubhala kulawo mathebula/imigqa.
Empeleni, uma sibeka ikhodi engalungile kubhulokhi ye-transaction, singakwazi ukwehlisa i-DB ngokuvimba konke okunye ukuxhumana ne-DB ekwenzeni imisebenzi kuyo.
Ingcuphe yesibili ukuthi okwenziwayo kumele kubuyiselwe emuva futhi KULINDELEKE ukuthi kubuyiseleke emuva. I-DB ihlehlisa ngokuzenzakalelayo konke ukusebenza uma kwenzeka iphutha ekwenziweni. Ngakho-ke, imisebenzi ye-DB esiyifake ku-transaction kufanele ibuyiseleke emuva - ingxenye enkulu, asikho isidingo sokukhathazeka ngalokhu nge-PSQL. Kodwa kuthiwani ngamanye amakhodi?
Ezikhathini eziningi, lapho sishintsha idatha yethu, sidinga ukwenza imisebenzi yokulandelela efana nokudubula imicimbi, ukubuyekeza amasevisi, ukuthumela izaziso zohlelo lokusebenza, njll. Le misebenzi AYIHAMBILEKI - asikwazi ukuhlehlisa umcimbi, isicelo, noma isaziso. Uma kwenzeka iphutha, izinguquko zedatha zibuyiselwa emuva, kodwa sesivele sithumele isaziso sohlelo lokusebenza sithi, "Umbiko wakho ukhiqiziwe; chofoza lapha ukuze uwubuke." Kwenzekani uma umsebenzisi noma amanye amasevisi enza lolu lwazi olungamanga? Kuzoba nenqwaba yokwehluleka. Ngakho-ke, noma iyiphi ikhodi engakwazi ukuhlehliswa akufanele ibe sekwenziweni, noma sizibeka engcupheni yokushiya isistimu yethu ikusimo esibi uma kwenzeka iphutha kumsebenzi.
Lezi yizinto okuthi, kuye ngokuthi ingakanani idatha ecutshungulwayo kanye nethrafikhi ye-DB, engabangela ukucisha ngenxa yokubamba izingidi isikhathi eside kakhulu. Zonke lezi zinto zilungile uma zingathathi isikhathi eside.
Imibuzo enensa - Ukulanda idatha kuvame ukushesha, ngaphandle kwalezi zimo ezintathu. Le mibuzo izobambezela okwenziwayo futhi inwebise isikhathi lapho ibamba izikhiya, okuzoba nemiphumela emibi kwabanye abasebenzisi.
@transaction.atomic def process_large_order_report(start_date, end_date, min_order_value=1000): # Complex query with multiple joins and aggregations large_orders = Order.objects.filter( created_at__range=(start_date, end_date), total_amount__gte=min_order_value, status='completed' ).select_related( 'customer', 'shipping_address', 'billing_address' ).prefetch_related( 'items__product__category', 'items__product__supplier' ).annotate( item_count=Count('items'), total_weight=Sum('items__product__weight'), discount_percentage=F('discount_amount') * 100 / F('total_amount') ).filter( # Additional complex filtering Q(customer__user__is_active=True) & (Q(items__product__category__name='Electronics') | Q(items__product__category__name='Furniture')) & ~Q(shipping_address__country='US') ).order_by('-total_amount') # do the transactional work with the large_orders queryset
# fixed def process_large_order_report(start_date, end_date, min_order_value=1000): # Complex query with multiple joins and aggregations large_orders = Order.objects.filter( created_at__range=(start_date, end_date), total_amount__gte=min_order_value, status='completed' ).select_related( 'customer', 'shipping_address', 'billing_address' ).prefetch_related( 'items__product__category', 'items__product__supplier' ).annotate( item_count=Count('items'), total_weight=Sum('items__product__weight'), discount_percentage=F('discount_amount') * 100 / F('total_amount') ).filter( # Additional complex filtering Q(customer__user__is_active=True) & (Q(items__product__category__name='Electronics') | Q(items__product__category__name='Furniture')) & ~Q(shipping_address__country='US') ).order_by('-total_amount') # Start the transaction block with transaction.atomic(): # do the transactional work with the large_orders queryset
Ukusebenza kumathebula amaningi — umsebenzi osebenza kumathebula amaningi ungakhiya ithebula ngalinye uze uqedwe. Lokhu kuvame kakhulu ekufudukeni kwe-Django - esinye isizathu sokugcina ukufuduka kukuncane futhi kugxile etafuleni elilodwa noma ambalwa ngesikhathi.
class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] # too many operations operations = [ migrations.RemoveField("Author", "age"), migrations.AddField("Author", "rating", models.IntegerField(default=0)), migrations.AlterField("Book", "price", models.DecimalField(max_digits=5, decimal_places=2)), ]
# fixed # 1st migration class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] operations = [ migrations.RemoveField("Author", "age"), ] # 2nd migration class Migration(migrations.Migration): dependencies = [("migrations", "0002_initial")] operations = [ migrations.AddField("Author", "rating", models.IntegerField(default=0)), ] # 3rd migration class Migration(migrations.Migration): dependencies = [("migrations", "0003_initial")] operations = [ migrations.AlterField("Book", "price", models.DecimalField(max_digits=5, decimal_places=2)), ]
Ukufuduka Kwedatha - Njengoba okwenziwayo kubambelela kukhiye kusukela lapho umbuzo wenziwe kuze kube yilapho okwenziwayo kwehluleka noma ukuphela, ukufuduka okusebenza kuyo yonke imigqa yetafula kuzogcina kukhiya lonke itafula, noma ngokuvimbela ukufunda noma ukubhala kumugqa ngamunye.
def migrate_user_profiles(): # Get all users with legacy profiles users_with_profiles = User.objects.filter( legacy_profile__isnull=False ).select_related('legacy_profile') # Process all users in a single transaction with transaction.atomic(): # Track progress total = users_with_profiles.count() print(f"Migrating {total} user profiles...") # Process each user for i, user in enumerate(users_with_profiles): if i % 100 == 0: print(f"Processed {i}/{total} profiles") legacy = user.legacy_profile legacy.update_new_user_profile()
# fixed def migrate_user_profiles(): # Get all users with legacy profiles users_with_profiles = User.objects.filter( legacy_profile__isnull=False ).select_related('legacy_profile') # Process all users in a single transaction # Track progress total = users_with_profiles.count() print(f"Migrating {total} user profiles...") # Process each user for i, user in enumerate(users_with_profiles): if i % 100 == 0: print(f"Processed {i}/{total} profiles") with transaction.atomic(): legacy = user.legacy_profile legacy.update_new_user_profile()
Zigijime kamuva. Le mibuzo iyadingeka, KODWA Akudingekile ukuthi siyiqhube ngamahora ebhizinisi. Inqubomgomo engcono kakhulu lapha ukunciphisa ubungozi bokunqamuka ngokunquma ukuthi itafula libaluleke kangakanani, ukulinganisa ukuthi ukufuduka kungathatha isikhathi esingakanani, ukuqalisa ukuthutha lapho i-DB inethrafikhi encane, kanye nokulungiselela uhlelo lokuhlehlisa.
Nciphisa isikhathi osithathayo. Lokhu kungenziwa ngokuhlukanisa ithebula nokusebenzisa ukufuduka kuma-partitions angawodwana. PSQL Partitions & Django
*I-Django igoqa kuphela okwenziwayo mayelana nokufuduka kwe-PSQL ne-SQLite.
class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] # this migration, if on a large table, can slow down and block other operations # do it later operations = [ migrations.RemoveField("Users", "middle_name"), ]
Imisebenzi engabuyiseleki emuva — Yonke into ekwenziweni kufanele ibuyisele emuva uma umsebenzi uhlehliswa; uma sifaka ikholi ye-API kumsebenzi, ayikwazi ukuhlehliswa.
def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) async_notification_service.send_email(user.email, "You can login now!") Account.objects.create(user=user, balance=0) # rest of user creation proccess
def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess # the transaction is still in progress, so it can still be rolled back, it is not # committed until the transaction block is exited, so putting the notification here # is not a good idea - especially if the job starts immediately tries to read the data # this creates a race condition async_notification_service.send_email(user.email, "You can login now!") def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess transaction.on_commit(partial(async_notification_service.send_email, user.email, "You can login now!"))
Ukuvimba izingcingo — njengoba okwenziwayo kuvimbela yonke eminye imibuzo ukuthi isebenze kumathebula/amarowu okwenziwayo kuyashintsha, noma iyiphi ikhodi ekhulisa ubude besikhathi somsebenzi izobangela ukuthi i-DB ivalwe, kubangele ukuphela kwesikhathi nokungaphenduli ezinhlelweni zokusebenza ezincike ku-DB.
def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) for file_data in user_files: # transaction waits for this upload and so do all other connections that need access to table/rows the transaction # uses url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url) Account.objects.create(user=user, balance=0) # rest of user creation proccess
# not bad def transaction(user_data, user_files): user = None with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess for file_data in user_files: url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url) # best fix from functools import partial def transaction(user_data, user_files): user = None with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess # partials create a callable with the function and arguments # so that the function is called with the arguments when the transaction is committed # TODO: diff between partial and lambda here??? transaction.on_commit(partial(create_user_files, user_files, user)) def create_user_files(user_files, user): for file_data in user_files: url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url)
Eposini elilandelayo, sizongena ku-PSQL futhi sithole: