heim - Windows
„Es ist keine Transaktion aktiv. Problem mit verknüpften SQLNCLI-Servern

Der Titel wirkte eingängig, aber es kochte über. Ich sage gleich, dass wir über 1C sprechen werden. Liebe 1C-Benutzer, Sie wissen nicht, wie man mit Transaktionen arbeitet und verstehen nicht, was Ausnahmen sind. Ich bin zu diesem Schluss gekommen, indem ich eine große Menge 1C-Code durchgesehen habe, der in der Wildnis des inländischen Unternehmens generiert wurde. In typischen Konfigurationen ist das alles ganz gut, aber eine erschreckende Menge an benutzerdefiniertem Code ist im Hinblick auf die Arbeit mit der Datenbank inkompetent geschrieben. Haben Sie schon einmal die Fehlermeldung „Bei dieser Transaktion sind bereits Fehler aufgetreten“ gesehen? Wenn ja, dann trifft der Titel des Artikels auch auf Sie zu. Lassen Sie uns endlich verstehen, was Transaktionen sind und wie man sie bei der Arbeit mit 1C richtig verarbeitet.

Warum sollten wir Alarm schlagen?

Lassen Sie uns zunächst herausfinden, was der Fehler „Bei dieser Transaktion sind bereits Fehler aufgetreten“ ist. Das ist in der Tat eine äußerst einfache Sache: Sie versuchen, mit der Datenbank innerhalb einer bereits zurückgesetzten (abgebrochenen) Transaktion zu arbeiten. Beispielsweise wurde irgendwo die Methode „CancelTransaction“ aufgerufen und Sie versuchen, sie festzuschreiben.


Warum ist das schlimm? Denn dieser Fehler sagt nichts darüber aus, wo das Problem tatsächlich aufgetreten ist. Wenn ein Screenshot mit einem solchen Text von einem Benutzer zur Unterstützung kommt, und insbesondere für Servercode, mit dem niemand interaktiv interagieren kann, ist es... Ich wollte „kritischer Fehler“ schreiben, aber ich dachte, es sei ein Schlagwort, das niemand bezahlt Aufmerksamkeit auf mehr... Das ist ein Arsch. Dies ist ein Programmierfehler. Dies ist kein zufälliger Fehler. Dies ist ein Fehler, der sofort behoben werden muss. Denn wenn Ihre Hintergrundserverprozesse nachts ausfallen und das Unternehmen schnell Geld verliert, dann ist „Bei dieser Transaktion sind bereits Fehler aufgetreten“ das Letzte, was Sie in den Diagnoseprotokollen sehen möchten.


Es besteht natürlich die Möglichkeit, dass das Technologieprotokoll des Servers (es ist in der Produktion aktiviert, oder?) irgendwie dabei hilft, das Problem zu diagnostizieren, aber im Moment fällt mir spontan keine Option ein – wie genau darin die wahre Ursache dieses Fehlers zu finden. Aber der wahre Grund ist einer: Der Programmierer Vasya erhielt eine Ausnahme innerhalb einer Transaktion und entschied, dass das einmal keine schlechte Idee sei: „Denk einfach nach, es ist ein Fehler, lass uns weitermachen.“

Was sind Transaktionen in 1C?

Es ist umständlich, über elementare Wahrheiten zu schreiben, aber anscheinend wird ein wenig nötig sein. Transaktionen in 1C sind die gleichen wie Transaktionen in einem DBMS. Hierbei handelt es sich nicht um spezielle „1C“-Transaktionen, sondern um Transaktionen im DBMS. Nach der allgemeinen Vorstellung von Transaktionen können diese entweder vollständig oder gar nicht ausgeführt werden. Alle innerhalb einer Transaktion vorgenommenen Änderungen an Datenbanktabellen können sofort rückgängig gemacht werden, als wäre nichts passiert.


Als nächstes müssen Sie verstehen, dass 1C keine verschachtelten Transaktionen unterstützt. Tatsächlich werden sie „in 1C“ nicht unterstützt, aber überhaupt nicht. Zumindest die DBMS, mit denen 1C arbeiten kann. Verschachtelte Transaktionen gibt es beispielsweise in MS SQL und Postgres nicht. Jeder „verschachtelte“ Aufruf von StartTransaction erhöht einfach den Transaktionszähler und jeder Aufruf von „CommitTransaction“ verringert diesen Zähler einfach. Dieses Verhalten wird in vielen Büchern und Artikeln beschrieben, die Schlussfolgerungen aus diesem Verhalten werden jedoch offenbar nicht ausreichend analysiert. Streng genommen gibt es in SQL ein sogenanntes. SAVEPOINT, aber 1C verwendet sie nicht, und diese Sache ist ziemlich spezifisch.



Prozedur Sehr nützlicher und wichtiger Code (Liste der Verzeichnislinks) StartTransaction(); Für jeden Link aus der Liste der Verzeichnis-Links Schleife Directory Object = Link.GetObject(); Directory Object.SomeField = „Ich wurde vom Programmcode geändert“; Verzeichnisobjekt.Write(); EndCycle; CommitTransaction(); Ende des Verfahrens

Code auf Englisch

Nicht wirklich. Ich möchte auf keinen Fall Beispiele auf Englisch duplizieren, nur um Fans von Heiligen Kriegen und Heiligen Kriegen zu unterhalten.


Du schreibst wahrscheinlich Code wie diesen, oder? Das bereitgestellte Codebeispiel enthält Fehler. Mindestens drei. Wissen Sie welche? Zum ersten möchte ich gleich sagen: Es bezieht sich auf Objektsperren und nicht direkt auf Transaktionen. Etwa im zweiten – etwas später. Der dritte Fehler ist ein Deadlock, der während der parallelen Ausführung dieses Codes auftritt. Dies ist jedoch ein Thema für einen separaten Artikel. Wir werden ihn jetzt nicht berücksichtigen, um den Code nicht zu komplizieren. Stichwort bei Google: Deadlock-gesteuerte Schlösser.


