Tao amin'ny lahatsoratra teo aloha, dia nianatra ny zava-mitranga rehefa antsoina ny asa voaravaka transaction.atomic
ary inona no mitranga amin'ny with transaction.atomic()
. Raha fintinina:
BEGIN;
dia alefa any amin'ny DB (raha PSQL na variana SQL hafa ny DB).
Ankehitriny, hiresaka momba ny zavatra tokony hatao amin'ny fifampiraharahana sy ny tokony hialana isika. Noho ireto fitondran-tena manaraka ireto dia mampidi-doza ny hetsika sasany rehefa apetraka ao anaty sakana iray.
Tohizo ny famakiana momba ireo safidy hafa sy ohatra kaody.
Ny risika voalohany dia ny fihazonana hidin-trano ny fifampiraharahana mandra-pahavitan'izy ireo mba hisorohana ny hetsika mifanipaka eo amin'ny latabatra sy ny laharana ary mamela ny fifampiraharahana ho azo averina - ilaina izany mba hahatonga ny hetsika DB amin'ny fifampiraharahana atomika. Midika izany fa ny fifampiraharahana maharitra izay miasa amin'ny latabatra maromaro na ireo mitsikera vitsivitsy dia mety hiteraka fahatapahan-jiro amin'ny alàlan'ny fanidiana hidin-trano sy hisorohana ny famakiana/manoratra amin'ireo latabatra/lahatra ireo.
Raha ny tena izy, raha mametraka ny kaody diso ao amin'ny sakana ara-barotra isika, dia afaka manaisotra ny DB amin'ny fomba mahomby amin'ny fanakanana ny fifandraisana hafa rehetra amin'ny DB tsy hanao asa momba izany.
Ny risika faharoa dia ny fifampiraharahana dia mila azo averina ary antenaina ho azo averina. Ny DB dia mamadika ho azy ny asa rehetra raha misy hadisoana mitranga amin'ny fifanakalozana. Noho izany, ny hetsika DB napetrakay amin'ny fifampiraharahana dia tokony ho azo averina - amin'ny ankapobeny, tsy mila manahy momba izany amin'ny PSQL isika. Ahoana anefa ny amin'ny kaody hafa?
Matetika, rehefa manova ny angonay izahay dia mila manao asa fanaraha-maso toy ny fandoroana hetsika, fanavaozana ny serivisy, fandefasana fampandrenesana fanosehana, sns. TSY azo averina ireo asa ireo - tsy afaka manafoana hetsika, fangatahana, na fampahafantarana izahay. Raha misy hadisoana dia averina averina ny fiovan'ny angon-drakitra, saingy efa nandefa ny fampandrenesana fanosehana izahay manao hoe: "Voaforona ny tatitrao; kitiho eto raha hijery azy." Inona no mitranga rehefa mihetsika amin'ity vaovao diso ity ny mpampiasa na serivisy hafa? Hisy cascade ny tsy fahombiazana. Noho izany, ny kaody rehetra izay tsy azo avadika dia tsy tokony ho ao anatin'ny fifampiraharahana, na atahorana ny handao ny rafitray amin'ny toe-javatra ratsy rehefa misy lesoka amin'ny fifampiraharahana.
Ireo dia zavatra izay, miankina amin'ny habetsaky ny angona voahodina sy ny fifamoivoizana DB, dia mety hiteraka fahatapahan-jiro noho ny fitazonana hidin-trano lava loatra. Ireo rehetra ireo dia tsara raha tsy maharitra ela.
Fanontaniana miadana - Mazàna haingana ny fakana angona, afa-tsy amin'ireo tranga telo ireo. Ireo fanontaniana ireo dia hampiadana ny fifampiraharahana ary hanitarana ny fotoana ihazonana hidy, izay hisy fiantraikany ratsy amin'ny mpampiasa hafa.
@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
Fampandehanana amin'ny latabatra maromaro - ny fifampiraharahana amin'ny asa amin'ny latabatra maromaro dia afaka manidy ny latabatra tsirairay mandra-pahavitany. Manjaka indrindra amin'ny fifindra-monina Django izany — antony iray hafa hitazonana ny fifindra-monina ho kely sy hifantoka amin'ny latabatra iray na vitsivitsy isaky ny mandeha.
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)), ]
Fifindran'ny angona - Satria ny fifampiraharahana dia mitazona hidin-trano manomboka amin'ny fanatanterahana ny fangatahana mandra-pahatapitry ny fifampiraharahana, ny fifindra-monina izay miasa amin'ny andalana tsirairay ao amin'ny latabatra dia hiafara amin'ny fanakatonana ny latabatra iray manontolo, na amin'ny alàlan'ny fisorohana ny famakiana na fanoratana isaky ny laharana.
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()
Ampandehano izy ireo any aoriana. Ilaina ireo fanontaniana ireo, FA tsy mila manao izany isika mandritra ny ora fiasana. Ny politika tsara indrindra eto dia ny fampihenana ny mety hisian'ny fahatapahan-jiro amin'ny alalan'ny famaritana ny maha-zava-dehibe ny latabatra, ny fanombantombanana ny halavan'ny fifindra-monina, ny fanatanterahana ny fifindra-monina rehefa manana fifamoivoizana kely indrindra ny DB, ary ny fanomanana drafitra famerenana.
Ahena ny fotoana ilana ny fifampiraharahana. Izany dia azo atao amin'ny fisarahana ny latabatra sy ny fampandehanana ny fifindra-monina amin'ny fizarana tsirairay. PSQL Partitions & Django
* Django ihany no mamehy ny fifampiraharahana manodidina ny fifindra-monina ho an'ny PSQL sy 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"), ]
Hetsika tsy azo ivalozana - Ny zavatra rehetra ao amin'ny fifampiraharahana dia tokony ho azo averina raha toa ka averina ny fifampiraharahana; raha mametraka antso API amin'ny fifampiraharahana isika dia tsy azo averina.
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!"))
Ny fanakanana ny antso - satria ny fifampiraharahana dia manakana ny fanontaniana hafa rehetra tsy hiasa amin'ny latabatra/laharan'ny fiovan'ny fifampiraharahana, izay kaody izay mampitombo ny faharetan'ny fifampiraharahana dia hahatonga ny DB hihidy, ka miteraka fe-potoana sy tsy fandraisana andraikitra amin'ny fampiharana miankina amin'ny 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)
Amin'ny lahatsoratra manaraka, hiditra ao amin'ny PSQL isika ary hahita: