1c Dış kaynaklardan 8 işlem. Bir kerelik müşteriler. Tekrarlanan satın alımları elde etmek için segmentasyon. Siparişteki malların maliyeti

Seçilen işletim seçeneğinden (dosya veya istemci-sunucu) bağımsız olarak, 1C:Enterprise sistemi, bir işlem mekanizması kullanarak veritabanında depolanan bilgilerle çalışmayı sağlar.

İşlem- bu, veri tabanı üzerindeki etki açısından bölünmez bir veri işleme işlemleri dizisidir. Ya hep ya hiç esasına göre çalışır ve veritabanını bir bütünsel durumdan başka bir bütünsel duruma taşır. Herhangi bir nedenle işlem eylemlerinden biri yürütülebilir değilse veya bir tür sistem kesintisi meydana gelirse, veritabanı işlem başlamadan önceki durumuna geri döner (işlem geri alınır).

1C:Enterprise sistemi, veritabanında saklanan bilgilerin değiştirilmesiyle ilgili herhangi bir eylem gerçekleştirirken işlemleri örtülü olarak çağırır. Örneğin, veritabanı verilerinin değiştirilmesiyle ilişkili nesne ve kayıt kümesi modüllerinde bulunan tüm olay işleyicileri bir işlemde çağrılır. İşlem ayrıca aşağıdaki türdeki nesneleri de okur: Planobena Nesne, Belge -uçak konusu, referans kitabı, Planwid -Karakter ve Planword Hesaplamaları, Plan -Sayaç -konu, Board Prosedürü, Nesne, Sıkıştırıcılar, Register Kayıt, Register -Knock -Yarış, Registachgontinarinapers, Kayıt Tescili, Yeniden Raporlama , yeniden hesaplanabilir.. Bu durumda, yönetilen kilitleme modunda, kayıt kümeleri için kayıt değeri ve bağımsız bir bilgi kaydının bir kayıt kümesi için seçim değerleri ile paylaşılan bir kilit kurulur.

Bununla birlikte geliştirici, işlemlerle çalışmayı açıkça kullanabilir. Bunu yapmak için genel bağlam prosedürlerini kullanın StartTransaction(), CommitTransaction() ve CancelTransaction().

Açık İşlem Çağrısı Kullanma

Yöntem İşlemi Başlat() bir işlem açmanıza olanak tanır. Sonraki bildirimlerle veritabanı bilgilerinde yapılan tüm değişiklikler daha sonra ya tamamen kabul edilebilir ya da tamamen reddedilebilir. Yapılan tüm değişiklikleri kabul etmek için yöntemi kullanın CommitTransaction(). Açık bir işlemde yapılan tüm değişiklikleri geri almak için yöntemi kullanın. İşlemi iptal et(). Yöntem çağrılarının sayısı ise İşlemi Başlat() yöntem çağrılarının sayısını aşıyor CommitTransaction() veya İşlemi iptal et(), daha sonra sistem örtülü bir yöntem çağrısı yapacaktır İşlemi iptal et() aşağıdaki durumlarda:

● yerleşik dilin yürütülmesinin sonunda (olay işleyicisi, harici bağlantı, otomasyon sunucusu);

● kontrolü sunucudan istemciye aktarırken.

Yöntem çağrılarının sayısı ise İşlemi Tamamla() veya İşlemi iptal et() yöntem çağrılarının sayısını aşıyor İşlemi Başlat(), daha sonra gereksiz bir yöntem çağrısı gerçekleştirirken CommitTransaction() veya İşlemi iptal et() bir istisna atılacak. Böylece, bir işlemle çalışma şeması Genel görünümşöyle görünebilir:

Girişim

İşlemi Başlat();

// İfadelerin sırası

CommitTransaction();

İstisna

İşlemi iptal et();

Deneme Sonu;

Böyle bir şema kullanırken, veritabanıyla çalışırken ortaya çıkan tüm hataların sistem tarafından aynı şekilde işlenmediğini unutmamalısınız. Genel olarak tüm veritabanı hataları iki kategoriye ayrılabilir:

● kurtarılamaz,

● kurtarılabilir.

Kurtarılamaz hatalar- bunlar hatadır, meydana gelmeleri halinde 1C:Enterprise sisteminin normal işleyişi bozulabilir, örneğin veriler bozulabilir. Kurtarılamaz bir hata meydana gelirse, 1C:Enterprise sisteminin yürütülmesi her durumda sonlandırılır. Bir işlemin yürütülmesi sırasında telafisi mümkün olmayan bir hata meydana gelirse, o işlem kapsamında yapılan tüm değişiklikler sistem tarafından iptal edilir.

Kurtarılabilir hatalar- bunlar 1C:Enterprise sisteminin işleyişinde ciddi kesintilere neden olmayan hatalardır. Düzeltilebilir bir hata meydana gelirse sistemin daha fazla çalışmasına devam edilebilir. Bu durumda, doğal olarak, hataya neden olan işlemin kendisi sonlandırılır ve yapı tarafından yakalanıp işlenebilen bir istisna ortaya çıkar.

Deneme... İstisna... EndTry.

İç içe işlem çağrısı

Halihazırda devam eden bir işlem içerisinde prosedürlere erişebilirsiniz. StartTransaction(), CommitTransaction() Ve İşlemi iptal et(). Örneğin aşağıdaki çağrı düzeni kullanılabilir:

İşlemi Başlat();

İşlemi Başlat();

CommitTransaction();

// İç içe işlem çağrısı

İşlemi Başlat();

CommitTransaction();

CommitTransaction();

Ancak böyle bir çağrı, halihazırda devam eden bir işlemin içinde yeni bir işlemin başlatılması anlamına gelmez.

DİKKAT!1C:Enterprise sistemi iç içe geçmiş işlemleri desteklemez.Bu, yalnızca işlemin kendisinin her zaman geçerli olduğu anlamına gelir. Üst düzey.

Halihazırda açık olan bir işlem içinde çağrılan tüm işlemler aslında iç içe geçmiş bir işlem oluşturmak yerine aynı işlemin parçasıdır. Bu nedenle, iç içe geçmiş bir işlemde gerçekleştirilen değişikliklerin geri alınması, sonuçta iç içe geçmiş işlemin kendisindeki değişiklikleri geri almaz, bunun yerine üst düzey işlemdeki tüm değişiklikleri geri alır. Aynı zamanda iç içe geçmiş bir işlemde yapılan taahhüt değişiklikleri de göz ardı edilir.

İşlemlerin yazılım nesnelerinin çalışması üzerindeki etkisi

Genel olarak 1C:Enterprise sistemi tarafından kullanılan yazılım nesneleri, veritabanı işlemlerine karşı kesinlikle şeffaftır. Başka bir deyişle, veritabanı işlemleri yürütülürken çağrılabilir. çeşitli metodlar yazılım nesneleri ancak örneğin bir işlemi geri alırken veritabanı tarafından gerçekleştirilen eylemler genellikle ilgili işlemi etkilemez. yazılım nesneler.

Bundan, veritabanı işlemlerini iptal ederken, geliştiricinin (gerekirse) karşılık gelen verilerin verilerinde yeterli değişiklikleri bağımsız olarak sağlaması gerektiği sonucu çıkar. yazılım nesneler. Bu, tüm nesne verilerinin yeniden okunmasıyla veya program nesnesi ayrıntılarının bir kısmının değiştirilmesiyle yapılabilir.

Bu kuralın istisnaları vardır. 1C:Enterprise sisteminin yazılım nesnelerinin önemli uygulama özgüllüğü nedeniyle, bazı durumlarda veritabanında yapılan değişikliklerin geri alınması, ilgili özelliklerin değerlerini yine de etkileyebilir. yazılım nesneler. Bu, aşağıdaki durumlarda gerçekleşir:

● bir işlem iptal edildiğinde, belge deftere nakil özelliği, işlemin başlamasından önceki değeri geri yükler;

● nesne bir işlemde oluşturulmuş ve yazılmışsa, işlem geri alındığında referans değeri temizlenir;

● Nesne işlem dışında oluşturulmuşsa ve işlem içine kaydedilirken otomatik olarak oluşturulan bir kod/numara kullanılmışsa, işlem iptal edildiğinde kod/numara silinir.

2017-08-12

OM nesnelerinin bakımı için özel işlemler oluşturun.

giriiş

Pek çok işlevsel SAP danışmanının kurumsal yönetim nesnelerinin bakımı işlemiyle karşılaştığını düşünüyorum. Yani, işlem PP01

Bu işlemin kullanılması, kullanıcıya, otomatikleştirilen iş süreçlerinde kullanılan nesne türleri için kurumsal yönetim bilgi türlerini yönetme yeteneği sağlar. Çoğu zaman bu işlem, her türlü organizasyonel yönetim nesnesiyle çalışmak için tek bir giriş noktası olarak kullanılır ve bu gerçekte pek iyi bir uygulama değildir. Peki ya da pek uygun değil. Kesinlikle yaygın olmasına rağmen. Daha sonra size ne gibi bir alternatif olabileceğini anlatmaya çalışacağım.

Tablo T77S0, "TCODE" grubu

OM nesne nesnelerini ayarlarken muhtemelen aşağıdaki yolda bulunan ayara dokunacaksınız. SPRO:

IMG: Personel Yönetimi -> Organizasyonel Yönetim -> Temel Ayarlar -> Veri Modeli Geliştirme -> Nesne Türlerini Koruma

Burada yeni OM nesneleri yaratıyorsunuz, onlar için isimler buluyorsunuz, simgeleri seçiyorsunuz ve onlar için bazı ayarları tanımlıyorsunuz... Şu anda düğümle ilgileniyoruz " Nesne Türü Anahtar + İşlem"

Kurulum görünümünün bir kısmı önünüzde açılacak T77S0 filtrelenmiş grup değerleriyle

Gruba dikkat etmeye değer TCODE Yakından bakarsanız, üzerinde çalışmak zorunda kaldığınız işlemlerin teknik adlarını burada bulabilirsiniz. Ayrıca sütunda Değer belirli bir işlemin amaçlandığı nesnenin türünü belirtir.

Bu işlemlerin özelliği nedir?

Belirli bir nesne türünü korumak için tasarlanmış işlemleri kullanarak, artık bir işlemde varsayılan olarak mevcut olan bu tür nesneleri seçmenize gerek kalmaz. PP01. Yani, örneğin bir işlem başlatarak PO09, gibi nesnelerle hemen çalışmaya başlarsınız L

Kendi kurumsal yönetim nesneniz için yeni bir işlem oluşturma

Önceki yazılarımdan birinde, nasıl yeni bir OM nesnesi oluşturabileceğinizi + ona yapısal bir arama ekleyebileceğinizi anlatmıştım.

Bu malzemeden fazla uzaklaşmayacağım. Örnek olarak, bir nesnenin bakımını yapmak için yeni bir işlem oluşturacağım 91.

T77S0'da yeni bir nesne türü tanımlama

Kurulum görünümünde gelecekteki işlemin adını tanımlayın T77S0

Bu durumda "ZP91M" değeri, nesnenin bakımı için gelecekteki işlemin adıdır 91 . Değişikliklerinizi kaydedin.

OM nesnesini korumak için yeni bir işlem oluşturma

İşlem yoluyla SE93 nesnenizi korumak için bir işlem oluşturun. Aşağıda ilgili işlemi oluşturmak için gerçekleştirilmesi gereken eylemlerin sırasını içeren bir video parçası bulunmaktadır.

Alanlar için kullanılan değerleri not edin programı, Ekran Numarası,Yetkilendirme Nesnesi. Şimdi yeni bir işlem başlatın

Kullanıcı, yalnızca belirli bir anlamda kolaylık olarak adlandırılabilecek belirli bir nesne türüyle çalışma ve isterseniz istenen nesneyi seçmek için ek eylemleri en aza indirme olanağına sahiptir.

