I have multiple API clients that call TokenAuth/Authenticate to get an accesstoken for using the API. When they try this too close to eachother I get a concurrency conflict at GetLoginResultAsync in TokenAuthController/Autheticate.
Full exception message: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
Why, and how should I solve this?
(I guess your different clients use the same account to login.)
Generally the exception explains; an entity is fetched from database and after that another client fetched the same entity. The second client updated entity and committed to database. While the first client tries to save the entity, he has an outdated dirty entity. Thus you got Concurrency Conflict!
This occurs when Optimistic Locking is used. And AspnetBoilerplate uses that method for performance priority against Pessimistic Locking.
Solution:
In your TokenAuthController class modify Authenticate method ;
private static AsyncLock _asyncLock = new AsyncLock();
[HttpPost]
public async Task<AuthenticateResultModel> Authenticate([FromBody] AuthenticateModel model)
{
//i am using AsyncLock because there are async methods in Authenticate.
using (await _asyncLock.LockAsync())
{
var loginResult = await GetLoginResultAsync(
model.UserNameOrEmailAddress,
model.Password,
GetTenancyNameOrNull()
);
//other codes ...
}
}
For AsyncLock library see https://github.com/StephenCleary/AsyncEx
Related
I am trying to control concurrent access to same object in spring+jpa configuration.
For Example, I have an entity named A. Now multiple processes updating the same object of A.
I am using versioning field but controlling it but here is the issue:
For example 2 processes reads the same entity (A) having version=1.
Now one process update the entity and version gets incremented.
when 2nd process tries to persist the object, Optimistic lock exception would be thrown.
I am using spring services and repository to access the objects.
Could you please help me here?
What's the problem then? That's how it's supposed to work.
You can catch the JpaOptimisticLockingFailureException and then decide what to do from there.
This, for example, would give a validation error message on a Spring MVC form:
...
if(!bindingResult.hasErrors()) {
try {
fooRepository.save(foo);
} catch (JpaOptimisticLockingFailureException exp){
bindingResult.reject("", "This record was modified by another user. Try refreshing the page.");
}
}
...
My problem is straightforward. I want to access some data from the database when the application loads on Tomcat. To do something at that point in time I use #PostConstruct (which does its job properly).
However, in that method I make 2 separate connections to the DB: one for bringing a list of entities and another for adding them into a common library. The second step implies some behind-the-scenes queries for resolving some lazy-loading associations. Here is the code snippet:
#Override
#PostConstruct
public void populateLibrary() {
// query for the Book Descriptors - 1st query works!!!
List<BookDescriptor> bookDescriptors= bookDescriptorService.list();
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
// resolving some lazy-loading associations - 2nd query fails!!!
for (BookDescriptor book: bookDescriptors) {
library.addEntry(book);
}
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
1st query works while the 2nd fails, as I wrote in the comments. The failure gives:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at com.freightgate.domain.SecurityFiling_$$_javassist_7.getSfSubmissionType(SecurityFiling_$$_javassist_7.java)
at com.freightgate.dao.SecurityFilingTest.test(SecurityFilingTest.java:73)
Which is very odd since I explicitly opened and closed a transaction. However, if I inspect some details of how the 1st query works it seems like behind the scenes the session is bound to AbstractLazyInitializer class.
I resolved my problem by abstracting away the functionality from the for loop into a separate service class that is annotated with #Transactional(readOnly = true). Still I'm puzzled as to why the approch that I posted here fails.
If anyone has some hints, I'd be very happy to hear them.
You load entities in a first session, then close this session, then open a new session, and try to lazy-load collections of the entities. That can't work.
For lazy-loading to work, the entity must be attached to an open session. Just opening another session doesn't make any entity you have loaded before attached to this new session. In the meantime, some other transaction could have radically changed the database, the entity could not exist anymore...
The best solution is what you have done. Encapsulate evrything into a single transactional service. You could also have open the transaction before calling the first service, but why handle transactions programmatically, since Spring does it for you declaratively?
I'm using the TransactionScope class within a project based on Silverlight and RIA services. Each time I need to save some data, I create a TransactionScope object, save my data using Oracle ODP, then call the Complete method on my TransactionScope object and dispose the object itself:
public override bool Submit(ChangeSet changeSet)
{
TransactionOptions txopt = new TransactionOptions();
txopt.IsolationLevel = IsolationLevel.ReadCommitted;
using (TransactionScope tx = new TransactionScope(TransactionScopeOption.Required, txopt))
{
// Here I open an Oracle connection and fetch some data
GetSomeData();
// This is where I persist my data
result = base.Submit(changeSet);
tx.Complete();
}
return result;
}
My problem is, the first time I get the Submit method to be called, everything is fine, but if I call it a second time, the execution gets stuck for a couple of minutes after the call to Complete (so, when disposing tx), then I get the Oracle error "ORA-12154". Of course, I already checked that my persistence code completes without errors. Any ideas?
Edit: today I repeated the test and for some reason I'm getting a different error instead of the Oracle exception:
System.InvalidOperationException: Operation is not valid due to the current state of the object.
at System.Transactions.TransactionState.ChangeStatePromotedAborted(InternalTransaction tx)
at System.Transactions.InternalTransaction.DistributedTransactionOutcome(InternalTransaction tx, TransactionStatus status)
at System.Transactions.Oletx.RealOletxTransaction.FireOutcome(TransactionStatus statusArg)
at System.Transactions.Oletx.OutcomeEnlistment.InvokeOutcomeFunction(TransactionStatus status)
at System.Transactions.Oletx.OletxTransactionManager.ShimNotificationCallback(Object state, Boolean timeout)
at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Object state, Boolean timedOut)
I somehow managed to solve this problem, although I still can't figure out the reason it showed up in the first place: I just moved the call to GetSomeData outside the scope of the distributed transaction. Since the call to Submit may open many connections and perform any kind of operations on the DB, I just can't tell why GetSomeData was causing this problem (it just opens a connection, calls a very simple stored function and returns a boolean). I can only guess that has something to do with the implementation of the Submit method and/or with the instantiation of multiple oracle connections within the same transaction scope.
I am developing a node.js application on Windows Azure Websites (IISNode) and have installed the Azure SDK module for node.js my question is how to use the etag or timestamp field in table storage.
Is it a matter of "me" doing something e.g:
if (entities[0].Timestamp == newEntity.Timestamp)
// commit this update because we are dealing with the latest copy of this entity
else
// oops! one of the entities is newer than the other, better not save it
Or do I need to listen for a error returned by the tableService.updateEntity( ... for an error returned or something ?
Any help or advice appreciated
As Neil mentioned good practice is to let table service handles the concurrency related stuff.
When we fetch the entity from the table service using the client library, library will store the ETag associated with the entity (which present in the response from the service for the entity) in an EntityDescriptior instance (EntityDescriptor is an object maintained by the library for each entity instance in the context)
When you submit a request to update an entity, sdk will prepare HTTP request with body as entity serialized to XML and ETag header of the request as the ETag value stored in the entity descriptor corresponding to the entity.
When the table service receives this request for updating the entity instance, it checks whether the ETag in the request matches with the ETag currently associated with entity in the table storage (the ETag associated with the entity stored in the service changes if some other update happened before receiving your update request), if it does not matches service returns pre-condition failed/conflict error by setting Http status code in the response to 412 or 409.
bool done = true;
while (!done)
{
Stat statistics = _context.Execute<Stat>(new Uri("https://management.core.windows.net/<subscription-id>/services/storageservices/StatEntity?RowKey=..&PartitionKey=..").FirstOrDefault();
try
{
// TODO: Update the entity, e.g. statistics.ReadCount++
_context.UpdateObject(statistics);
_context.SaveChanges();
// success
break;
}
catch (DataServiceRequestException exception)
{
var response = exception.Response.FirstOrDefault();
if (response != null && (response.StatusCode == 412 || response.StatusCode == 409))
{
// Concurrency Exception - Entity Updated in-between
// by another thread, Fetch the latest _stat entity and repeat operation
}
else
{
// log it and come out of while loop
break;
}
}
catch (Exception)
{
// log it and come out of while loop
break;
}
}
The ETag is used for optimistic concurrency during updates. The ETag is set automatically when you retrieve an entity and is uploaded automatically when you update that queried entity. The update would fail if the entity has in the meantime been updated by another thread. The updateEntity method has an optional parameter, checkEtag, that can be used to modify this behavior by allowing you to specigy that the update should succeed regardless of whether or not another thread has updated the record - thereby overriding the optimistic concurrency.
The Windows Azure Storage Service REST API is the definitive interface to Windows Azure Storage, and htis is the documentation to go to when you want to understand the API capabilities of the service. The documention describing ETag, in general, is here.
I have a service level methods, which make few changes to database and I want them to use transaction control. Such methods can do following:
- LINQ SubmitChanges() functionality
- Calls to StoredProcedures
Component users can combine set of such elementary operations into something bigger.
I see that there is nice class TransactinScope and trying to use it:
using (TransactionScope transaction = new TransactionScope())
{
content = repository.CreateBaseContent(content);
result = repository.CreateTreeRelation(content, parent.Id, name);
transaction.Complete();
}
public baseContent CreateBaseContent(baseContent content)
{
EntityContext.baseContents.InsertOnSubmit(content);
EntityContext.SubmitChanges();
return content;
}
public CreateTreeRelation (params)
{
// do StoredProcedure call here via LINQ
}
My Assumption was that on outer layers it would be possible to add another level of transaction scope. Instead, I am having following error:
The transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D024)
I am using same (Vista Ultimate) machine for MS SQL 2005 and microsoft development server. From unit tests everything works fine. Same when TransactionScope commented.
I was trying to play with security for DTC (http://support.microsoft.com/kb/899191) and when I set to acccept all inbound and outbound transactions, I have following error message:
Error HRESULT E_FAIL has been returned from a call to a COM component.
During debug, I discovered that in SubmitChanges, Linq Entity Context has Property Transaction IS NULL(!!), and System.Transactions.Transaction.Current has open transaction
I think you can also use TransactionScope as long as you pass the datacontexts the same connection you .Open.
Another issue you get with TransactionScope is that it doesn't care if the connection string is the same, doing a second .Open will elevate the transaction to a distributed transaction. And then you have to deal with the related configuration, and also the fact that it isn't using the light transaction that is what is needed for that case.
Issue happened because Linq Datacontext was created before transactionscope.
Solution was to add own transaction control to LINQ datacontext.
Connection.Open()
Transaction = Connection.BeginTransaction();
and counters to maintain nested calls.