I am not new to hibernate, concurrrency problems, and stale exceptions.
Im working in grails with GORM in a high concurrent environment. Optimistic locking is on and im using static lock method whithin a transactional service.
for(Entity entity : entityList) {
//refresh and lock for update
entity.refresh();
entity = Entity.lock(entity.id)
entity.setSomeData(new Date());
entity.save()
}
It is somehow possible to have an HibernateOptimisticLockingFailureException in this scenario??
Please note the stack trace:
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xxxxx.xxx.xxxxx.Entity#48225]
at org.hibernate.dialect.lock.PessimisticWriteSelectLockingStrategy.lock(PessimisticWriteSelectLockingStrategy.java:94)
at org.hibernate.persister.entity.AbstractEntityPersister.lock(AbstractEntityPersister.java:1954)
at org.hibernate.event.internal.AbstractLockUpgradeEventListener.upgradeLock(AbstractLockUpgradeEventListener.java:102)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromSessionCache(DefaultLoadEventListener.java:560)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:430)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:212)
at org.hibernate.event.internal.DefaultLoadEventListener.lockAndLoad(DefaultLoadEventListener.java:391)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:153)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
at org.hibernate.internal.SessionImpl.access$2000(SessionImpl.java:176)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2544)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:1023)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate$5.doInHibernate(GrailsHibernateTemplate.java:282)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:179)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.lock(GrailsHibernateTemplate.java:279)
at org.codehaus.groovy.grails.orm.hibernate.HibernateGormStaticApi.lock(HibernateGormStaticApi.groovy:221)
at com.xxxxx.xxx.xxxxx.Entity.lock(Entity.groovy)
How is possible for static Entity.lock() to throw a stale object exception??
Related
I am a getting a MappingException error when executing the following piece of code:
Configuration configuration = new Configuration.Builder()
.uri("file:///var/lib/neo4j/data/databases/graph.db")
.credentials("neo4j","noor")
.build();
SessionFactory sessionFactory = new SessionFactory(configuration,"OntologyDescription","info.testNeo");
Session session = sessionFactory.openSession();
ResourceDescription classDescription = OntologyUtils.getClassDescription(classIRI,
dogont);
session.save(classDescription);
sessionFactory.close();
Full trace:
Exception in thread "main" org.neo4j.ogm.exception.core.MappingException: Field with primary id is null for entity state
at org.neo4j.ogm.context.MappingContext.nativeId(MappingContext.java:514)
at org.neo4j.ogm.context.EntityGraphMapper.newNodeBuilder(EntityGraphMapper.java:318)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntity(EntityGraphMapper.java:257)
at org.neo4j.ogm.context.EntityGraphMapper.mapRelatedEntity(EntityGraphMapper.java:797)
at org.neo4j.ogm.context.EntityGraphMapper.link(EntityGraphMapper.java:501)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:414)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntity(EntityGraphMapper.java:265)
at org.neo4j.ogm.context.EntityGraphMapper.map(EntityGraphMapper.java:149)
at org.neo4j.ogm.session.delegates.SaveDelegate.lambda$save$1(SaveDelegate.java:89)
at java.util.Collections$SingletonList.forEach(Collections.java:4822)
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:89)
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:51)
at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:468)
at Examples.TestNeo4j.main(TestNeo4j.java:41)
I am getting the error only when getting classDescription from the OntologyUtils.getClassDescription method. However, if I instantiate a ResourceDescription newly, I don't get the error. In short, OntologyUtils.getClassDescription calls several other methods to add information to the new instance.
This problem was because the package names contain capital letters. As mentioned in this GitHub issue, package names should be completely in lower case
We have an Entity Framework execution strategy coded in our lower environment. How do we test this to show it's actually working? We don't want to release to Prod without something to say we aren't introducing new problems.
The easy way is to use some listener where you can throw an exception and subscribe this listener to the dbContext.
public class CommandListener
{
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting")]
public void OnCommandExecuting(DbCommand command, DbCommandMethod executeMethod, Guid commandId, Guid connectionId, bool async, DateTimeOffset startTime)
{
throw new TimeoutException("Test exception");
}
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted")]
public void OnCommandExecuted(object result, bool async)
{
}
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandError")]
public void OnCommandError(Exception exception, bool async)
{
}
}
Subscribe listener to dbContext f.i. in Startup.cs
var context = provider.GetService<SomeDbContext>();
var listener = context.GetService<DiagnosticSource>();
(listener as DiagnosticListener).SubscribeWithAdapter(new CommandListener());
As TimeoutException is transient exception in SqlServerRetryingExecutionStrategy.cs (if you use the default retrying strategy) you will get TimeoutException as many as your MaxRetryingCount of strategy setting has. Finally, you have to get RetryLimitExceededException as a result of the request.
You have to see TimeoutException in your app logs. Also it is good idea to turn on transaction logs "Microsoft.EntityFrameworkCore.Database.Transaction": "Debug"
What I did to manage to throw the transient exception and debug strategy (testing and playing around purpose only)
I added ExectuionStrategyBase.cs and
TestServerRetryingExecutionStrategy.cs. The first one is clone of
ExectuionStrategy.cs and second one is clone of
SqlServerRetryingExecutionStrategy.cs
In Startup.cs I set retrying strategy
strategy services.AddDbContext<SomeDbContext>(options =>
{options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), sqlOption =>
{
sqlOption.ExecutionStrategy(dependencies =>
{
return new TestSqlRetryingStrategy(
dependencies,
settings.SqlMaxRetryCount,
settings.SqlMaxRetryDelay,
null);
});
});
In OnCommandExecuting of CommandListener.sc I just checked some static bool variable to throw or not TimeoutException and in ExectuionStrategyBase.cs I swithced that variable.
Thus, I managed to throw transient Exception on the first execution of the query and successful execution on the second short. Now I think about some long running transaction and kill session of this transaction in SSCM during execution of it.
Also, I found out that if there is a query like
var users = context.Users.AsNoTracking().ToArrayAsync() execution strategy is not implemented and I am stuck on it. I have been struggling with that a couple of days but still can figure out nothing. If remove AsNoTracking or replace ToArrayAsync() by something like FirstAsync() all foes well.
What is proper way to get DB connection in Grails 3?
For grails 2 following code has works:
((SessionImpl) sessionFactory.getCurrentSession()).connection() // sessionFactory initialized in bootstrap
But after migration to Grails 3 sometimes I see exceptions in the log:
java.sql.SQLException: Operation not allowed after ResultSet closed at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860) at
com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:743) at
com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1037) at
com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2757) at
com.mchange.v2.c3p0.impl.NewProxyResultSet.getLong(NewProxyResultSet.java:424)
at java_sql_ResultSet$getLong$3.call(Unknown Source)
It happens for 0,01% of requests
Grails 3.2.11
Gorm 6.0.12
I guess it depends on where you need it, but you can inject a DataSource into a service.
javax.sql.DataSource dataSource
Then you can just use
dataSource.getConnection()
Also be aware of the changes to flush mode in GORM 6 (http://gorm.grails.org/6.0.x/hibernate/manual/ section 1.2.1). If an upstream save/commit is failing, your result set could be incidentally closed and trigger an error that looks like this while not really have anything to do with this particular line of code at all. I'd (very temporarily) set back to the old flush mode and see if the problem goes away, before tracking much more down!
From grails docs, you can get the actual dataSource bean. From that you can access the connection or use it to query your db
import groovy.sql.Sql
def dataSource
println "connection: ${dataSource.connection}"
Sql sql = new Sql(dataSource)
sql.eachRow("SELECT * FROM note") { row ->
println "row: ${row}"
}
Use 'dataSourceUnproxied' to avoid Hibernate transaction and session issues:
def dataSourceUnproxied
For executing queries inside current hibernate transactions following construction can be used:
sessionFactory.currentSession.doWork {connection ->
new Sql(connection).execute(query, params)
}
I am trying to enhance the in proc MVC cache to serve the old value while triggering a new thread to populate the new value.
This below code "works" if I remove the line:
ThreadPool.QueueUserWorkItem(delegate
By "works" I mean that the client that made the request that triggered the cache reload is blocked until the cache is refreshed, but all other clients continue to load against the shadow version.
Ideally, I want the processing to occur in the background and the client that triggered the cache refresh to use the shadow copy for that request. When they make a future request once the thread has completed they would be served the new cached values.
My solution relies heavily on Castle as the DI framework. I believe the problem I am getting is to do with LifeStyles in Castle. The error message is:
HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net
The exception happens deep in the bowels of the long running process (getCacheItem()) when it is trying to resolve a component that is required.
My cache method is as follows:
public T GetShadow<T>(string key, Func<T> getCacheItem, int timeOut)
{
if (Exists(key))
{
_log.Info("Shadow: Returning item from Cache: " + key);
return (T)HttpContext.Current.Cache[key];
}
var shadowKey = key + "-shadow";
if (Monitor.TryEnter(GetKeyLock(key)))
{
ThreadPool.QueueUserWorkItem(delegate
{
try
{
var item = getCacheItem(); // Long running query
// Replace the cache entry
HttpRuntime.Cache.Insert(key, item, null,
DateTime.UtcNow.AddMinutes(
timeOut), Cache.NoSlidingExpiration);
// And add its shadow for subsequent updates
HttpRuntime.Cache.Insert(shadowKey, item, null,
DateTime.UtcNow.AddMinutes(timeOut * 2), Cache.NoSlidingExpiration);
}
finally
{
Monitor.Exit(GetKeyLock(key));
}
});
}
while (!Exists(shadowKey))
{
Thread.Sleep(500);
}
return (T)HttpContext.Current.Cache[shadowKey];
}
So my question is, am I doing the thread creation correctly within MVC3??
Is there a better way to spin up a thread in this scenario that will not cause Windsor to throw an exception due to the PWR lifestyle?
So my question is, am I doing the thread creation correctly within MVC3??
No, you are using HttpContext.Current inside a background thread in an ASP.NET application. Your problem has nothing to do with Windsor nor ASP.NET MVC. It's just something that you can't do simply because background threads (as their name suggests) could run in the background outside from any user HTTP context. So attempting to access this context inside such a thread doesn't make any sense.
You could use the new caching features in .NET 4.0 thanks to the new MemoryCache class which was designed to be used independently of ASP.NET.
Background:
From another question here at SO I have a Winforms solution (Finance) with many projects (fixed projects for the solution).
Now one of my customers asked me to "upgrade" the solution and add projects/modules that will come from another Winforms solution (HR).
I really don't want to keep these projects as fixed projects on the existing finance solution. For that I'm trying to create plugins that will load GUI, business logic and the data layer all using MEF.
Question:
I have a context (DbContext built to implment the Generic Repository Pattern) with a list of external contexts (loaded using MEF - these contexts represent the contexts from each plugin, also with the Generic Repository Pattern).
Let's say I have this:
public class MainContext : DbContext
{
public List<IPluginContext> ExternalContexts { get; set; }
// other stuff here
}
and
public class PluginContext_A : DbContext, IPluginContext
{ /* Items from this context */ }
public class PluginContext_B : DbContext, IPluginContext
{ /* Items from this context */ }
and within the MainContext class, already loaded, I have both external contexts (from plugins).
With that in mind, let's say I have a transaction that will impact both the MainContext and the PluginContext_B.
How to perform update/insert/delete on both contexts within one transaction (unity of work)?
Using the IUnityOfWork I can set the SaveChanges() for the last item but as far as I know I must have a single context for it to work as a single transaction.
There's a way using the MSDTC (TransactionScope) but this approach is terrible and I'd reather not use this at all (also because I need to enable MSDTC on clients and server and I've had crashes and leaks all the time).
Update:
Systems are using SQL 2008 R2. Never bellow.
If it's possible to use TransactionScope in a way that won't scale to MSDTC it's fine, but I've never achieved that. All the time I've used TransactionScope it goes into MSDTC. According to another post on SO, there are some cases where TS will not go into MSDTC: check here. But I'd really prefer to go into some other way instead of TransactionScope...
If you are using multiple contexts each using separate connection and you want to save data to those context in single transaction you must use TransactionScope with distributed transaction (MSDTC).
Your linked question is not that case because in that scenario first connection do not modify data so it can be closed prior to starting the connection where data are modified. In your case data are concurrently modified on multiple connection which requires two-phase commit and MSDTC.
You can try to solve it with sharing single connection among multiple contexts but that can be quite tricky. I'm not sure how reliable the following sample is but you can give it a try:
using (var connection = new SqlConnection(connnectionString))
{
var c1 = new Context(connection);
var c2 = new Context(connection);
c1.MyEntities.Add(new MyEntity() { Name = "A" });
c2.MyEntities.Add(new MyEntity() { Name = "B" });
connection.Open();
using (var scope = new TransactionScope())
{
// This is necessary because DbContext doesnt't contain necessary methods
ObjectContext obj1 = ((IObjectContextAdapter)c1).ObjectContext;
obj1.SaveChanges(SaveOptions.DetectChangesBeforeSave);
ObjectContext obj2 = ((IObjectContextAdapter)c2).ObjectContext;
obj2.SaveChanges(SaveOptions.DetectChangesBeforeSave);
scope.Complete();
// Only after successful commit of both save operations we can accept changes
// otherwise in rollback caused by second context the changes from the first
// context will be already accepted = lost
obj1.AcceptAllChanges();
obj2.AcceptAllChanges();
}
}
Context constructor is defined as:
public Context(DbConnection connection) : base(connection,false) { }
The sample itself worked for me but it has multiple problems:
First usage of contexts must be done with closed connection. That is the reason why I'm adding entities prior to opening the connection.
I rather open connection manually outside of the transaction but perhaps it is not needed.
Both save changes successfully run and Transaction.Current has empty distributed transaction Id so it should be still local.
The saving is much more complicated and you must use ObjectContext because DbContext doesn't have all necessary methods.
It doesn't have to work in every scenario. Even MSDN claims this:
Promotion of a transaction to a DTC may occur when a connection is
closed and reopened within a single transaction. Because the Entity
Framework opens and closes the connection automatically, you should
consider manually opening and closing the connection to avoid
transaction promotion.
The problem with DbContext API is that it closes and reopens connection even if you open it manually so it is a opened question if API always correctly identifies if it runs in the context of transaction and do not close connection.
#Ladislav Mrnka
You were right from the start: I have to use MSDTC.
I've tried multiple things here including the sample code I've provided.
I've tested it many times with changed hare and there but it won't work. The error goes deep into how EF and DbContext works and for that to change I'd finally find myself with my very own ORM tool. It's not the case.
I've also talked to a friend (MVP) that know a lot about EF too.
We have tested some other things here but it won't work the way I want it to. I'll end up with multiple isolated transactions (I was trying to get them together with my sample code) and with this approach I don't have any way to enforce a full rollback automatically and I'll have to create a lot of generic/custom code to manually rollback changes and here comes another question: what if this sort of rollback fails (it's not a rollback, just an update)?
So, the only way we found here is to use the MSDTC and build some tools to help debug/test if DTC is enabled, if client/server firewalls are ok and all that stuff.
Thanks anyway.
=)
So, any chance this has changed by October 19th? All over the intertubes, people suggest the following code, and it doesn't work:
(_contextA as IObjectContextAdapter).ObjectContext.Connection.Open();
(_contextB as IObjectContextAdapter).ObjectContext.Connection.Open();
using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions{IsolationLevel = IsolationLevel.ReadUncommitted, Timeout = TimeSpan.MaxValue}))
{
_contextA.SaveChanges();
_contextB.SaveChanges();
// Commit the transaction
transaction.Complete();
}
// Close open connections
(_contextA as IObjectContextAdapter).ObjectContext.Connection.Close();
(_contextB as IObjectContextAdapter).ObjectContext.Connection.Close();
This is a serious drag for implementing a single Unit of Work class across repositories. Any new way around this?
To avoid using MSDTC (distributed transaction):
This should force you to use one connection within the transaction as well as just one transaction. It should throw an exception otherwise.
Note: At least EF6 is required
class TransactionsExample
{
static void UsingExternalTransaction()
{
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var sqlTxn = conn.BeginTransaction(System.Data.IsolationLevel.Snapshot))
{
try
{
var sqlCommand = new SqlCommand();
sqlCommand.Connection = conn;
sqlCommand.Transaction = sqlTxn;
sqlCommand.CommandText =
#"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'";
sqlCommand.ExecuteNonQuery();
using (var context =
new BloggingContext(conn, contextOwnsConnection: false))
{
context.Database.UseTransaction(sqlTxn);
var query = context.Posts.Where(p => p.Blog.Rating >= 5);
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context.SaveChanges();
}
sqlTxn.Commit();
}
catch (Exception)
{
sqlTxn.Rollback();
}
}
}
}
}
Source:
http://msdn.microsoft.com/en-us/data/dn456843.aspx#existing