Son kez baktık en basit yol yerleşik 1C dilini kullanarak. Pratikte işlemler tasarımla birlikte çok daha sık kullanılır. Bu, bir hata durumunda kodun çalıştırılmasına devam edilmesine, ayrıca kullanıcıya yeterli bir hata mesajı sağlanmasına ve sistem yöneticisi tarafından daha sonra analiz edilmek üzere kayıt günlüğüne veya bir günlük dosyasına bilgi yazılmasına olanak tanır.

Teknik belgelere veya ITS diskine dönersek, 1C'nin bir girişimi düzenlemek için aşağıdaki yöntemi önerdiğini göreceğiz.

Girişim //1. İşlemin başlangıcı.İşlemi Başlat() ; //2. Bir işlemde gerçekleştirilen işlem bloğu. //3. Eğer tüm işlemler başarılı ise işlemi commit ediyoruz. CommitTransaction() ; İstisna //4. Kodun çalıştırılması sırasında hata oluşursa işlemi iptal edin.İşlemi iptal et() ; //5. Gerekirse kayıt defterine kaydedin. //6. Gerekirse kullanıcıya bir mesaj görüntüleyin. Deneme Sonu;

Aslında kodun özel bir açıklamaya ihtiyacı yok. Devam ediyorsa denemelerİşlem kodunu çalıştırırken bir hata oluşur, hemen bloğa düşeriz istisna yani yöntemden önce CommitTransaction() oraya varamıyoruz. İstisnai durumlarda, işlemi buna göre iptal ediyoruz ve gerekirse bir hata mesajı görüntüleyip bilgileri günlüğe yazıyoruz. Özellikle kullanıcı katılımı olmadan gerçekleştirilen işlemlerde (örneğin rutin görevler) hataların kayıt defterine kaydedilmesi oldukça arzu edilir. Bu, hatayı daha sonra analiz etmenize olanak tanır. Günlüğe kaydetme yerine mesajların yöneticiye e-postayla gönderilmesini ayarlayabilirsiniz.

Şimdi yeni bilgilerle donanmış olarak, . Rehberdeki girişi dikkate aldığımızı hatırlatmama izin verin. Mal ve bilgi kaydına Fiyat aşağıdaki şemaya göre:

&SunucudaBağlam Olmadanİşlemi Başlat() ; //yeni bir ürün kaydetÜrün = Dizinler. Mal. CreateItem() ; Ürün. Ad = "Delik Açma" ; Ürün. Yazmak() ; //fiyatını yaz RecordSet = Bilgi Kayıtları. Fiyat. CreateRecordSet() ; Yeni Kayıt = Kayıt Kümesi. Eklemek() ; Yeni Rekor. Dönem = CurrentDate() ; Yeni Rekor. Ürün = Ürün. Bağlantı; Yeni Rekor. Tutar = 100; RecordSet. Yazmak() ; CommitTransaction() ; Prosedürün Sonu

Şimdi işlemi bir bloğa koyalım İstisna Denemesi. Büyük olasılıkla, hatalar yalnızca bir dizine veya bilgi kaydına yazarken meydana gelebilir, bu nedenle ön hazırlıkİşlemin dışına alalım.

&SunucudaBağlam Olmadan Prosedür RunTransactionOnServer() //yeni bir ürün oluşturÜrün = Dizinler. Mal. CreateItem() ; Ürün. Ad = "Delik Açma" ; //Fiyat içeren bir kayıt oluşturun RecordSet = Bilgi Kayıtları. Fiyat. CreateRecordSet() ; Yeni Kayıt = Kayıt Kümesi. Eklemek() ; Yeni Rekor. Dönem = CurrentDate() ; Yeni Rekor. Tutar = 100; //Deneme sırasında işlemi yürütün StartTransaction()'ı deneme; Ürün. Yazmak() ; Yeni Rekor. Ürün = Ürün. Bağlantı; RecordSet. Yazmak() ; CommitTransaction() ; İstisna CancelTransaction() ; Mesaj = Yeni MesajToKullanıcı; İleti. Metin = ; İleti. Rapor etmek() ; GünlükKayıt( "Ürün ve fiyatı kaydedilirken hata oluştu") ); Deneme Sonu; Prosedürün Sonu

Ne yapılmamalı

İşlemlerle yeni çalışmaya başlayanlar genellikle bunu bu şekilde yapma arzusuna sahiptirler

İşlemi Başlat() ; StartTransaction()'ı deneme; //İşlem bloğu CommitTransaction() ; İstisna CancelTransaction() ; Deneme Sonu; StartTransaction()'ı deneme; //İşlem bloğu CommitTransaction() ; İstisna CancelTransaction() ; Deneme Sonu; CommitTransaction() ;

Veya bir döngüde

İşlemi Başlat() ; Veri Dizisi Döngüsünden Gelen Her Veri İçin İşlemi Başlatma Girişimi() ; Veri. Yazmak() ; CommitTransaction() ; İstisna CancelTransaction() ; Deneme Sonu; EndCycle; CommitTransaction() ;

İlk bakışta her şeyi 1C şirketinin tavsiyelerine uygun olarak yaptık. Ancak gerçek şu ki, 1C platformu iç içe geçmiş işlemleri desteklemiyor. Yani tamamen teknik olarak bu şekilde yazmak mümkündür. Ancak aynı zamanda tüm iç içe geçmiş işlemler yenilerini oluşturmaz, aynı üst düzey işleme aittir. Bu şekilde, iç içe geçmiş işlemlerden biri başarısız olursa, bir sonraki iç içe geçmiş işlem gerçekleştirilemez. Sistem şöyle bir mesaj görüntüleyecektir: “Bu işlemde zaten hatalar oluştu!”. Bunu bir örnekle gösterelim. Diyelim ki her biri kendi işleminde olan iki malı kaydetmeye karar verdik. Ve bu işlemleri üçüncünün iç içe geçmesini sağlayalım. Daha sonra, yöntemi kullanarak ilk işlemde yapay olarak bir hataya neden olacağız. İstisnayı Yükselt:

