I am using JPA 3, with annotation (no mapping file) and with provider org.hibernate.ejb.HibernatePersistence
I need to have optimistic concurrency.
1)I tried to rely on the tag called , it did not work.
2)
So I decided to do it with java code. I have a mergeServiceRequest method and an object with type Request as follows: I start a transaction, lock the request object,
then try to get a Request object newRequest from database, compare its timestamp with the current one request. If they do not match, I throw an exception; if they match, then I update the current request enter code herewith current time and save it to database.
I need to lock the object manually, because by starting a transaction from session, it does not put a lock on the row in database. I wrote some java code which shows that a transaction does not lock the record in database automatically.
Problem with this approach is the query
Request newRequest=entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
always return same object as request. "request" is in the session entityManger, and the query always return what is cached in the session. I tried all the five query.setHint lines and I still get same result: no database query is performed, the result is from session cache directly.
#Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Query query = entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
//query.setHint("javax.persistence.cache.retrieveMode", "BYPASS");
//query.setHint("org.hibernate.cacheMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.cache.retrieveMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.retrieveMode", CacheMode.REFRESH);
//query.setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);
Request newRequest=(Request)query.getSingleResult();
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
}
3)So I also tried to use another session get query the newRequest, if I do that, the newRequest will be different from request. But for some reason, if I do that, then the lock on request object is never released, even after the transaction commit. Code looks like below
#Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Request newRequest=findRequest(request.getServiceRequestId()); // get it from another session
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
//lock on the database record is not released after this, and even after entityManager is closed
}
Could anyone help me on this?
Thanks.
Daniel
Related
I have a query in a Spring data JpaRepository like so:
#Lock(value = LockModeType.PESSIMISTIC_WRITE)
#QueryHints({#QueryHint(name = "javax.persistence.lock.timeout", value = "70000")})
Collection<AnyCLass> findBy ...
However, in my test, if I run the transaction ( that uses this query as the first query) in two concurrent threads I get an SQL Lock timeout (SQL Error: 50200, SQLState: HYT00) after one second, which is the default for the H2 in memory.
If the transaction is faster then one second everything works as expected.
Possible workaround for this Issue is a simple retry on the enclosing method:
#Retryable(backoff = #Backoff(value = 500,random = true))
void getSometingLocked(){
findById(id)
}
I am using Ember data with the REST adapter. When you save a record using this.transaction.commit() and the server responds with a 422 validation error, then this case can be captured using the "becameError" event.
However, after changing the data in teh form field and clicking save again (thus doing a second this.transaction.commit(), nothing happens. The transaction is not committed because we are in a Invalid state ...
How can I solve this ?
You can transition the model back to uncommitted state via it's stateManager. If it is an existing record, transition to loaded.updated.committed:
model.get('stateManager').transitionTo('loaded.updated.uncommitted')
and for new records, transition to loaded.created.uncommitted
model.get('stateManager').transitionTo('loaded.created.uncommitted')
Consider this to be a workaround until the ember-data API has a better way.
See What can you do with Ember Data Models when in the error state? and https://gist.github.com/intrica/4773420 for more detail
After transition to ('loaded.created.uncommitted') state in case of a becameInvalid state, you need to use the store defaultTransaction to recommit.
See code below - very dirty check to know whether to use transaction.commit() or defaultTransaction.commit()
save: function () {
//Local commit - author record goes in Flight state
this.transaction.commit();
//After a becameInvalid state, transaction.commit() does not work; use defaultTransaction in that case
//Is this the only way to do this ?
if (this.get('stateManager.currentState.name') == "uncommitted") {
this.get('store').get("defaultTransaction").commit();
}
var author = this.get('model');
author.one('didCreate', this, function () {
this.transitionToRoute('author.edit', author);
});
//If response is error (e.g. REST API not accessible): becameError fires
author.one('becameError', this, function () {
this.get('stateManager').transitionTo('loaded.created.uncommitted');
});
//If response is 422 (validation problem at server side): becameInvalid fires
author.one('becameInvalid', this, function () {
this.set('errors', this.get('content.errors'));
//Does set stateManager.currentState.name to uncommitted, but when committing again, nothing happens.
this.get('stateManager').transitionTo('loaded.created.uncommitted')
});
},
As a horrible workaround, you can try saving a clone of the record instead. This will leave your original record pristine.
If the save succeeds, delete the original record.
Else delete the clone and try again with a new clone.
I have controller with method that blocks the Play server thread due to very slow Database query. I need to implement controller method in a way that it don't block the thread.
I have read documentation: http://www.playframework.org/documentation/1.2.4/asynchronous
There's absolutely no examples anywhere on how to do this. The only thing that I found close is this https://github.com/playframework/play/blob/master/samples-and-tests/chat/app/controllers/LongPolling.java
It simply wraps result in await();
When I try to do that it doesn't work.
routes:
GET /blog Controller.blog
Controller (this is not an actual slow query but everything else is identical):
public static void blog() {
String queryStr = "SELECT b FROM Blog b ORDER BY createTime DESC";
JPAQuery q = Blog.find(queryStr);
List<Blog> bList = q.fetch(100);
List<BlogDTO> list = new ArrayList<BlogDTO>(bList.size());
for (Blog b : bList) {
BlogDTO obj = new BlogDTO(b);
list.add(obj);
}
renderJSON(list);
}
I tried List<Blog> bList = await(q.fetch(100)); but that doesn't work.
I have not worked with Future and promises before.
Can anyone give me any pointers on how to approach this?
For me the best way to do this is to use a Job that returns a List object. Then in your controller you can await for the job termination :
public static void blog() {
List<BlogDTO> list = await(new BlogPostJob().now());
renderJSON(list);
}
and you put your jpa code in your job
Because JDBC uses blocking IO, any slow database query will always block a Thread.
The only way seems to be using Job for that purpose.
I'm researching a way to build an n-tierd sync solution. From the WebSharingAppDemo-CEProviderEndToEnd sample it seems almost feasable however for some reason, the app will only sync if the client has a live SQL db connection. Can some one explain what I'm missing and how to sync without exposing SQL to the internet?
The problem I'm experiencing is that when I provide a Relational sync provider that has an open SQL connection from the client, then it works fine but when I provide a Relational sync provider that has a closed but configured connection string, as in the example, I get an error from the WCF stating that the server did not receive the batch file. So what am I doing wrong?
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = hostName;
builder.IntegratedSecurity = true;
builder.InitialCatalog = "mydbname";
builder.ConnectTimeout = 1;
provider.Connection = new SqlConnection(builder.ToString());
// provider.Connection.Open(); **** un-commenting this causes the code to work**
//create anew scope description and add the appropriate tables to this scope
DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription(SyncUtils.ScopeName);
//class to be used to provision the scope defined above
SqlSyncScopeProvisioning serverConfig = new SqlSyncScopeProvisioning();
....
The error I get occurs in this part of the WCF code:
public SyncSessionStatistics ApplyChanges(ConflictResolutionPolicy resolutionPolicy, ChangeBatch sourceChanges, object changeData)
{
Log("ProcessChangeBatch: {0}", this.peerProvider.Connection.ConnectionString);
DbSyncContext dataRetriever = changeData as DbSyncContext;
if (dataRetriever != null && dataRetriever.IsDataBatched)
{
string remotePeerId = dataRetriever.MadeWithKnowledge.ReplicaId.ToString();
//Data is batched. The client should have uploaded this file to us prior to calling ApplyChanges.
//So look for it.
//The Id would be the DbSyncContext.BatchFileName which is just the batch file name without the complete path
string localBatchFileName = null;
if (!this.batchIdToFileMapper.TryGetValue(dataRetriever.BatchFileName, out localBatchFileName))
{
//Service has not received this file. Throw exception
throw new FaultException<WebSyncFaultException>(new WebSyncFaultException("No batch file uploaded for id " + dataRetriever.BatchFileName, null));
}
dataRetriever.BatchFileName = localBatchFileName;
}
Any ideas?
For the Batch file not available issue, remove the IsOneWay=true setting from IRelationalSyncContract.UploadBatchFile. When the Batch file size is big, ApplyChanges will be called even before fully completing the previous UploadBatchfile.
// Replace
[OperationContract(IsOneWay = true)]
// with
[OperationContract]
void UploadBatchFile(string batchFileid, byte[] batchFile, string remotePeer1
I suppose it's simply a stupid example. It exposes "some" technique but assumes you have to arrange it in proper order by yourself.
http://msdn.microsoft.com/en-us/library/cc807255.aspx
I'm just starting to practice BDD using the GWT approach to the following code exert and just realised that I can't do the second test.
My GWT goes something like
Given there exists an open query
When the user replies to the query
Then it should save the reply if the reply is not blank
Then it should notify the user and not save the reply if it is blank
So I coded it up like so
public class when_user_replies_to_the_query : OpenQuery
{
Because
{
query.Reply(data);
}
ThenIt should_save_the_reply_to_the_database_if_there_is_a_reply
ThenIt should_notify_the_user_if_there_is_no_text_in_the_reply_and_not_save_to_database
}
public class Query
{
void Reply(string data)
{
//do something
}
}
But then I realised that I can't do the second case because the first case requires data to have something in it whilst the second case says that data should be an empty string.
Does this mean that I should be splitting my GWT into something like
Given the reply is blank
When the user replies to the query
Then it should notify the user ......
If this is the case, then I'd be writing a huge amount of null case scenarios for return
values being null. Such as
Given the database is null
When retrieving queries
Should reply with error message
When saving queries
Should save to file and reply with error message
When // basically doing anything
Should //give appropriate response
Is this how I should be writing my BDD specs? And am I even in the right forum O_O?
You would want to invert the two Then clauses, because they basically form different contexts under which the Query class is exercised. When you read both Then statemenents you can see that "if is not blank" and "is blank" form both contexts.
Context #1:
Given an open query
Given a non-blank reply
When the user replies to the query
It should save the reply
public class When_the_user_replies_to_the_query_and_the_reply_is_not_blank
{
static Query Query;
Establish context = () =>
{
Query = new Query();
};
Because of = () =>
{
Query.Reply("answer");
};
It should_save_the_reply = () =>
{
// Use your imagination
};
}
Context #2:
Given an open query
Given a blank reply
When the user replies to the query
It should not save the reply
It should notify the user
public class When_the_user_replies_to_the_query_and_the_reply_is_blank
{
static Query Query;
Establish context = () =>
{
Query = new Query();
};
Because of = () =>
{
Query.Reply(String.Empty);
};
It should_not_save_the_reply = () =>
{
// Use your imagination
};
It should_notify_the_user = () =>
{
// Use your imagination
};
}
Considering that you could have multiple possible "empty reply" values (null, String.Empty, " ", \r\n) , you could write contexts for any of these. I often do not write specs for any imaginable combination of values, but rather
have one context for the "happy path", i.e. reply is not empty
have one context for empty replies
In the light of your example, one could argue that the Query class isn't the right place to decide whether a reply satisfies the "is not empty" specification. You should rather code up that decision in a separate class and the Query should rely on the decision of that one. This would bring some advantages:
Separation of concerns: the Query class and the specification can evolve separately
You can re-use the specification in multiple places, hinting a problem with the reply before the user posts his empty reply
You can get the specification under test separately without worrying about user notification and database saves, thus preventing context explosion for Query concerns