What does session.commit() do in XCC/J
08 July 2013 02:51 PM
We have seen some confusion around the use of the commit() method when working with XCC/J or XCC .NET. In this article, we will walk through a scenario where exceptions are thrown if it is used in an unexpected way and we will discuss managing transactions in general. This article will attempt to give a clearer picture regarding how all the parts work in unison.
We'll start by taking a look at the JavaDoc for XCC/J's Session.commit() at https://docs.marklogic.com/javadoc/xcc/com/marklogic/xcc/Session.html#commit()
Under the "Throws" heading, it states that you should expect to see an IllegalStateException if the TransactionMode is set to AUTO.
Consider the following code:
Note that this is a slightly adapted example of the ad-hoc query in the XCC Developer Guide (http://docs.marklogic.com/guide/xcc/concepts#id_65804).
The code itself is fairly simplistic - we're running a newAdHocQuery and calling xdmp:document-delete and passing in the URI of the first doc in a given database. As xdmp:document-delete returns an empty sequence, we will not be using a ResultSequence Object to work with the result set after the request has been submitted.
If you were to run the code as-is, you should see that there are no Exceptions caught and you should be able to verify that the code ran to the end. Most importantly, examination of the database should show one less document than before.
If we were to add a new line just below line 22 and add a commit():
You should see two things happening
In this example, the call to s.commit() appears to do little more than just throw back an exception. Why was that?
Remembering that the JavaDoc stated that you would see an IllegalStateException if you had the TransactionMode set to AUTO, you should be able to confirm the state of the TransactionMode by getting XCC to tell you. To do this, you can add a line just below cs.newSession() to print the current transaction mode to stdout:
Running the code this time, you should see AUTO printed out in the console.
Adding the line:
Should now allow you to make a call to s.commit() without getting that exception thrown. Note that in this example, such usage is okay; as you're issuing a single xdmp:document-delete() and this must run as an update.
If you change the transaction mode to QUERY and run the code again, you will see an error message that looks like:
com.marklogic.xcc.exceptions.XQueryException: XDMP-UPDATEFUNCTIONFROMQUERY: xdmp:document-delete([YOUR_URI_HERE]) -- Cannot apply an update function from a query
In essence, XCC will manage transactions on your behalf; you can issue adHocQueries in this nature and the server should do the right thing; as the query is sent to MarkLogic Server, it will be evaluated and it will set the correct transaction mode for you - for simple transactions, you don't need to handle it yourself.
Inside MarkLogic Server explains transactions in significantly more detail - you can download it at http://developer.marklogic.com/inside-marklogic
The Developer's Guide also covers transactions in detail - particularly the section called "Understanding Transactions in MarkLogic Server" - which can be found at http://docs.marklogic.com/guide/app-dev/transactions#chapter
Now it may be the case that you don't really need to use an explicit call to commit() at all.
Understanding when commit() may be useful
You can get a better idea of what newAdHocQuery does by looking at the JavaDoc for the method http://docs.marklogic.com/javadoc/xcc/com/marklogic/xcc/AdhocQuery.html
Note this part of the description:
A specialization of Request which contains an ad-hoc query (XQuery code as a literal String) to be submitted and evaluated by the MarkLogic Server.
The key word in the description is "evaluated" - what your newAdHocQuery is doing at the server level is passing the enclosed string to one of MarkLogic Server's builtins - xdmp:eval (http://docs.marklogic.com/xdmp:eval)
The xdmp:eval builtin creates a transaction on your behalf. You can test this on your own system if you enable the eval audit event; to do this from the Admin UI, navigate to Groups > [Group Name] > Auditing - ensure "audit enabled" is set to true and tick the checkbox next to 'eval'.
If you run the original code again and then check the audit log, you should see something like:
2013-05-02 14:27:46.937 event=eval; expr=fn:doc(); database=[your-database-name-here]; success=true; user=[your-user-name-here]; roles=admin;
In the scenario earlier, why was an IllegalStateException being thrown?
Here's a quick recap of the events that took place:
The previous query has already returned and has performed the delete as an enclosed transaction. The message is telling you that you're trying to commit a transaction where no transaction exists.
When would you use commit()?
The best case for this is when you want to compose Multi Statement Transactions. For a good overview, you can read the documentation in the XCC Developer's Guide:
In the code example in that section of documentation, you should see the use of commit() as used in a situation where two separate transactions take place and where either both need to run to completion, or the whole transaction needs to be completely rolled back in the event of failure.