&SunucudaBağlam Olmadan Prosedür RunTransactionOnServer() StartTransaction() ; StartTransaction()'ı deneme; Ürün = Dizinler. Mal. CreateItem() ; Ürün. İsim = "Tablo"; Ürün. Yazmak() ; İstisnayı Yükselt "Ürün giriş hatası."; CommitTransaction() ; İstisna CancelTransaction() ; Mesaj = Yeni MesajToKullanıcı; İleti. Metin = ErrorDescription() AttemptStartTransaction() ; Ürün = Dizinler. Mal. CreateItem() ; Ürün. İsim = "Sandalye"; Ürün. Yazmak() ; CommitTransaction() ; İstisna CancelTransaction() ; Mesaj = Yeni MesajToKullanıcı; İleti. Metin = ErrorDescription() ; İleti. Rapor etmek() ; Deneme Sonu; CommitTransaction() ; Prosedürün Sonu

Bu işlemin gerçekleştirilmesi sonucunda mesaj penceresinde aşağıdakileri göreceğiz:

(ExternalProcessing.TransactionsAtTrying.Form.Form.Form(20)): Öğe yazılırken hata oluştu. (ExternalProcessing.TransactionsAtTrying.Form.Form.Form(40)): Bağlam yöntemini çağırırken hata (Write): Bu işlemde zaten hatalar oluştu!

Bu nedenle, 1C'de iç içe geçmiş işlemlerin düzenlenmesi kesinlikle anlamsızdır.

Olası seçenekler

Şimdi ürünü ve fiyatını kaydettiğimiz seçeneğe geri dönelim. Bir işlemi gerçekleştirirken bir hatayla karşılaşırsak, bunun hangi noktada, yani ürünü kaydederken mi yoksa fiyatı kaydederken mi gerçekleştiğini anlamak zor olacaktır çünkü her ikisi de aynı denemede meydana gelir. Hatanın nerede oluştuğunu belirlemek için her yazma işlemini kendi denemesinde sarmalamamız ve iç içe geçmiş işlemlerden kaçınmamız gerekir. Bunu yapmak için bir Boolean değişkeni tanıtıyoruz Reddetme ve tüm işlemlerin sonunda değerine bağlı olarak işlemi gerçekleştireceğiz veya iptal edeceğiz.

&SunucudaBağlam Olmadan Prosedür RunTransactionOnServer() // İşlemi başlat Reddet = Yanlış; İşlemi Başlat() ; // Ürünü kaydetmeye çalışıyoruzÜrün = Dizinleri Deneyin. Mal. CreateItem() ; Ürün. Ad = "Delik Açma" ; Ürün. Yazmak() ; İstisna Hatası = Doğru; Mesaj = Yeni MesajToKullanıcı; İleti. Metin = "Ürün kaydedilirken hata oluştu"; İleti. Rapor etmek() ; Deneme Sonu; // Fiyatı kaydetmeye çalışıyoruz AttemptRecordSet = Bilgi Kayıtları. Fiyat. CreateRecordSet() ; Yeni Kayıt = Kayıt Kümesi. Eklemek() ; Yeni Rekor. Dönem = CurrentDate() ; Yeni Rekor. Ürün = Ürün. Bağlantı; Yeni Rekor. Tutar = 100; RecordSet. Yazmak() ; İstisna Hatası = Doğru; Mesaj = Yeni MesajToKullanıcı; İleti. Metin = "Fiyat kaydedilirken hata oluştu"; İleti. Rapor etmek() ; Deneme Sonu; // İşlemi onaylayın veya iptal edin Başarısız DEĞİLSE CommitTransaction() ; Aksi takdirde CancelTransaction() ; EndIf ; Prosedürün Sonu

Bir döngüde herhangi bir veriyi yineleyip yazdığımızda da aynı şeyi yapabiliriz. Bu durumda, varsa hatalı olan tüm verilerin bir listesini elde edebileceğiz.

1C Expert sertifikasyonuna hazırlanırken, çok önemli ve küresel iki konu olan engellemenin arifesinde, yukarıdaki kavramların onsuz imkansız olduğu bir şeye, bir DBMS işlemine bakmak istiyorum.

İşlem- Mantıksal olarak birbirine bağlı, bölünemez bir eylemler dizisi. İşlem ya tamamen tamamlanabilir ya da hiç tamamlanamaz. DBMS'de bir işlemi gerçekleştirmek için COMMIT yöntemi kullanılır.

Bir işlemin tipik bir örneği transferdir Para bir hesaptan diğerine:

  1. bir işlem başlatmak;
  2. 123 numaralı hesaptaki fon miktarını okuyun;
  3. hesap bakiyesini 123 100 ruble azaltın;
  4. 123 numaralı hesap bakiyesini kaydedin;
  5. 321 numaralı hesaptaki fon miktarını okuyun;
  6. bakiyenizi 100 ruble artırın;
  7. yeni fon miktarını 321 numaralı hesaba kaydedin;
  8. işlemi gerçekleştirin.

1C'de 267 video dersini ücretsiz alın:

Görüldüğü gibi bir işlem tam olarak tamamlanmadıysa hiçbir anlamı yoktur.

İşlemsel bir DBMS için temel gereksinimler (ACID)

İşlemler ve işlemsel DBMS'ler için en yaygın gereksinim kümelerinden biri ACID (Atomiklik, Tutarlılık, Yalıtım, Dayanıklılık) kümesidir. Bunlar herhangi bir işlemin sahip olması gereken özelliklerdir:

  • Atomiklik— hiçbir işlem kısmen kaydedilmemelidir;
  • Tutarlılık- Sistem, işlem başlamadan önce tutarlı bir durumdadır ve işlem tamamlandıktan sonra da tutarlı bir durumda kalmalıdır;
  • İzolasyon- bir işlemin yürütülmesi sırasında paralel işlemler sonucunu etkilememelidir;
  • Dayanıklılık- Başarısızlık durumunda, başarıyla tamamlanan bir işlemde yapılan değişiklikler, sistem tekrar çalışmaya döndükten sonra kayıtlı kalmalıdır.

