I'm using Delphi 10.4 with a Firebird-Database (3) and FireDac. I have a general question about transaction handling.
Please have a look at the following pseudo code:
write_transaction := TFDTransaction.Create;
write_connection := TFDConnection.Create;
write_transaction.Connection := write_connection;
write_connection.StartTransaction;
There is a connection assigned to a transaction. Then I start working with:
write_transaction.StartTransaction;
...
write_transaction.Commit;
But when I call write_connection.StartTransaction what will happen? So my questions...
Will there be started a transaction for the write_transaction, as if write_transaction.StartTransaction is called? Or will there be started a completely different transaction?
Will there be started a transaction for the write_transaction, as if
write_transaction.StartTransaction is called?
Yes, this is the same. The TFDTransaction component wraps the transaction control functionality into a component. Practically, it offers the same transaction functionality as TFDConnection, but allows you to group commands and datasets by linking them to a specific transaction object.
Related
I'm curious about yielding during a transaction. Will it be interrupted immediately? Or will other fibers be able to read changes that have not yet been committed?
I've overlooked the documentation but didn't see it.
Currently, there is a way to yield in a transaction. This is because there is now a fully functional transaction manager for both memtx and vinyl engines.
Here's a working example:
local fiber = require('fiber')
-- If you just use box.cfg{}, this app will fail
box.cfg{memtx_use_mvcc_engine=true}
--box.cfg{}
box.schema.space.create('account', {if_not_exists=true})
box.space.account:format({ {name='id',type='unsigned'},
{name='first_name',type='string'},
{name='last_name',type='string'},
})
box.begin()
box.space.account:put({2, "John", "Doe"})
print("sleeping")
fiber.sleep(1)
print("woke up")
box.space.account:put({3, "Ivan", "Ivanov"})
box.commit()
os.exit(0)
Note the memtx_use_mvcc_engine option. It enables the transaction engine. Without this option, a yield inside the transaction will result in immediate rollback.
The new transaction manager will also make changes inside the transaction to be invisible to other fibers and transactions before it is committed. And in case of conflict (parallel changes to the same data), the transaction will be rolled back.
I have implemented a user defined procedure using the example template.
The procedure is annotated using "#Procedure(value = "foo.bar", mode = Mode.WRITE)", nevertheless, when I try to execute an operation on a Node instance that modifies the graph, it fails with "Write operations are not allowed for READ transactions".
The node instance was obtained via db.findNode(...), and the write-operation that I am attempting to execute is nodeinstance.createRelationshipTo(...)
Interestingly, the code works fine when run in the context of the neo4j testing harness.
Any help greatly appreciated!
From inspecting the APOC user defined procedures, I learned the answer. I am using neo4j 3.0.7, for 3.0.x a procedure that wants to write to the graph must be annotated with "#PerformsWrites", as well as "#Procedure". The mode argument", mode = Mode.WRITE", is for 3.1, and "#PerformsWrites" is for 3.0.x -- learned this from Stefan Armbruster
I have the following stored procedure in DB2:
CREATE OR REPLACE PROCEDURE CANCEL_ACTIVITY (IN application_handle INTEGER)
LANGUAGE SQL
BEGIN
DECLARE UOW_ID INTEGER;
DECLARE ACTIVITY_ID INTEGER;
FOR v AS cur1 CURSOR FOR
SELECT UOW_ID, ACTIVITY_ID FROM TABLE(SYSPROC.MON_GET_ACTIVITY(application_handle, -1))
DO
CALL WLM_CANCEL_ACTIVITY(application_handle, v.uow_id, v.activity_id);
END FOR ;
END
Using the following query, I am able to find my connection ID:
SELECT MON_GET_APPLICATION_HANDLE() from SYSIBM.SYSDUMMY1
Which would return a value like 36547. So I call the procedure I just created like so:
CALL CANCEL_ACTIVITY(36547);
As a result, I get the following:
However, if I execute the query that gets connection IDs again, it doesn't seem like that connection ID is gone. I still get the 36547 value returned.
I am quite confused whether this query canceling is working at all. I am getting a range of different type of errors in different environments I am executing the code at.
When I am running it as a SQL query, I get the above error code / response. When my code is being executed in my webpage, I get the following error:
Cannot cancel queries: Java::ComIbmDb2JccAm::SqlDataException: DB2 SQL Error: SQLCODE=-802, SQLSTATE=22003, SQLERRMC=null, DRIVER=4.16.53
I am curious what I am doing wrong?
I would recommend to read Canceling Activies in the DB2 documentation. Canceling an activity is not closing a connection, but selectively aborting a query or other running tasks:
If an activity is consuming too many resources, or is running too
long, you can cancel it. Canceling an activity is gentler than forcing
the application that submitted the activity. A canceled activity
returns SQL4725N to the user, but does not end the connection or
affect any other user activity. Forcing the application ends both the
connection and user activities.
In your procedure you are looking for the app handle, uow and a specific activity ID. Have you looked what the activity you are going to cancel is/was doing? You could use WLM_CAPTURE_ACTIVITY_IN_PROGRESS to first dump information about that activity, so that you can debug your scenario.
I have about 30 unique sites which I login to and download a few files from each one of them. Sometimes I have about 50 sites, which the 20 extra are the same as previous ones but with different login credentials.
If I run the download process for any of them with all the other sites disabled, all of them work great. But if I try to download them one after another, I usually get about 5-10 errors from 40 sites!
Exceptions that occur are usually socket error, connection closed gracefully or unknown error occured!
Right now, I create a class for each site, and in each class I create a TIdHTTP or TIdFTP object (very few are FTP and I don't have a problem with any of them). When the download from one class is finished, I destroy the class and destroy the TIdHTTP, and start the download process for the next class (or site), so the downloads are not parallel. But I do create about 40 TIdHTTP and a few TIdFTP objects at the very beginning, and I start the download process one after another.
Is my approach correct? Or should I use only one TIdHTTP object in all classes? But if I have to do so, how can I refresh or reset it? Sometimes I have to login to a single site multiple times with different credentials.
I should also mention that one approach I came up with that did help a little bit (maybe solved one or two errors!) was this:
// mMaxTryCount is 4 and mSleepInterval is 1000
for I := 1 to mMaxTryCount do
begin
if not(isSuccess) then
begin
if (i = mMaxTryCount) then
begin
responseCode.Clear;
idHttp.Post(URL, requestList, responseCode);
end
else
try
responseCode.Clear;
idHttp.Post(URL, requestList, responseCode);
isSuccess := true;
except
Sleep(mSleepInterval * (i + (i - 1)));
end;
end;
end;
I'm using TNMHTTP in Delphi to retrieve the code from a webpage. The code is relatively simple:
NMHTTP1 := TNMHTTP.Create(Self);
NMHTTP1.InputFileMode := FALSE;
NMHTTP1.OutputFileMode := FALSE;
NMHTTP1.ReportLevel := Status_Basic;
NMHTTP1.TimeOut := 3000;
URL := 'http://www....';
NMHTTP1.Get(URL);
S := NMHTTP1.Body;
I am catching exceptions in a try/except block, but that is not the problem.
The problem is that on executing the NMHTTP1.Get method when the URL is a redirect, that method does not return and the program hangs. This is despite the fact that I've put a timeout of 3000 seconds in.
So I see three possible ways of solving this (in order of easiest to hardest for me to modify my program):
Do whatever is necessary to get the NMHTTP1.Get method to respond.
Do some sort of check in advance of the NMHTTP1.Get statement to see if the URL is a redirect and get the URL it is redirecting to.
Use another method to get a webpage using Delphi. When I wrote this, I used Delphi 4 and did not have Indy. I now have Delphi 2009, so I would be willing to use something that works in it (maybe INDY) if a simple #1 or #2 answer is not available.
I would love to get an answer from someone that will work for me. Thanks in advance.
I would avoid the NetMasters controls, period.
Instead, you can use Indy's IdHTTP component, which has a RedirectMaximum property (defaults to 15) and an OnRedirect event in case you want to track the details.
I can advice you to switch to Indy. They are great for a lot of network protocols (with the exception of the IRC protocol). There are nice examples included so you can examine the working examples yourself.
Also have a look at http://www.indyproject.org/index.en.aspx for more information on indy.