Bitte beachten Sie, dass der Code einfach ist. Davon gibt es in Ihren 1C-Systemen einfach viel. Und es enthält mindestens 3 Fehler gleichzeitig. Denken Sie in Ihrer Freizeit darüber nach, wie viele Fehler es in komplexeren Szenarien für die Arbeit mit Transaktionen gibt, die von Ihren 1C-Programmierern geschrieben wurden :)

Objektsperren

Also der erste Fehler. In 1C gibt es Objektsperren, die sogenannten „optimistischen“ und „pessimistischen“. Ich weiß nicht, wer den Begriff erfunden hat, ich hätte ihn getötet :). Es ist absolut unmöglich, sich daran zu erinnern, wer von ihnen wofür verantwortlich ist. Über sie wurde ausführlich und auch in anderer allgemeiner IT-Literatur geschrieben.


Der Kern des Problems besteht darin, dass im angegebenen Codebeispiel ein Datenbankobjekt geändert wird, in einer anderen Sitzung jedoch möglicherweise ein interaktiver Benutzer (oder ein benachbarter Hintergrundthread) vorhanden ist, der dieses Objekt ebenfalls ändert. Hier erhält einer von Ihnen möglicherweise die Fehlermeldung „Der Eintrag wurde geändert oder gelöscht.“ Wenn dies in einer interaktiven Sitzung passiert, kratzt sich der Benutzer an der Rübe, flucht und versucht, das Formular erneut zu öffnen. Wenn dies in einem Hintergrundthread passiert, müssen Sie in den Protokollen danach suchen. Und das Logbuch ist, wie Sie wissen, langsam, und nur wenige Leute in unserer Branche haben den ELK-Stack für 1C-Logs eingerichtet ... (wir gehören übrigens zu denen, die es eingerichtet haben und anderen bei der Einrichtung helfen :) )


Kurz gesagt, das ist ein ärgerlicher Fehler und es ist besser, ihn nicht zu machen. Daher legen die Entwicklungsstandards klar fest, dass vor dem Ändern von Objekten eine Objektsperre mit dem Befehl „ Verzeichnisobjekt.Lock()". Dann kann die gleichzeitige Sitzung (die dies auch tun muss) den Aktualisierungsvorgang nicht starten und erhält den erwarteten, kontrollierten Fehler.

Und nun zu den Transaktionen

Wir haben uns mit dem ersten Fehler befasst, kommen wir zum zweiten.


Wenn Sie in dieser Methode keine Ausnahmeprüfung bereitstellen, führt eine Ausnahme (z. B. sehr wahrscheinlich in der Methode „Write()“) dazu, dass Sie diese Methode verlassen ohne die Transaktion abzuschließen. Eine Ausnahme von der „Write“-Methode kann aus verschiedenen Gründen ausgelöst werden, beispielsweise werden einige Anwendungsprüfungen in der Geschäftslogik ausgelöst oder es tritt die oben erwähnte Objektsperre auf. Wie dem auch sei, der zweite Fehler lautet: Der Code, der die Transaktion gestartet hat, ist nicht für deren Abschluss verantwortlich.



Genau so würde ich dieses Problem bezeichnen. In unserem statischen 1C-Codeanalysator auf Basis von SonarQube haben wir eine solche Diagnose sogar separat eingebaut. Jetzt arbeite ich an seiner Entwicklung, und die Fantasie der 1C-Programmierer, deren Code zur Analyse zu mir kommt, versetzt mich manchmal in Schock und Ehrfurcht ...


Warum? Denn eine oben innerhalb einer Transaktion ausgelöste Ausnahme lässt in 90 % der Fälle nicht zu, dass diese Transaktion festgeschrieben wird, und führt zu einem Fehler. Es versteht sich, dass 1C eine nicht abgeschlossene Transaktion erst dann automatisch zurücksetzt, wenn vom Skriptcode auf die Ebene des Plattformcodes zurückgekehrt ist. Solange Sie sich auf der 1C-Codeebene befinden, bleibt die Transaktion aktiv.


Gehen wir im Aufrufstapel eine Ebene nach oben:


Prozedur ImportantCode() LinkList = GetLinkListWhere(); VeryUsefulAndImportantCode(LinkList); Ende des Verfahrens

Schauen Sie, was passiert. Unsere problematische Methode wird von irgendwo außerhalb, weiter oben im Stapel, aufgerufen. Auf der Ebene dieser Methode hat der Entwickler keine Ahnung, ob es innerhalb der Methode „Very Useful and Important Code“ Transaktionen geben wird oder nicht. Und wenn ja, werden sie alle fertiggestellt ... Wir sind alle hier, um Frieden und Abgeschiedenheit zu finden, oder? Der Autor der Methode „ImportantCode“ sollte nicht darüber nachdenken, was genau in der von ihm aufgerufenen Methode passiert. Dasselbe, bei dem die Transaktion falsch verarbeitet wird. Daher wird ein Versuch, mit der Datenbank zu arbeiten, nachdem eine Ausnahme innerhalb einer Transaktion ausgelöst wurde, höchstwahrscheinlich zu Folgendem führen: „In dieser Transaktion bla bla ...“

Transaktionen auf verschiedene Methoden verteilen

Die zweite Regel für „transaktionssicheren“ Code: Der Transaktionsreferenzzähler am Anfang und am Ende der Methode muss den gleichen Wert haben. Sie können eine Transaktion nicht mit einer Methode starten und mit einer anderen beenden. Es ist wahrscheinlich möglich, Ausnahmen von dieser Regel zu finden, aber es handelt sich dabei um eine Art Low-Level-Code, der von kompetenteren Leuten geschrieben wurde. Im Allgemeinen kann man so nicht schreiben.


Zum Beispiel:


Prozedur ImportantCode() LinkList = GetLinkListWhere(); VeryUsefulAndImportantCode(LinkList); CommitTransaction(); // Eine Fahrkarte zur Hölle, ein ernstes Gespräch mit dem Autor über unsere komplexen Arbeitsbeziehungen. Ende des Verfahrens