1C'deki işlemler

1C 8.3 ve 8.2'deki işlemler hem otomatik olarak oluşturulur hem de geliştiriciler tarafından tanımlanır.

Bir işlemin etkin olup olmadığını öğrenmek için TransactionActive() yöntemini kullanabilirsiniz.

Otomatik işleme bir örnek, bir belge gönderiminin işlenmesi, bir dizin öğesinin bir veritabanına yazılması, bir dizi bilgi kayıt kaydının yazılması vb.'dir.

Başlık akılda kalıcı geldi ama abartıldı. Hemen 1C hakkında konuşacağımızı söyleyeceğim. Sevgili 1C kullanıcıları, işlemlerle nasıl çalışılacağını bilmiyorsunuz ve istisnaların ne olduğunu anlamıyorsunuz. inceleyerek bu sonuca vardım çok sayıda Yerli işletmenin vahşi doğasında doğan 1C kodu. İÇİNDE tipik konfigürasyonlar bunların hepsi yeterince iyi, ancak veritabanı açısından bakıldığında korkunç miktarda özel kod beceriksizce yazılıyor. “Bu işlem zaten hatalarla karşılaştı” hatasını hiç gördünüz mü? Cevabınız evet ise makalenin başlığı sizin için de geçerlidir. Sonunda 1C ile çalışırken işlemlerin ne olduğunu ve bunların nasıl doğru şekilde ele alınacağını anlayalım.

Neden alarmı çalmalıyız?

Öncelikle "Bu işlemde hatalar zaten oluştu" hatasının ne olduğunu bulalım. Bu aslında son derece basit bir şeydir: zaten geri alınmış (iptal edilmiş) bir işlem içinde veritabanıyla çalışmaya çalışıyorsunuz. Örneğin, bir yerde CancelTransaction yöntemi çağrıldı ve siz bunu taahhüt etmeye çalışıyorsunuz.


Bu neden kötü? Çünkü bu hata size sorunun gerçekte nerede olduğu hakkında hiçbir şey söylemez. Destek, bir kullanıcıdan bu tür bir metni içeren bir ekran görüntüsü aldığında ve özellikle sunucu kodu Bir kişinin etkileşimli olarak çalışamadığı bir şey... “Kritik hata” yazmak istedim ama bunun artık kimsenin umursamadığı moda bir kelime olduğunu düşündüm… Bu bir eşek. Bu bir programlama hatasıdır. Bu rastgele bir aksaklık değil. Bu derhal düzeltilmesi gereken bir hatadır. Çünkü gece arka plan sunucu süreçleriniz çöktüğünde ve şirket hızla para kaybetmeye başladığında, teşhis günlüklerinde görmek isteyeceğiniz son şey "Bu işlemde zaten hatalar oluştu" olacaktır.


Elbette, sunucunun teknolojik günlüğünün (üretimde açık, değil mi?) bir şekilde sorunu teşhis etmeye yardımcı olma olasılığı var, ancak şu anda aklıma gelen bir seçenek düşünemiyorum - tam olarak nasıl Bu hatanın gerçek nedenini bulmak için. Ancak asıl sebep bir; programcı Vasya bir işlemde bir istisna aldı ve bir kez kötü bir fikir olmadığına karar verdi, "bir düşünün, bu bir hata, hadi devam edelim."

1C'deki işlemler nelerdir

Temel gerçekler hakkında yazmak garip ama görünüşe göre biraz gerekli olacak. 1C'deki işlemler DBMS'deki işlemlerle aynıdır. Bunlar bazı özel “1C” işlemler değil, bunlar DBMS'deki işlemlerdir. İşlemlerin genel fikrine göre ya tamamen gerçekleştirilebilir ya da hiç gerçekleştirilmeyebilir. Bir işlem sırasında veritabanı tablolarında yapılan tüm değişiklikler, sanki hiçbir şey olmamış gibi anında geri alınabilir.


Daha sonra 1C'nin iç içe işlemleri desteklemediğini anlamalısınız. Nitekim “1C'de” desteklenmiyorlar, ancak hiç desteklenmiyorlar. En azından 1C'nin çalışabileceği DBMS'ler. Örneğin iç içe geçmiş işlemler MS SQL ve Postgres'te mevcut değildir. StartTransaction'a yapılan her "iç içe" çağrı, işlem sayacını artırır ve "CommitTransaction"a yapılan her çağrı, bu sayacı azaltır. Bu davranış birçok kitap ve makalede anlatılmaktadır, ancak bu davranıştan elde edilen sonuçların yeterince analiz edilmediği görülmektedir. Açıkçası, SQL'de sözde bir şey var. SAVEPOINT, ancak 1C bunları kullanmıyor ve bu şey oldukça spesifik.



Prosedür Çok Faydalı ve Önemli Kod(Dizin Bağlantıları Listesi) StartTransaction(); Dizin Bağlantıları Listesindeki Her Bağlantı İçin Döngü Dizin Nesnesi = Link.GetObject(); Directory Object.SomeField = "Program kodundan değiştirildim"; Dizin nesnesi.Write(); EndCycle; CommitTransaction(); Prosedürün Sonu

İngilizce Kod

Tam olarak değil. Sırf kutsal savaşların ve kutsal savaşların hayranlarını eğlendirmek için İngilizce örnekleri kesinlikle çoğaltmak istemiyorum.


Muhtemelen böyle bir kod yazıyorsunuz, değil mi? Sağlanan kod örneği hatalar içeriyor. En az üç. Hangileri olduğunu biliyor musun? İlkini hemen söyleyeyim; nesne kilitleriyle ilgilidir ve doğrudan işlemlerle ilgili değildir. İkincisi hakkında - biraz sonra. Üçüncü hata, bu kodun paralel yürütülmesi sırasında ortaya çıkacak bir kilitlenmedir, ancak bu ayrı bir makalenin konusu, kodu karmaşıklaştırmamak için şimdi dikkate almayacağız. Anahtar kelime Google'da gezinmek için: kilitlenme kontrollü kilitler.


