Once a connection is retrieved for performing model operations, it cannot be released until the service terminates.
Performing Data read operations before model operations allows a connection to be retrieved for querying, then released while other work is being completed.
Any of the following request handlers will automatically register the intent to participate in a transaction:
However, the actual transaction is initiated if and when a database connection is acquired. The entire transaction is managed by the local (i.e. NOT distributed/XA) JDBC transaction support available with the connection.
All the above-mentioned service invocations would initiate a single transaction automatically and commit or rollback at the end of the service invocation. Note that the database transaction remains open until the request invocation completes. Therefore, it’s advised to write efficient/modular custom services and avoid long running monolithic services to avoid holding database connections for too long, which would result in running out of database connections.
The transaction API is not exposed as ThingWorx scripting API and therefore, not accessible from the JavaScript based custom services or scripts.
Most of persisted data changes (Stream, Value Stream, Data Table, Persisted Properties) are queued and batched to improve data ingestion throughput. Therefore, the actual writing to the database is performed by a separate executor thread (Data Processing Subsystem). This thread pool will create its own transaction and thus will not be part of the transaction initiated by the originating service request.
Model changes (modeled entities CRUD operations) in contrast are not queued or batched and hence would be performed as part of the transaction initiated by the originating service request.
It should also be noted that any and all database operations including reads (i.e. via select statements) require a transaction as per the JDBC specification. While typical applications may use ‘auto commit’ feature with reads ThingWorx does not treat them as separate request since it complicates transaction handling when multiple reads and writes are interlaced in service invocations. Thus transactions initiated by a Read operation will also remain open until the request invocation completes.
When there are more than one database instances are involved (usually with multiple Persistence Providers) there will be a separate connection acquired for each database and those transactions will be handled independently per connection. ThingWorx does not support distributed transactions with two phase commit protocol which means that the commit and rollback would be just best effort.
A. Long running service (the pauses represent for example calls to an external system)
pause(5000); // 5 sec
result = MyDataTable.GetDataTableEntryCount(); // Start DB Transaction
pause(10000); // 10 sec
This service is invoked via REST :
B. Request that involves multiple threads
me.prop1 = 10; // logged property with data change subscription, the subscription queries a Data Table
myAsyncSrc(); // Asynchronous service that also queries a Data Table
This service is invoked via REST :
New Section in the Help Center documenting the behavior: Performing Long Running Work When No Connection is in Use