Das Obige ist ein inakzeptabler Scheißcode. Sie können Methoden nicht so schreiben, dass sich der Aufrufer an mögliche (oder wahrscheinliche – wer weiß) Transaktionen innerhalb anderer Methoden, die er aufruft, erinnert und diese im Auge behält. Dies ist ein Verstoß gegen die Kapselung und eine Verbreitung von Spaghetti-Code, die nicht mit gesundem Menschenverstand nachvollzogen werden kann.


Es macht besonders Spaß, sich daran zu erinnern, dass der echte Code viel größer ist als die synthetischen dreizeiligen Beispiele. Die Suche nach Start- und Endtransaktionen auf sechs Verschachtelungsebenen motiviert direkt zu intimen Gesprächen mit den Autoren.

Versuche den Code zu reparieren

Kehren wir zur ursprünglichen Methode zurück und versuchen, das Problem zu beheben. Ich sage gleich, dass wir die Objektsperre vorerst nicht reparieren werden, nur um den Beispielcode nicht zu komplizieren.

Der erste Ansatz eines typischen 1C-Spitznamens

Normalerweise wissen 1C-Programmierer, dass beim Aufzeichnen eine Ausnahme ausgelöst werden kann. Sie haben auch Angst vor Ausnahmen und versuchen, sie alle zu erwischen. Zum Beispiel so:


Prozedur Sehr nützlicher und wichtiger Code (Liste der Verzeichnislinks) StartTransaction(); Für jeden Link aus der Liste der Verzeichnis-Links Schleife Directory Object = Link.GetObject(); Directory Object.SomeField = „Ich wurde vom Programmcode geändert“; AttemptDirectoryObject.Write(); Ausnahme Log.Error("Element %1 konnte nicht geschrieben werden", Link); Weitermachen; EndAttempt; EndCycle; CommitTransaction(); Ende des Verfahrens

Nun ja, die Dinge sind besser geworden, oder? Schließlich werden nun mögliche Aufzeichnungsfehler verarbeitet und sogar protokolliert. Beim Schreiben eines Objekts werden keine Ausnahmen mehr ausgelöst. Und im Log kann man sogar sehen, auf welchem ​​Objekt ich mich nicht zu faul gemacht habe und statt des lakonischen „Fehlers beim Schreiben eines Verzeichnisses“, wie Entwickler, die immer in Eile sind, gerne schreiben, einen Link in die Nachricht eingefügt haben. Mit anderen Worten: Es kommt zu einer Sorge um den Nutzer und zu einem Kompetenzzuwachs.


Ein erfahrener 1C-Benutzer hier wird jedoch sagen: Nein, es ist nicht besser geworden. Tatsächlich hat sich nichts geändert, vielleicht sogar noch schlimmer. Bei der Methode „Write()“ startet die 1C-Plattform selbst eine Schreibtransaktion, und diese Transaktion ist bereits in Bezug auf unsere verschachtelt. Und wenn während der Arbeit mit der 1C-Datenbank die Transaktion zurückgesetzt wird (z. B. wird eine Geschäftslogik-Ausnahme ausgelöst), wird unsere Transaktion der obersten Ebene weiterhin als „beschädigt“ markiert und kann nicht festgeschrieben werden. Infolgedessen bleibt dieser Code problematisch und wenn Sie versuchen, ihn festzuschreiben, wird die Meldung „Es sind bereits Fehler aufgetreten“ angezeigt.


Stellen Sie sich nun vor, wir sprechen nicht von einer kleinen Methode, sondern von einem tiefen Aufrufstapel, bei dem ganz unten jemand die gestartete Transaktion von seiner Methode übernommen und „freigegeben“ hat. Die Verfahren auf oberster Ebene haben möglicherweise keine Ahnung, dass dort unten jemand Transaktionen gestartet hat. Infolgedessen schlägt der gesamte Code mit einem vagen Fehler fehl, der im Prinzip nicht untersucht werden kann.


Der Code, der eine Transaktion startet, ist erforderlich, um sie abzuschließen oder rückgängig zu machen. Unabhängig von etwaigen Ausnahmen. Jeder Codezweig sollte untersucht werden, um festzustellen, ob eine Methode beendet wird, ohne die Transaktion festzuschreiben oder abzubrechen.

Methoden zum Arbeiten mit Transaktionen in 1C

Es wäre nicht überflüssig, Sie daran zu erinnern, was uns 1C im Allgemeinen für die Arbeit mit Transaktionen bietet. Dies sind die bekannten Methoden:

  • StartTransaction()
  • CommitTransaction()
  • CancelTransaction()
  • TransactionActive()

Die ersten drei Methoden sind offensichtlich und tun, was ihr Name verspricht. Die letzte Methode gibt True zurück, wenn der Transaktionszähler größer als Null ist.


Und es gibt eine interessante Funktion. Die Transaktions-Exit-Methoden (Commit und Cancel) lösen Ausnahmen aus, wenn die Transaktionsanzahl Null ist. Das heißt, wenn Sie einen von ihnen außerhalb einer Transaktion aufrufen, tritt ein Fehler auf.


Wie wendet man diese Methoden richtig an? Es ist ganz einfach: Sie müssen die oben formulierte Regel lesen:


Wie kann diese Regel eingehalten werden? Lass es uns versuchen:


Wir haben oben bereits verstanden, dass die Do Something-Methode potenziell gefährlich ist. Es kann eine Ausnahme auslösen und die Transaktion wird aus unserer Methode „herauskriechen“. Okay, fügen wir einen möglichen Ausnahmehandler hinzu:


StartTransaction(); Versuchen Sie DoSomething(); Ausnahme // aber was soll ich hier schreiben? EndAttempt; CommitTransaction();