Lütfen kodun basit olduğunu unutmayın. 1C sistemlerinizde bunlardan çok var. Ve aynı anda en az 3 hata içeriyor. 1C programcılarınızın yazdığı işlemlerle çalışmak için daha karmaşık senaryolarda ne kadar hata olduğunu boş zamanınızda düşünün :)

Nesne kilitleri

Yani ilk hata. 1C'de "iyimser" ve "kötümser" olarak adlandırılan nesne kilitleri vardır. Bu terimi kimin icat ettiğini bilmiyorum, onu öldürürdüm :). Hangisinin neden sorumlu olduğunu hatırlamak kesinlikle imkansızdır. Bunlar hakkında diğer genel BT literatüründe olduğu gibi ayrıntılı olarak yazılmıştır.


Sorunun özü, belirtilen kod örneğinde bir veritabanı nesnesinin değiştirilmesidir, ancak başka bir oturumda bu nesneyi de değiştirecek etkileşimli bir kullanıcı (veya komşu bir arka plan iş parçacığı) olabilir. Burada biriniz "giriş değiştirildi veya silindi" hatasını alabilirsiniz. Etkileşimli bir oturumda bu gerçekleşirse, kullanıcı kıçını kaşıyacak, küfredecek ve formu yeniden açmaya çalışacaktır. Bu bir arka plan iş parçacığında meydana gelirse, bunu günlüklerde aramanız gerekir. Ve bildiğiniz gibi kayıt defteri yavaştır ve sektörümüzde 1C günlükleri için ELK yığınını yalnızca birkaç kişi kurmuştur... (bu arada biz de kurup başkalarının kurmasına yardımcı olanlar arasındayız :) )


Kısacası bu can sıkıcı bir hatadır ve bunu yapmamak daha iyidir. Bu nedenle, geliştirme standartları, nesneleri değiştirmeden önce "" seçeneğini kullanarak üzerlerine bir nesne kilidi yerleştirilmesi gerektiğini açıkça belirtmektedir. Dizin nesnesi.Lock()". Ardından eşzamanlı oturum (bunu da yapması gerekir) güncelleme işlemini başlatamayacak ve beklenen, kontrollü hatayı alacaktır.

Ve şimdi işlemler hakkında

İlk hatayı hallettik, şimdi ikinciye geçelim.


Bu yöntemde istisna kontrolü sağlamazsanız, o zaman bir istisna (örneğin, büyük olasılıkla "Write()" yönteminde) sizi bu durumdan çıkaracaktır. Bu method işlemi tamamlamadan. “Write” yönteminden bir istisna, çeşitli nedenlerle atılabilir; örneğin, iş mantığındaki bazı uygulama kontrollerinin tetiklenmesi veya yukarıda belirtilen nesne kilidinin meydana gelmesi. Neyse, ikinci hata şunu söylüyor: İşlemi başlatan kod, işlemin tamamlanmasından sorumlu değildir.



Ben bu soruna tam olarak bunu derim. SonarQube'u temel alan statik 1C kod analizörümüzde, bu tür teşhisleri ayrı ayrı oluşturduk. Şimdi bunun geliştirilmesi üzerinde çalışıyorum ve kodları analiz için bana gelen 1C programcılarının hayal gücü bazen beni şok ve hayrete düşürüyor...


Neden? Çünkü bir işlemin üst kısmına atılan bir istisna, vakaların %90'ında bu işlemin taahhüt edilmesine izin vermeyecek ve hataya yol açacaktır. 1C'nin tamamlanmamış bir işlemi ancak komut dosyası kodundan platform kodu düzeyine döndükten sonra otomatik olarak geri aldığı anlaşılmalıdır. 1C kod düzeyinde olduğunuz sürece işlem etkin kalır.


Çağrı yığınında bir seviye yukarı çıkalım:


Prosedür ÖnemliCode() LinkList = GetLinkList Where(); VeryUsefulAndImportantCode(LinkList); Prosedürün Sonu

Bakın ne oluyor? Sorunlu yöntemimiz dışarıdan, yığının üst kısımlarından çağrılıyor. Bu yöntem seviyesinde geliştiricinin Çok Faydalı ve Önemli Kod yöntemi içerisinde herhangi bir işlem olup olmayacağı konusunda hiçbir fikri yoktur. Varsa hepsi tamamlanacak mı... Hepimiz barış ve kapsüllenme için buradayız değil mi? "ImportantCode" yönteminin yazarı, çağırdığı yöntemin içinde tam olarak ne olduğunu düşünmemelidir. İşlemin yanlış işlendiği işlemle aynı. Sonuç olarak, bir işlem içinden bir istisna atıldıktan sonra veritabanıyla çalışma girişimi büyük olasılıkla şu sonuçla sonuçlanacaktır: "Bu işlemde falan falan..."

İşlemlerin yöntemlere yayılması

"İşlem açısından güvenli" kodun ikinci kuralı: Yöntemin başlangıcındaki ve sonundaki işlem referans sayısı aynı değere sahip olmalıdır. Bir yöntemde bir işlemi başlatıp diğerinde sonlandıramazsınız. Muhtemelen bu kuralın istisnalarını bulmak mümkündür ancak bu, daha yetkin kişiler tarafından yazılan bir tür düşük seviyeli kod olacaktır. Genel olarak bu şekilde yazamazsınız.


Örneğin:


Prosedür ÖnemliCode() LinkList = GetLinkList Where(); VeryUsefulAndImportantCode(LinkList); CommitTransaction(); // Cehenneme bir bilet, yazarla karmaşık iş ilişkilerimiz hakkında ciddi bir konuşma. Prosedürün Sonu

Yukarıdaki kabul edilemez saçmalık kodudur. Arayanın çağırdığı diğer yöntemler içindeki olası (veya kim bilir) işlemleri hatırlamasını ve takip etmesini sağlayacak yöntemler yazamazsınız. Bu, kapsüllemenin ihlali ve kişinin akıl sağlığıyla takip edilemeyen spagetti kodunun çoğalmasıdır.


