I want to delete and insert triples from a sesame repository using SPARQL queries, and I want to execute both operations as a single transaction.
- DELETE
- INSERT
If an exception is thrown during the transaction, rollback is executed… but it seems not to work.
The problem is that, if an exception is thrown during the insert query, the rollback is executed, but the previously deleted triples are not recovered (Why?).
Here you have some code:
I have a class called OwlimConnector which wraps the repository connection and provides some methods to make SPARQL Queries.
In the constructor of this class, I set up the connection and I set the autocommit to false:
RemoteRepositoryManager repos_manager = RemoteRepositoryManager.getInstance(SERVER_URL, USER, PASSWORD);
repos_manager.initialize();
Repository ssr = repos_manager.getRepository(REPOSITORY);
rconn = ssr.getConnection();
rconn.setAutoCommit(false);
In OwlimConnector there is a method called executeUpdate:
public void executeUpdate(String queryString) throws RepositoryException, MalformedQueryException, UpdateExecutionException
{
Update up = rconn.prepareUpdate(QueryLanguage.SPARQL, queryPrefixString + queryString);
up.execute();
}
and these methods among others:
public void commit(){
rconn.commit();
}
public void rollback() {
rconn.rollback();
}
public void close(){
rconn.close();
}
On the other hand, I have a web service “updateUserGroup” wich uses the previous OwlimConnector and a data access object called UserGroupDAO:
@PUT
@Consumes(MediaType.APPLICATION_XML)
public Response updateUserGroup(UserGroup ug) {
try {
oc = new OwlimConnector();
} catch (OwlimInstantiationException e) {
return ResponseFactory.getError(e.getErrorMessage());
}
try {
UserGroupDAO ugdao = new UserGroupDAO(oc);
ugdao.delete(ug.getUri());
ugdao.add(ug);
oc.commit();
oc.close();
return ResponseFactory.getOK();
} catch (MandatoryFieldException e) {
oc.rollback();
oc.close();
return ResponseFactory.getError(e.getErrorMessage());
} catch (NotExistingResourceException e) {
oc.rollback();
oc.close();
return ResponseFactory.getError(e.getErrorMessage());
} catch (Exception e) {
oc.rollback();
oc.close();
return ResponseFactory.getError(new GenericException(e).getErrorMessage());
}
}
1 What ugdao.delete(ug.getUri()) does is to call the OwlimConnector method executeUpdate:
oc.executeUpdate("DELETE { " + usergroup + " ?p ?v . } WHERE { " + usergroup + " ?p ?v . }");
Here the triples are deleted even though there is no commit!
2 What ugdao.add(ug) does is:
To check that ug.getName() is not null or spaces, otherwise the MandatoryFieldException is thrown:
if (ug.getName() == null || ug.getName().equals("")){
throw new MandatoryFieldException("name");
}
Then, the data is inserted:
oc.executeUpdate("INSERT DATA { " + ug.getUri() + " a scmu:UserGroup ; scmu:hasName \"" + ug.getName() + "\" . }");
When ug.getName() is null or spaces the MandatoryFieldException exception is thrown and caught by updateUserGroup. Then the rollback is executed but the deleted triples are not recovered.
I don´t know why this happens. Any Idea?
Thank you very much in advance
The solution is much easier than I thought. This is the answer I received from the Ontotext AD in the mailing list:
“you are using RemoteRepository so each update, is immediately sent to the remote repository at up.execute() and there it is autocommited immediately .
what you could do is instead of preparing and executing on each delete/add operation in your service to start collecting all individual updates (into a StringBuilder for instance) and on oc.commit() to prepare and execute the whole list of updates at once (and just clear the list on rollback, in case an exception is thrown)
Your update request can have multiple ‘INSERT DATA’ or ‘DELETE DATA’ updates … “
And it works! Thank you.