Großartig, wir haben den aufgetretenen Fehler erkannt, aber was sollen wir dagegen tun? Eine Nachricht ins Protokoll schreiben? Nun, vielleicht sollte der Fehlerprotokollierungscode genau auf dieser Ebene liegen und wir hier auf einen Fehler warten. Und wenn nicht? Was wäre, wenn wir hier keine Fehler erwarten würden? Dann sollten wir diese Ausnahme einfach weitergeben und eine andere Schicht der Architektur damit beauftragen. Dies geschieht mit dem Operator „CauseException“ ohne Argumente. In Ihren Javascripts geschieht dies genauso mit dem Throw-Operator.


StartTransaction(); Versuchen Sie DoSomething(); Ausnahme ThrowException; EndAttempt; CommitTransaction();

Also, warten Sie ... Wenn wir die Ausnahme einfach weiter auslösen, warum ist dann überhaupt ein Versuch erforderlich? Hier ist der Grund: Die Regel zwingt uns, den Abschluss der von uns begonnenen Transaktion sicherzustellen.


StartTransaction(); Versuchen Sie DoSomething(); ExceptionCancelTransaction(); throwException; EndAttempt; CommitTransaction();

Jetzt scheint es wunderschön zu sein. Wir erinnern uns jedoch daran, dass wir dem Do Something()-Code nicht vertrauen. Was wäre, wenn der Autor diesen Artikel nicht gelesen hätte und nicht wüsste, wie man mit Transaktionen umgeht? Was wäre, wenn er es dorthin bringen und die Methode „CancelTransaction“ aufrufen oder es im Gegenteil festschreiben würde? Das ist uns sehr wichtig Der Ausnahmebehandler hat keine neue Ausnahme ausgelöst Andernfalls geht der ursprüngliche Fehler verloren und eine Fehlerbehebung wird unmöglich. Und wir erinnern uns, dass die Methoden „Commit“ und „Cancel“ eine Ausnahme auslösen können, wenn die Transaktion nicht existiert. Hier bietet sich die TransactionActive-Methode an.

Endgültige Version

Schließlich können wir die richtige, „transaktionssichere“ Version des Codes schreiben. Da ist er:


**UPD: Die Kommentare schlugen eine sicherere Option vor, wenn sich CommitTransaction innerhalb des Attempt-Blocks befindet. Diese spezielle Option wird hier angezeigt; zuvor befand sich Fixation nach dem Attempt-Exception-Block.


StartTransaction(); Versuchen Sie DoSomething(); CommitTransaction(); Exception If TransactionIsActive() Then CancelTransaction(); endIf; throwException; EndAttempt;

Warten Sie, aber nicht nur „CancelTransaction“ kann zu Fehlern führen. Warum wird „CommitTransaction“ dann nicht in die gleiche Bedingung eingeschlossen wie „TransactionActive“? Wiederum mit der gleichen Regel: Der Code, der die Transaktion gestartet hat, sollte für deren Abschluss verantwortlich sein. Unsere Transaktion ist nicht unbedingt die allererste; sie kann verschachtelt werden. Auf unserer Abstraktionsebene müssen wir uns nur um unsere Transaktion kümmern. Alle anderen sollten für uns uninteressant sein. Sie sind Fremde, wir sollten nicht für sie verantwortlich sein. Genau genommen sollten sie es nicht tun. Es sollte kein Versuch unternommen werden, den tatsächlichen Transaktionszählerstand zu ermitteln. Dadurch wird die Kapselung erneut unterbrochen und es kommt zu einer „Verschmierung“ der Transaktionsverwaltungslogik. Wir haben nur die Aktivität im Ausnahmehandler überprüft und nur, um sicherzustellen, dass unser Handler generiert keine neue Ausnahme und „versteckt“ die alte.

Refactoring-Checkliste

Schauen wir uns einige der häufigsten Situationen an, die einen Codeeingriff erfordern.


Muster:


StartTransaction(); Etwas tun(); CommitTransaction();

Verpacken Sie es mit Attempt, Keep Alive und Throw an Exception in ein „sicheres“ Design.


Muster:


Wenn NotTransactionActive() ThenStartTransaction()EndIf

Analyse und Refactoring. Der Autor verstand nicht, was er tat. Es ist sicher, verschachtelte Transaktionen zu starten. Es ist nicht erforderlich, die Bedingung zu überprüfen, sondern lediglich die verschachtelte Transaktion zu starten. Unterhalb des Moduls ist es dort vermutlich noch durch deren Fixierung verzerrt. Das ist garantiert Hämorrhoiden.


Eine ungefähr ähnliche Option:


Wenn Transaction Active() ist, dann CommitTransaction() EndIf

Ebenso: Es ist seltsam, eine Transaktion anhand einer Bedingung zu begehen. Warum liegt hier eine Bedingung vor? Was, jemand anderes könnte diese Transaktion bereits aufgezeichnet haben? Grund für den Prozess.


Muster:


StartTransaction() While Select.Next() Loop // Ein Objekt anhand einer Referenz lesen // Ein Objekt schreiben EndCycle; CommitTransaction();
  1. Führen Sie eine kontrollierte Sperre ein, um einen Deadlock zu vermeiden
  2. Geben Sie einen Aufruf der Block-Methode ein
  3. Wickeln Sie „try“ ein, wie oben gezeigt

Muster:


StartTransaction() While Select.Next()-Schleife Versuchen Sie Object.Write(); Ausnahmebericht("Schreiben fehlgeschlagen"); EndAttempt; EndCycle; CommitTransaction();

Diese Transaktion wird im Ausnahmefall nicht mehr abgeschlossen. Es hat keinen Sinn, den Zyklus fortzusetzen. Der Code muss neu geschrieben werden, wobei die ursprüngliche Aufgabe überprüft wird. Geben Sie außerdem eine informativere Fehlermeldung an.

Abschließend