Gerçek kodun sentetik 3 satırlı örneklerden çok daha büyük olduğunu hatırlamak özellikle eğlencelidir. Altı düzeydeki yerleştirmede işlemleri başlatma ve bitirmeyi bulma - bu, yazarlarla samimi sohbetleri doğrudan motive eder.

Kodu düzeltmeye çalışıyorum

Orijinal yönteme geri dönelim ve düzeltmeye çalışalım. Örnek kodu karmaşıklaştırmamak adına nesne kilidini şimdilik düzeltmeyeceğimizi hemen söyleyeyim.

Tipik bir 1C takma adının ilk yaklaşımı

Tipik olarak 1C programcıları kayıt sırasında bir istisnanın atılabileceğini bilirler. İstisnalardan da korktukları için hepsini yakalamaya çalışırlar. Örneğin şöyle:


Prosedür Çok Faydalı ve Önemli Kod(Dizin Bağlantıları Listesi) StartTransaction(); Dizin Bağlantıları Listesindeki Her Bağlantı İçin Döngü Dizin Nesnesi = Link.GetObject(); Directory Object.SomeField = "Program kodundan değiştirildim"; AttemptDirectoryObject.Write(); Exception Log.Error("%1 öğesi yazılamadı", Bağlantı); Devam etmek; Deneme Sonu; EndCycle; CommitTransaction(); Prosedürün Sonu

Şey, işler daha iyiye gitti, değil mi? Sonuçta artık olası hatalar kayıtlar işlenir ve hatta günlüğe kaydedilir. Artık bir nesne yazarken istisnalar oluşturulmayacak. Ve günlükte hangi nesnede çok tembel olmadığımı ve mesaja kısa ve öz "Dizin yazarken hata" yerine bir bağlantı eklediğimi bile görebilirsiniz, çünkü her zaman acelesi olan geliştiriciler genellikle yazmayı severler. Yani kullanıcıya yönelik bir kaygı ve yetkinliklerde artış söz konusu.


Ancak buradaki deneyimli bir 1C kullanıcısı hayır, daha iyiye gitmediğini söyleyecektir. Aslında hiçbir şey değişmedi, hatta belki daha da kötüye gitti. “Write()” yönteminde, 1C platformunun kendisi bir yazma işlemi başlatacak ve bu işlem zaten bizimkine göre iç içe geçmiş olacaktır. Ve eğer 1C veritabanıyla çalışırken işlem geri alınırsa (örneğin, bir iş mantığı istisnası atılırsa), o zaman üst düzey işlemimiz yine de "bozuk" olarak işaretlenecek ve gerçekleştirilemez. Sonuç olarak, bu kod sorunlu olmaya devam edecek ve işleme koymaya çalıştığınızda "hatalar zaten oluştu" mesajını görüntüleyecektir.


Şimdi küçük bir yöntemden değil, derin bir çağrı yığınından bahsettiğimizi hayal edin; burada en altta birisi kendi yönteminden başlatılan işlemi alıp "serbest bıraktı". Üst düzey prosedürlerin, oradaki herhangi birinin işlem başlattığından haberi olmayabilir. Sonuç olarak kodun tamamı, prensipte araştırılması imkansız olan belirsiz bir hatayla başarısız olur.


Bir işlemi başlatan kod, işlemi tamamlamak veya geri almak için gereklidir.İstisnalar ne olursa olsun. Bir yöntemin işlemi gerçekleştirmeden veya iptal etmeden çıkıp çıkmadığını görmek için her kod dalının incelenmesi gerekir.

1C'de işlemlerle çalışma yöntemleri

1C'nin işlemlerle çalışmak için bize genel olarak neler sağladığını size hatırlatmak gereksiz olmaz. Bunlar iyi bilinen yöntemlerdir:

  • İşlemi Başlat()
  • CommitTransaction()
  • İşlemi iptal et()
  • TransactionActive()

İlk 3 yöntem bellidir ve adlarının söylediğini yapar. Son yöntem, işlem sayacı sıfırdan büyükse True değerini döndürür.


Ve ilginç bir özellik var. İşlem çıkış yöntemleri (Kaydet ve İptal), işlem sayısı sıfırsa istisnalar atar. Yani bunlardan birini işlem dışında çağırırsanız hata oluşacaktır.


Bu yöntemler nasıl doğru şekilde kullanılır? Çok basit: Yukarıda formüle edilen kuralı okumalısınız:


Bu kurala nasıl uyulur? Hadi deneyelim:


Yukarıda Bir Şey Yap yönteminin potansiyel olarak tehlikeli olduğunu zaten anlamıştık. Bir tür istisna ortaya çıkarabilir ve işlem, yöntemimizin "dışarısına çıkacaktır". Tamam, olası bir istisna işleyicisini ekleyelim:


İşlemi Başlat(); DoSomething()'i deneyin; İstisna // ama buraya ne yazmalıyım? Deneme Sonu; CommitTransaction();

Harika, meydana gelen hatayı yakaladık ama bu konuda ne yapmalıyız? Günlüğe bir mesaj yazılsın mı? Peki, belki hata günlüğü kodunun tam olarak bu seviyede olması gerekir ve burada bir hata bekliyoruz. Ve değilse? Ya burada herhangi bir hata beklemiyorsak? O zaman bu istisnayı bir kenara atmalı ve mimarinin başka bir katmanının bununla ilgilenmesine izin vermeliyiz. Bu, bağımsız değişkenler olmadan "CauseException" operatörüyle yapılır. Bu Javascript'lerinizde bu, throw operatörüyle tamamen aynı şekilde yapılır.


İşlemi Başlat(); DoSomething()'i deneyin; İstisna ThrowException; Deneme Sonu; CommitTransaction();

Öyleyse bekleyin... Eğer istisnayı daha da ileri götürürsek, o zaman neden bir Denemeye ihtiyaç duyulsun ki? Nedeni şu: Kural bizi başlattığımız işlemin tamamlanmasını sağlamaya zorluyor.


İşlemi Başlat(); DoSomething()'i deneyin; ExceptionCancelTransaction(); throwException; Deneme Sonu; CommitTransaction();

