I read a lot of documents and articles about DBcontext in Efcore and its lifetime, however, I have some questions.
Based on this link "https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration/" the best lifetime of DBcontext and default lifetime of AddDbContext is scope, but there is a contradiction in the two below sentences on this document.
"DbContext is not thread-safe. Do not share contexts between
threads. Make sure to await all async calls before continuing to use
the context instance."
on the other hand, it was mentioned too,
"Dbcontext is safe from concurrent access issues in most
ASP.NET Core applications because there is only one thread executing
each client request at a given time, and because each request gets
a separate dependency injection scope (and therefore a separate
DbContext instance)."
I was confused about whether registering DBcontext as a scoped service is thread-safe or not?
What are the problems of registering DBcontext as a singleton service in detail?
In addition, I read some docs that prohibit registering singleton DbContext, however, AddDbContextPool makes to register singleton DBcontext.
so there are some questions about the Dbcontextpool.
what are the impacts of using the DbContextPool instead of the DbContext?
when we should use it and what should be considered when we use contextPool?
DbContextPool is thread-safe?
Has it memory issues because of storing a number of dbset instances throughout the application's lifetime?
change-tracking or any parts of the ef would be failed or not in the DB context pool?
One DbContext per web request... why?
.NET Entity Framework and transactions
I understand why you think the language in the Microsoft documents is confusing. I'll unravel it for you:
"DbContext is not thread-safe." This statement means that it's not safe to access a DbContext from multiple threads in parallel. The stack overflow answers you already referenced, explain this.
"Do not share contexts between threads." This statement is confusing, because asynchronous (async/await) operations have the tendency to run across multiple threads, although never in parallel. A simpler statement would be: "do not share contexts between web requests," because a single web request typically runs a single unit of work and although it might run its code asynchronously, it typically doesn't run its code in parallel.
"Dbcontext is safe from concurrent access issues in most ASP.NET Core applications": This text is a bit misleading, because it might make the reader believe that DbContext instances are thread-safe, but they aren't. What the writers mean to say here is that, with the default configuration (i.e. using AddDbContext<T>(), ASP.NET Core ensures that each request gets its own DbContext instance, making it, therefore, "safe from concurrent access" by default.
1 I was confused about whether registering DBcontext as a scoped service is thread-safe or not?
DbContext instances are by themselves not thread-safe, which is why you should register them as Scoped, because that would prevent them from being accessed from multiple requests, which would make their use thread-safe.
2 What are the problems of registering DBcontext as a singleton service in detail?
This is already described in detail in this answer, which you already referenced. I think that answer goes into a lot of detail, which I won't repeat here.
In addition, I read some docs that prohibit registering singleton DbContext, however, AddDbContextPool makes to register singleton DBcontext. so there are some questions about the Dbcontextpool.
The DbContext pooling feature is very different from registering DbContext as singleton, because:
The pooling mechanism ensures that parallel requests get their own DbContext instance.
Therefore, multiple DbContext instances exist with pooling, while only a single instance for the whole application exists when using the Singleton lifestyle.
Using the singleton lifestyle, therefore, ensures that one single instance is reused, which causes the myriad of problems laid out (again) here.
The pooling mechanism ensures that, when a DI scope ends, the DbContext is 'cleaned' and brought back to the pool, so it can be reused by a new request.
what are the impacts of using the DbContextPool instead of the DbContext?
More information about this is given in this document.
when we should use it and what should be considered when we use contextPool?
When your application requires the performance benefits that it brings. This is something you might want to benchmark before deciding to add it.
DbContextPool is thread-safe?
Yes, in the same way as registering a DbContext as Scoped is thread-safe; in case you accidentally hold on to a DbContext instance inside an object that is reused accross requests, this guarantee is broken. You have to take good care of Scoped objects to prevent them from becoming Captive Dependencies.
Has it memory issues because of storing a number of dbset instances throughout the application's lifetime?
The memory penalty will hardly ever be noticable. The so-called first-level cache is cleared for every DbContext that is brought back to the pool after a request ends. This is to prevent the DbContext from becoming stale and to prevent memory issues.
change-tracking or any parts of the ef would be failed or not in the DB context pool?
No, it doesn't. For the most part, making your DbContext pooled is something that only requires infrastructural changes (changes to the application's startup path) and is for the most part transparent to the rest of your application. But again, make sure to read this to familiar yourself with the consequences of using DbContext pooling.
Related
I get it that all the operations involving the DB access should not be called in parallel. Creating DbContext is cheap, use the new one, all that.
But what about the local operations, like DbSet.Add(...), or DbSet.Local.<...>? They happen almost instantly, so the chances of race conditions are extremely low, but still. What are the underlying containers in DbSet? Do they support thread-safe operations?
Based on a GitHub issue and this answer, DbSet is not considered thread-safe. The responses from the GitHub issue indicate that anything in EFCore that is not a singleton should be considered non-thread-safe.
I'm using Hibernate in an embedded Jetty server, and I want to be able to parallelize my data processing with some multithreading and still have it all be in the same transaction. As Sessions are not thread safe this means I need a way to get multiple sessions attached to the same transaction, which means I need to switch away from the "thread" session context I've been using.
By my understanding of the documentation, this means I need to switch to JTA session context, but I'm having trouble getting that to work. My research so far seems to indicate that it requires something external to Hibernate in the server to provide transaction management, and that Jetty does not have such a thing built in, so I would have to pull in some additional library to do it. The top candidates I keep running across for that generally seem to be large packages that do all sorts of other stuff too, which seems wasteful, confusing, and distracting when I'm just looking for the one specific feature.
So, what is the minimal least disruptive setup and configuration change that will allow getCurrentSession() to return Sessions attached to the same transaction in different threads?
While I'm at it, I know that fetching objects in one thread and altering them in another is not safe, but what about reading their properties in another thread, for example calling toString() or a side effect free getter?
While reading some material (like this one) on how to create a service application that spawns a separate worker thread for each service request (because my service requests are likely to entail lengthy database operations), I've come across references to TThread and other references to TServiceThread. Now I'm confused. Which one should I use? and Why? and if you want to be super helpful and want to share your expertise on how or maybe you know of an exceptionally great link (emphasis on quality of content on the other side of that link) then that would contribute to the resolution of this asker's situation. Thanks anyway.
TServiceThread is the thread that implements the main service thread. It is intended solely for that purpose and you should not derive your work thread from TServiceThread. For a worker thread, derive from TThread.
The documentation is perhaps a little hazy, but it does point in the right direction:
TServiceThread represents the thread associated with a specific
service (TService object).
TServiceThread is the thread associated with a service. Each service
application has one or more service objects, each of which has its own
dedicated thread. TServiceThread instances represent those threads.
And take a look at the implementation of TServiceThread.Execute. It contains all the logic that is needed to implement a service's main thread. It is clearly not appropriate for a worker thread.
Given: simple JSF webapp (no Seam), having JSF beans calling few EJB's which in turn load and persist JPA entities. What I want to is to use #Singleton annotation for ejb's and inject EntityManager instead of EntityManagerFactory:
#Singleton
public class MyEJB {
#PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
protected EntityManager em; // not EntityManagerFactory
}
Spec says that #Singleton is thread-safe, supports concurrency and transaction attributes which (from my pov) makes it safe for calling from JSF beans. I expect also performance benefits because of EntityManager not being recreated for each call and it's internal caching abilities.
My main concern here is create/update operations on JPA entities in the situation when I have several singletons and, as a result, the same count of long-living EntityManagers.
What happens if one singleton updates an JPA instance and how these
changes are populated to other singletons?
As I'm not able to close entity manager, do I need to flush it upon
each entity update?
Would it be better if these few singletons will share the same entity
manager?
I saw only few examples of such design. Why? Are there any serious
drawbacks?
Many thanks in advance!
I expect also performance benefits because of EntityManager not being recreated for each call and it's internal caching abilities.
You might save some memory using singletons, but using it everywhere in your app could make it actually slower, because as there's only one EJB to serve all the concurrent requests by various users of your app, the container locks access to the EJB and when it's busy serving a request it cannot be serving another request. However this can be alleviated to some degree using lock types (i.e. #Lock(WRITE) and #Lock(READ)).
Singletons are useful for times when you want to execute a piece of code periodically using EJB timers, or to update a cache periodically, etc.
What happens if one singleton updates an JPA instance and how these changes are populated to other singletons?
Shouldn't be any different to the way non-singleton EJBs behave.
As I'm not able to close entity manager, do I need to flush it upon each entity update?
If you use CMT, no. At the end of each transaction everything will be flushed automatically.
Would it be better if these few singletons will share the same entity manager?
Looks like premature optimization to me. Just let the container inject the EM for you.
I saw only few examples of such design. Why? Are there any serious drawbacks?
Already explained.
There is one thing I want to mention regarding changing LockType of Singleton EJBs. While in general it sounds like a good idea, you should remember that resources such as EntityManger are NOT thread-safe, so appropriate concurrent access control should be provided. You can annotate methods that access non-thread-safe resources with #Lock(WRITE), but if almost all interface methods of your Singleton EJB access such resources, you will have almost the same situation as with fully write locked one. Alternative is to use Bean Concurrency Management with manual fine-grained synchronization, but it's also questionable decision.
Because of this in general I prefer Stateless EJBs over Singleton and use latter in specific cases.
In a Message-Driven Bean am I restricted to the same rules of Session Beans (EJB3 or EJB3.1), i.e:
use the java.lang.reflect Java Reflection API to access information unavailable by way of the security rules of the Java runtime environment
read or write nonfinal static fields
use this to refer to the instance in a method parameter or result
access packages (and classes) that are otherwise made unavailable by the rules of Java programming language
define a class in a package
use the java.awt package to create a user interface
create or modify class loaders and security managers
redirect input, output, and error streams
obtain security policy information for a code source
access or modify the security configuration objects
create or manage threads
use thread synchronization primitives to synchronize access with other enterprise bean instances
stop the Java virtual machine
load a native library
listen on, accept connections on, or multicast from a network socket
change socket factories in java.net.Socket or java.net.ServerSocket, or change the stream handler factory of java.net.URL.
directly read or write a file descriptor
create, modify, or delete files in the filesystem
use the subclass and object substitution features of the Java serialization protocol
It is always a good idea not to create threads manually (ExecutorService seems fine in some cases though).
Actually MDBs are very often used to address this limitation: instead of creating a separate thread, send some task object (put something like MyJob extends Serializable in ObjectMessage) into the queue and let it be executed in MDB thread pool. This approach is much more heavyweight but scales very well and you don't have to manage any threads manually. In this scenario JMS is just a fancy way of running jobs asynchronously.
These EJB restrictions are typically not hard restrictions. In fact, they're not caveats on making your EJBs work properly, they're more like advisories on how to make your EJBs portable across EJB containers.
From time to time, some very fussy EJB container providers (cough.... WebSphere... cough) will actually enforce these restrictions through java security policies, but I would say about half of those restrictions are routinely ignored ( I mean just using log4j in your MDB potentially violates about 30% of them).
Violating the the other 70% probably indicates some architectural or design problem.
So, can you call System.exit() in an MDB ? The answer is yes, but only once... :)
It sounds like, in your case, you need some of these restrictions to reign in potentially misbehaving plugins. I don't know if MDBs are going to get you out of that problem. I suppose it depends on how much you trust the third party developers, but rather than use the invocation based models in EJB, I would install the components as JMX ModelMBeans. You can use the java security model to limit what they can do, but I suppose that would defeat the purpose.
Perhaps using some run (or load) time AOP byte code engineering, you could rewrite all requests for threads to be redirected to a per component thread factory that you allocate and limits the threads that can be created. Because you don't want to stop them from doing whatever it is that they do, you just don't want them to take down the whole server when they crash/stall/misbehave.
Interesting problem.