Ich gehöre, wie Sie wahrscheinlich schon vermutet haben, zu den Menschen, die die 1C-Plattform und die Entwicklung darauf lieben. Natürlich gibt es Kritik an der Plattform, insbesondere im Highload-Umfeld, aber im Allgemeinen ermöglicht sie die kostengünstige und schnelle Entwicklung sehr hochwertiger Unternehmensanwendungen. Bereitstellung eines sofort einsatzbereiten ORM, einer GUI, einer Webschnittstelle, Berichterstellung und vielem mehr. In den Kommentaren zu Habré schreiben sie normalerweise alle möglichen arroganten Dinge, also Leute – das Hauptproblem bei 1C als Ökosystem ist weder eine Plattform noch ein Anbieter. Dies ist eine zu niedrige Eintrittsschwelle, die es Menschen ermöglicht, in die Branche einzusteigen, die nicht verstehen, was ein Computer, eine Datenbank, ein Client-Server, ein Netzwerk und all das ist. 1C hat die Entwicklung von Unternehmensanwendungen zu einfach gemacht. In 20 Minuten kann ich ein Buchhaltungssystem für Einkäufe/Verkäufe mit flexiblen Berichten und einem Web-Client schreiben. Danach fällt es mir leicht, zu denken, dass man in größerem Maßstab genauso schreiben kann. Irgendwie wird 1C alles intern erledigen, ich weiß nicht wie, aber es wird es wahrscheinlich tun. Lassen Sie mich „StartTransaction()“ schreiben...

Tags hinzufügen

Beim Arbeiten in 1C kommt es nicht selten vor, dass die Fehlermeldung „Sperrkonflikt beim Ausführen von Transaktionen: Die maximale Wartezeit für die Erteilung einer Sperre wurde überschritten“ angezeigt wird. Sein Kern liegt darin, dass mehrere Sitzungen versuchen, gleichzeitig ähnliche Aktionen auszuführen, die sich auf dieselbe Ressource auswirken. Heute werden wir herausfinden, wie wir diesen Fehler beheben können.

Eine große Anzahl von Operationen durchgeführt

Der erste Schritt bei der Suche nach Gründen besteht darin, zu klären, wie viele gleichzeitige Benutzer sich in der Informationsbasis befinden, in der ein solcher Fehler generiert wird. Wie wir wissen, kann ihre maximale Anzahl recht groß sein. Das sind sowohl tausend als auch fünftausend.

Der Sperr- und Transaktionsmechanismus ist im Entwicklerhandbuch beschrieben. Sie werden verwendet, wenn mehrere Sitzungen gleichzeitig auf dieselben Daten zugreifen. Es ist logisch, dass dieselben Daten nicht gleichzeitig von verschiedenen Benutzern geändert werden können.

Sie sollten auch prüfen, ob einer der Benutzer die Massendatenänderungsverarbeitung ausführt. Dies könnte beispielsweise ein Monatsende oder Ähnliches sein. In diesem Fall verschwindet der Fehler nach Abschluss der Verarbeitung von selbst.

Geplante Aufgaben

Nicht selten liegt die Ursache eines Fehlers in einem System, das große Datenmengen verarbeitet. Es wird empfohlen, solche Dinge nachts zu tun. Legen Sie einen Zeitplan für die Ausführung solcher Routineaufgaben außerhalb der Arbeitszeit fest.

Auf diese Weise arbeiten Benutzer in einem stabilen System und die Routineaufgaben selbst werden erfolgreich erledigt, da die Wahrscheinlichkeit von Konflikten mit Benutzersitzungen verringert wird.

„Hung-Sessions“

Das Problem „steckengebliebener Sitzungen“ von Benutzern ist fast jedem bekannt, der mit der 1C-Wartung in Berührung gekommen ist. Der Benutzer könnte das Programm schon vor langer Zeit verlassen oder ein Dokument geschlossen haben, seine Sitzung bleibt jedoch weiterhin im System bestehen. Das Problem tritt meist isoliert auf und es reicht aus, eine solche Sitzung über die Administratorkonsole zu beenden. Die gleichen Probleme können bei Hintergrundjobs auftreten.

Zahlreichen Kommentaren im Internet zufolge kommen solche Situationen häufiger vor, wenn Netzwerksicherheitsschlüssel verwendet werden. Wenn sich die Situation mit „eingefrorenen Sitzungen“ systematisch wiederholt, ist dies ein Grund, das System und die Server (sofern es sich bei der Datenbank um eine Client-Server-Datenbank handelt) gründlich zu überprüfen und zu warten.

Fehler beim Schreiben der Konfiguration

Alle Standardkonfigurationen werden von qualifizierten Spezialisten und Experten entwickelt. Jedes System wird gründlich getestet und optimiert, um einen schnelleren und korrekteren Betrieb zu gewährleisten.

In dieser Hinsicht kann die Fehlerursache in suboptimalem Code liegen, der von einem Drittentwickler geschrieben wurde. Dies könnte eine „schwere“ Anfrage sein, die Daten für einen langen Zeitraum blockiert. Es kommt auch häufig vor, dass Algorithmen mit geringer Leistung und Verstößen gegen die Logik erstellt werden.

Es besteht eine hohe Wahrscheinlichkeit, dass der Sperrkonflikt gerade aufgrund von Entwicklerfehlern entstanden ist, wenn er nach einem Programmupdate aufgetreten ist. Um dies zu überprüfen, können Sie die Verbesserungen einfach „rückgängig machen“ oder den Code umgestalten.

Letztes Mal haben wir uns die einfachste Methode mit der integrierten 1C-Sprache angesehen. Zur Praxis Transaktionen viel häufiger in Verbindung mit dem Design verwendet. Dies ermöglicht im Fehlerfall die weitere Ausführung des Codes, die Übermittlung einer entsprechenden Fehlermeldung an den Benutzer und das Schreiben von Informationen in das Registrierungsprotokoll oder in eine Protokolldatei zur späteren Analyse durch den Systemadministrator.

Wenn wir uns die technische Dokumentation oder die ITS-Diskette ansehen, werden wir sehen, dass 1C die folgende Methode zur Organisation einer Transaktion in einem Versuch empfiehlt