Şimdi çok güzel görünüyor. Ancak Do Something() koduna güvenmediğimizi hatırlıyoruz. Ya içerideki yazar bu makaleyi okumadıysa ve işlemlerle nasıl çalışılacağını bilmiyorsa? Peki ya onu oraya götürüp CancelTransaction yöntemini çağırırsa ya da tam tersine bunu taahhüt ederse? Bu bizim için çok önemli istisna işleyicisi yeni bir istisna atmadı aksi takdirde orijinal hata kaybolacak ve sorun giderme imkansız hale gelecektir. Ayrıca, Commit ve Cancel yöntemlerinin, işlem mevcut değilse bir istisna oluşturabileceğini hatırlıyoruz. TransactionActive yönteminin kullanışlı olduğu yer burasıdır.

Son sürüm

Son olarak kodun doğru, "işlem açısından güvenli" versiyonunu yazabiliriz. İşte burada:


**UPD: Yorumlar, CommitTransaction, Attempt bloğunun içinde yer aldığında daha güvenli bir seçenek önerdi. Bu özel seçenek burada gösterilmektedir; daha önce Sabitleme, Deneme-İstisna bloğundan sonra bulunuyordu.


İşlemi Başlat(); DoSomething()'i deneyin; CommitTransaction(); İstisna If TransactionIsActive() Sonra CancelTransaction(); endIf; throwException; Deneme Sonu;

Bekle, ancak hata üretebilen yalnızca "CancelTransaction" değildir. O halde neden "CommitTransaction", "TransactionActive" ile aynı duruma getirilmiyor? Yine aynı kuralı kullanarak: İşlemi başlatan kod, işlemin tamamlanmasından sorumlu olmalıdır.İşlemimizin mutlaka ilk olması gerekmez; iç içe geçebilir. Soyutlama seviyemizde, yalnızca işlemimizle ilgilenmemiz gerekiyor. Diğerleri bizi ilgilendirmemeli. Onlar yabancı, onlardan sorumlu olmamalıyız. Kesinlikle YAPMAMALILAR. Gerçek işlem sayacı seviyesini belirlemek için hiçbir girişimde bulunulmamalıdır. Bu yine kapsüllemeyi bozacak ve işlem yönetimi mantığının "bulaşmasına" yol açacaktır. Yalnızca istisna işleyicideki etkinliği kontrol ettik ve yalnızca işleyicimizin etkin olduğundan emin olmak için kontrol ettik. eskisini “gizleyerek” yeni bir istisna oluşturmayacak.

Yeniden düzenleme kontrol listesi

Kod müdahalesi gerektiren en yaygın durumlardan bazılarına bakalım.


Model:


İşlemi Başlat(); Bir şey yap(); CommitTransaction();

Bir Deneme, Hayatta Kalma ve Bir İstisna Atma ile onu "güvenli" bir tasarımla sarın.


Model:


If NotTransactionActive() ThenStartTransaction()EndIf

Analiz ve Yeniden Düzenleme. Yazar ne yaptığını anlamadı. İç içe işlemleri başlatmak güvenlidir. Durumu kontrol etmenize gerek yoktur, sadece iç içe işlemi başlatmanız yeterlidir. Modülün altında, muhtemelen sabitlemeleri nedeniyle orada hala çarpıktır. Bu garantili hemoroiddir.


Kabaca benzer bir seçenek:


İşlem Aktifse() Sonra CommitTransaction() EndIf

benzer şekilde: bir işlemin koşula göre yapılması gariptir. Neden burada bir koşul var? Ne yani, başka birisi bu işlemi zaten kaydetmiş olabilir mi? Yargılanma nedeni.


Model:


StartTransaction() While Select.Next() Döngü // bir nesneyi referansa göre okuma // bir nesneyi yazma EndCycle; CommitTransaction();
  1. Kilitlenmeyi önlemek için kontrollü kilitlemeyi tanıtın
  2. Block yöntemine bir çağrı girin
  3. yukarıda gösterildiği gibi "dene" ifadesini sarın

Model:


StartTransaction() While Select.Next() Döngü Denemesi Object.Write(); İstisna Raporu ("Yazılamadı"); Deneme Sonu; EndCycle; CommitTransaction();

Bir istisna durumunda bu işlem artık tamamlanmayacaktır. Döngüyü sürdürmenin bir anlamı yok. Orijinal görevi kontrol ederek kodun yeniden yazılması gerekiyor. Ayrıca daha bilgilendirici bir hata mesajı sağlayın.

Nihayet

Muhtemelen tahmin ettiğiniz gibi, 1C platformunu ve onun üzerinde geliştirmeyi seven insanlardan biriyim. Elbette platformla ilgili özellikle Highload ortamında şikayetler var ama genel olarak çok kaliteli kurumsal uygulamaları ucuza ve hızlı bir şekilde geliştirmenize olanak tanıyor. Kutudan çıktığı gibi bir ORM, bir GUI, bir web arayüzü, Raporlama ve çok daha fazlasını sağlar. Habré hakkındaki yorumlarda genellikle her türlü kibirli şey yazıyorlar, bu yüzden arkadaşlar - bir ekosistem olarak 1C'nin asıl sorunu bir platform veya satıcı değil. Bu, giriş için çok düşük bir eşiktir ve bilgisayarın, veritabanının, istemci-sunucunun, ağın ve bunların hepsinin ne olduğunu anlamayan insanların sektöre girmesine olanak tanır. 1C, kurumsal uygulama geliştirmeyi çok kolaylaştırdı. 20 dakika içinde satın alma/satışlar için esnek raporlara ve bir web istemcisine sahip bir muhasebe sistemi yazabilirim. Bundan sonra kendi kendime daha büyük ölçekte hemen hemen aynı şekilde yazabileceğinizi düşünmek benim için kolay. Bir şekilde 1C her şeyi dahili olarak yapacak, nasıl olduğunu bilmiyorum ama muhtemelen yapacak. "StartTransaction()" yazayım....

Etiket ekle