Versuchen //1. Beginn der Transaktion. StartTransaction() ; //2. Ein Block von Vorgängen, die in einer Transaktion ausgeführt werden. //3. Wenn alle Vorgänge erfolgreich sind, schreiben wir die Transaktion fest. CommitTransaction() ; Ausnahme //4. Sollten beim Ausführen des Codes Fehler auftreten, brechen Sie die Transaktion ab. CancelTransaction() ; //5. Bei Bedarf im Logbuch eintragen. //6. Zeigen Sie dem Benutzer bei Bedarf eine Nachricht an. EndAttempt ;

Eigentlich bedarf der Code keiner besonderen Erklärung. Falls in Bearbeitung Versuche Tritt bei der Ausführung des Transaktionscodes ein Fehler auf, geraten wir sofort in den Block Ausnahme, d.h. vor Methode CommitTransaction() Wir kommen einfach nicht dorthin. Nun, im Ausnahmefall brechen wir die Transaktion entsprechend ab und zeigen ggf. eine Fehlermeldung an und schreiben die Informationen in das Registrierungsprotokoll. Es ist äußerst wünschenswert, Fehler im Logbuch zu erfassen, insbesondere bei Vorgängen, die ohne Benutzerbeteiligung ausgeführt werden (z. B. Routineaufgaben). Dies ermöglicht Ihnen später eine Fehleranalyse. Anstelle einer Protokollierung können Sie auch den Versand von Nachrichten per E-Mail an den Administrator veranlassen.

Nun wollen wir mit neuem Wissen versuchen, den im Artikel über besprochenen Code zu ändern. Ich möchte Sie daran erinnern, dass wir den Eintrag im Verzeichnis berücksichtigt haben Waren und zum Informationsregister Preis nach folgendem Schema:

&OnServerOhne Kontext StartTransaction() ; //ein neues Produkt aufnehmen Produkt = Verzeichnisse. Waren. CreateItem() ; Produkt. Name = „Locher“ ; Produkt. Schreiben() ; //Schreiben Sie den Preis auf RecordSet = InformationRegisters. Preis. CreateRecordSet() ; NewRecord = RecordSet. Hinzufügen() ; Neuer Eintrag. Zeitraum = CurrentDate() ; Neuer Eintrag. Produkt = Produkt. Verknüpfung; Neuer Eintrag. Betrag = 100 ; RecordSet. Schreiben() ; CommitTransaction() ; Ende des Verfahrens

Lassen Sie uns nun die Transaktion in einen Block einfügen Versuchsausnahme. Fehler können höchstwahrscheinlich nur zum Zeitpunkt der Eintragung in das Verzeichnis oder das Informationsregister auftreten, daher werden wir die vorbereitende Vorbereitung außerhalb der Transaktion übernehmen.

&OnServerOhne Kontext Prozedur RunTransactionOnServer() //ein neues Produkt erstellen Produkt = Verzeichnisse. Waren. CreateItem() ; Produkt. Name = „Locher“ ; //Einen Datensatz mit einem Preis erstellen RecordSet = InformationRegisters. Preis. CreateRecordSet() ; NewRecord = RecordSet. Hinzufügen() ; Neuer Eintrag. Zeitraum = CurrentDate() ; Neuer Eintrag. Betrag = 100 ; //Führen Sie die Transaktion versuchsweise aus Versuch, StartTransaction() zu starten; Produkt. Schreiben() ; Neuer Eintrag. Produkt = Produkt. Verknüpfung; RecordSet. Schreiben() ; CommitTransaction() ; Ausnahme CancelTransaction() ; Message = New MessageToUser; Nachricht. Text = ; Nachricht. Etwas melden() ; LogRegistration( „Beim Erfassen des Produkts und seines Preises ist ein Fehler aufgetreten.“); EndAttempt ; Ende des Verfahrens

Was man NICHT tun sollte

Diejenigen, die gerade erst anfangen, mit Transaktionen zu arbeiten, haben oft den Wunsch, dies auf diese Weise zu tun

StartTransaction() ; Versuch, StartTransaction() zu starten; //Operationsblock CommitTransaction() ; Ausnahme CancelTransaction() ; EndAttempt ; Versuch, StartTransaction() zu starten; //Operationsblock CommitTransaction() ; Ausnahme CancelTransaction() ; EndAttempt ; CommitTransaction() ;

Oder in einer Schleife

StartTransaction() ; Für jede Daten-aus-Daten-Array-Schleife wird versucht, Transaction() zu starten; Daten. Schreiben() ; CommitTransaction() ; Ausnahme CancelTransaction() ; EndAttempt ; EndCycle ; CommitTransaction() ;

Auf den ersten Blick haben wir alles nach den Empfehlungen der Firma 1C gemacht. Tatsache ist jedoch, dass die 1C-Plattform keine verschachtelten Transaktionen unterstützt. Das heißt, rein technisch ist es möglich, auf diese Weise zu schreiben. Aber gleichzeitig bilden alle verschachtelten Transaktionen keine neuen, sondern gehören zur gleichen Transaktion der obersten Ebene. Wenn eine der verschachtelten Transaktionen fehlschlägt, kann auf diese Weise die nächste verschachtelte Transaktion nicht festgeschrieben werden. Das System zeigt eine Meldung wie diese an: „Bei dieser Transaktion sind bereits Fehler aufgetreten!“. Lassen Sie uns dies anhand eines Beispiels demonstrieren. Nehmen wir an, wir beschließen, zwei Waren zu erfassen, jede in einer eigenen Transaktion. Und lassen Sie uns diese Transaktionen im dritten verschachteln. Als nächstes werden wir mit dieser Methode künstlich einen Fehler in der ersten Transaktion verursachen Ausnahme auslösen:

&OnServerOhne Kontext Prozedur RunTransactionOnServer() StartTransaction() ; Versuch, StartTransaction() zu starten; Produkt = Verzeichnisse. Waren. CreateItem() ; Produkt. Name = "Tabelle" ; Produkt. Schreiben() ; Ausnahme auslösen „Fehler bei der Produkteingabe.“; CommitTransaction() ; Ausnahme CancelTransaction() ; Message = New MessageToUser; Nachricht. Text = ErrorDescription() AttemptStartTransaction() ; Produkt = Verzeichnisse. Waren. CreateItem() ; Produkt. Name = „Stuhl“ ; Produkt. Schreiben() ; CommitTransaction() ; Ausnahme CancelTransaction() ; Message = New MessageToUser; Nachricht. Text = ErrorDescription() ; Nachricht. Etwas melden() ; EndAttempt ; CommitTransaction() ; Ende des Verfahrens

Als Ergebnis dieses Vorgangs sehen wir im Meldungsfenster Folgendes:

(ExternalProcessing.TransactionsAtTrying.Form.Form.Form(20)): Fehler beim Schreiben des Elements. (ExternalProcessing.TransactionsAtTrying.Form.Form.Form(40)): Fehler beim Aufruf der Kontextmethode (Write): In dieser Transaktion sind bereits Fehler aufgetreten!

Daher ist die Organisation verschachtelter Transaktionen in 1C absolut sinnlos.

Möglichkeiten

Kehren wir nun zu der Option zurück, bei der wir das Produkt und den Preis dafür erfasst haben. Wenn bei der Durchführung einer Transaktion ein Fehler auftritt, ist es schwierig zu verstehen, an welchem ​​Punkt dieser aufgetreten ist – bei der Erfassung des Produkts oder bei der Erfassung des Preises, da beides im Rahmen desselben Versuchs geschieht. Um festzustellen, wo der Fehler aufgetreten ist, müssen wir jeden Schreibvorgang in einen eigenen Versuch einschließen und verschachtelte Transaktionen vermeiden. Dazu führen wir eine boolesche Variable ein Ablehnung und abhängig von seinem Wert am Ende aller Vorgänge werden wir die Transaktion festschreiben oder stornieren.

&OnServerOhne Kontext Prozedur RunTransactionOnServer() // Transaktion starten Verweigern = Falsch; StartTransaction() ; // Versuche, das Produkt aufzuzeichnen Versuchen Sie Produkt = Verzeichnisse. Waren. CreateItem() ; Produkt. Name = „Locher“ ; Produkt. Schreiben() ; Ausnahmefehler = True; Message = New MessageToUser; Nachricht. Text = „Fehler bei der Produktaufzeichnung“; Nachricht. Etwas melden() ; EndAttempt ; // Versuche den Preis aufzuzeichnen AttemptRecordSet = InformationRegisters. Preis. CreateRecordSet() ; NewRecord = RecordSet. Hinzufügen() ; Neuer Eintrag. Zeitraum = CurrentDate() ; Neuer Eintrag. Produkt = Produkt. Verknüpfung; Neuer Eintrag. Betrag = 100 ; RecordSet. Schreiben() ; Ausnahmefehler = True; Message = New MessageToUser; Nachricht. Text = „Fehler bei der Preiserfassung“; Nachricht. Etwas melden() ; EndAttempt ; // Transaktion festschreiben oder abbrechen Wenn KEIN Fehler, dann CommitTransaction() ; Sonst CancelTransaction() ; EndIf ; Ende des Verfahrens

Dasselbe können wir tun, wenn wir beliebige Daten in einer Schleife iterieren und schreiben. In diesem Fall können wir eine Liste aller Daten mit etwaigen Fehlern erhalten.

3

Ich versuche, eine gespeicherte Prozedur auszuführen und ihre Ergebnisse einfach in eine temporäre Tabelle einzufügen, und erhalte die folgende Meldung:

Der Vorgang konnte nicht abgeschlossen werden, da der OLE DB-Anbieter „SQLNCLI“ für den Verbindungsserver „MyServerName“ keine verteilte Transaktion starten konnte. Der OLE DB-Anbieter „SQLNCLI“ für den Verbindungsserver „MyServerName“ hat die Meldung „Keine Transaktion ist aktiv“ zurückgegeben.

Meine Anfrage sieht so aus:

INSERT INTO #TABLE EXEC MyServerName.MyDatabase.dbo.MyStoredProcedure Param1, Param2, Param3

Die genaue Anzahl der Spalten, Namen, Problem ist nicht das Ergebnis.

MSDTC ist aktiviert und wird auf beiden Computern ausgeführt, ebenso wie der Remote-Prozeduraufruf.

Die Maschinen befinden sich nicht in derselben Domäne, aber ich kann von meiner Maschine aus Remote-Abfragen durchführen und das Ergebnis erhalten. Ich kann sogar die gespeicherte Prozedur ausführen und ihre Ergebnisse sehen, ich kann sie nur nicht in eine andere Tabelle einfügen.

Helfen Sie mir bitte? :) :)

Oh, ich habe vergessen zu erwähnen, dass die gespeicherte Prozedur keinen Auslöser auslöst. Es fügt Datensätze nur in temporäre Tabellen ein, die es zur Verarbeitung der Daten erstellt.

  • 3 Antworten
  • Sortierung:

    Aktivität

3

Nun, nachdem ich viele Tutorials verfolgt und viel darüber recherchiert hatte, habe ich alle Konfigurationen geändert, die ich für notwendig hielt, damit es funktioniert, aber das ist noch nicht geschehen.

Heute mussten wir aufgrund eines Absturzes ohne Unterbrechung einen Neustart unseres Entwicklungsservers erzwingen, und als wir den Server hochfuhren, wissen Sie was? Es klappt!

Also fürs Protokoll: Ich habe die spezifische MSDTC-Konfiguration geändert, sie als Verbindungsserver hinzugefügt und RPC IN und OUT zugelassen und die RPC-Konfiguration in „KEINE AUTHENTIFIZIERUNG ERFORDERLICH“ oder so ähnlich geändert.

Ich erinnere mich, irgendwo gelesen zu haben, dass ein Neustart erforderlich war, nachdem Sie diese Konfiguration geändert hatten, obwohl Windows angab, den Dienst bereits neu gestartet zu haben.

Ich habe meinen Server etwa ... zweimal neu gestartet, seit ich ihn geändert habe, und es funktioniert immer noch nicht. Aber heute, nach vollständigem Aus- und Einschalten, funktioniert es!

Bezüglich der Syntax habe ich mich daran gehalten.

2

Haben Sie versucht, OpenQuery zu verwenden?

In Tabelle einfügen select * from openquery(myservername, „exec mydatabase.dbo.mystoredproc param1, param2, param3“)

0

Aus der MSDN-Dokumentation: (http://msdn.microsoft.com/en-us/library/ms188427(SQL.90).aspx) In SQL Server 2000 und höher kann OPENQUERY nicht zum Ausführen erweiterter gespeicherter Prozeduren auf einem Verbindungsserver verwendet werden. Eine erweiterte gespeicherte Prozedur kann jedoch unter Verwendung eines vierteiligen Namens auf einem Verbindungsserver ausgeführt werden. Beispiel: EXEC SeattleSales.master.dbo.xp_msver - Murmeln 28. Mai. 10 28.05.2010 20:52:56

1

Sie sollten auch die DNS-Namensauflösung in Ihrer IP-Netzwerkkonfiguration überprüfen.

Wenn Sie beispielsweise einen Server namens server-a.meinedomain.com und einen anderen namens server-b.anderedomain.com haben, melden Sie sich bei Server-a und „ping-server-b“ (keine Domäne) an.

Wenn es antwortet: „Ping-Anfrage konnte Host-Server-B nicht finden.“ Bitte überprüfen Sie den Namen und versuchen Sie es erneut. das ist ein Problem.

Gehen Sie zu Systemsteuerung > Netzwerkverbindungen > Rechtsklick auf die Netzwerkkarte > Eigenschaften > Internetprotokoll > Eigenschaften > Erweitert > DNS > Fügen Sie dieses DNS-Suffix der Reihe nach hinzu. Und hier fügen Sie die lokale Domäne hinzu: mydomain.com und dann die Remote-Domäne hinzufügen: otherdomain.com. Klicken Sie auf OK, bis es geschlossen wird

Wenn Sie nun „Server B anpingen“, sollte die Antwort etwa so lauten:

installieren erstellen (4)

Cursor = Verbindung. Cursor () Cursor . ausführenmany( „In Person (Vorname, Nachname) Werte (?, ?) einfügen“, Personen) Verbindung. begehen()

Ich versuche, einen Buchindexer mit Python (traditionell, 2.7) und SQLite (3) zu programmieren.

Der Code läuft auf diese Folge von SQL-Anweisungen hinaus:

„Wählen Sie count(*) aus tag_dict aus“() /* [(30,)] */ „wähle count(*) aus file_meta“() /* [(63613,)] */ "Transaktion beginnen" () „ID aus dem Archiv auswählen, wobei Name=?“("158326-158457.zip",) /* [(20,)] */ „Wählen Sie die ID aus der Datei mit Name=? und Archiv= aus?“("158328.fb2" , 20 ) /* [(122707,)] */ „aus file_meta löschen, wo file=?“(122707,) „Transaktion festschreiben“ () # Fehler: Commit nicht möglich – keine Transaktion ist aktiv

Der Isolationsgrad ist „DEFERRED“ („EXCLUSIVE“ ist nicht besser).

Ich habe versucht, „connection.commit()“ anstelle von „cursor.execute(„commit“)“ zu verwenden – es ist nichts Nützliches passiert.

  • Natürlich habe ich auch im Internet gesucht, aber die gefundenen Antworten spielen keine Rolle.
  • Modus Autokompositionen inakzeptabel aus Performance-Gründen.
  • Ich verwende jeweils nur die Datenbankdatei.
  • Mein Code läuft in einem Thread.
  • Die gesamte SQL-Ausführung erfolgt mit einer einzigen Funktion, die sicherstellt, dass ich höchstens öffnen kann eins Mauszeiger.

Was ist also mit der Transaktion hier passiert?

Wenn ich „connection.commit()“ verwende (Hinweis: Es gibt keine „connection.begin“-Methode!), verliere ich einfach meine Daten.

Natürlich habe ich doppelt/dreifach/vierfach geprüfte Dateiberechtigungen für die Datenbankdatei und ihr Verzeichnis.

Nun, wie so oft fand ich die Lösung innerhalb einer Minute, nachdem ich die Frage gestellt hatte.

Als Neuling kann ich meine Frage 8 Stunden lang nicht beantworten... Also, das Folgende ist jetzt:

Die Lösung war und besteht aus einer einzigen Idee.



 


Lesen:



Java Update Scheduler, was ist das für ein Programm und wird es benötigt?

Java Update Scheduler, was ist das für ein Programm und wird es benötigt?

Hallo Freunde! Heute möchte ich Ihnen erklären, warum Java-Technologie auf einem Computer benötigt wird, und klare Beispiele für ihre Verwendung durch Entwickler geben ...

Samsung Galaxy Note N7000 – Technische Daten

Samsung Galaxy Note N7000 – Technische Daten

Positionierung Beim Galaxy Note ist die Positionierung der interessanteste Punkt. Was ist das für ein Gerät? Jemand könnte zählen...

Tele2 Mini-Smartphone: Detaillierte Überprüfung der Eigenschaften des Modells Tele2 Mini-Mobiltelefon

Tele2 Mini-Smartphone: Detaillierte Überprüfung der Eigenschaften des Modells Tele2 Mini-Mobiltelefon

Budget-3G-Gerät für 2 SIM-Karten zum Preis von 1.890 Rubel. Einer der Hauptzwecke eines Smartphones besteht darin, potenziellen Kunden ein kostengünstiges Gerät zur Verfügung zu stellen ...

Lenovo Service Center Sichere Firmware für Lenovo A319

Lenovo Service Center Sichere Firmware für Lenovo A319

Die Installation neuer Firmware auf einem Telefon ist eine verantwortungsvolle Angelegenheit und erfordert eine vorbereitende Vorbereitung. Reflash Lenovo a319, a916 und...

Feed-Bild RSS