We have a central database for accounts. It contains login information, and a field called database profile. The database profile indicates what database connection should be used for the account. For example, we would have Profile1, Profile2, Profile3... ProfileN
If a user is indicated to have Profile1, they would be using a different database than a user who is indicated to be a part of Profile2.
My understanding of JPA is that you would need a new EntityManagerFactory for each Profile (Persistence Unit), even though the databases all have the same schema, just different connection information. So if we ended up having 100 profiles we would have 100 Entity Manager Factories, which doesn't seem ideal.
I've looked into the EntityManagerFactory, and it doesn't seem to let you change the database connection options.
Is my only option to have N EntityManagerFactory's, and if so would their be be any major consequences to this (such as bad performance)?
Thanks for any advice.
The kinds of things you're talking about are getting out of the scope of the JPA abstraction. Things like specific connection management are generally more provider specific. For example, with Hibernate SessionFactory you can certainly create new sessions from an aribtraty JDBC connection. There would be pitfalls to consider such as ID generation schemes (you'll probably have to use sequences generated in the DB), and you're basically hooped for L2 caching, but with careful programming it could be made to work.
Just use javax.persistence.Persistence#createEntityMananagerFactory(String,Map), and provide in the Map the connection parameters. Cache the EMF, and use the connections judiciously, don't mix n match object from the different EMFs.
If you are using spring then I know there is a way to dynamically switch the DataSource. Find more information here
Related
We have a somewhat huge application which started a decade ago and is still under active development. So some parts are still in J2EE 1.4 architecture, others using Java EE 5/6.
While testing some new code, I realized that I had data inconsistency between information coming in through old and new code parts, where the old one uses the Hibernate session directly and the new one an injected EntityManager. This led to the problem, that one part couldn't see new data from the other part and thus also created a database record, resulting in primary key constraint violation.
It is planned to migrate the old code completely to get rid of J2EE, but in the meantime - what can I do to coordinate database access between the two parts? And shouldn't at some point within the application server both ways come together in the Hibernate layer, regardless if accessed via JPA or directly?
You can mix both Hibernate Session and Entity Manager in the same application without any problem. The EntityManagerImpl simply delegates calls the a private SessionImpl instance.
What you describe is a Transaction configuration anomaly. Every database transaction runs in isolation (unless you use REAN_UNCOMMITED which I guess it's not the case), but once you commit it the changes are available from any other transaction or connection. So once a transaction is committed you should see al changes in any other Hibernate Session, JDBC connection or even your database UI manager tool.
You said that there was a primary key conflict. This can't happen if you use Hibernate identity or sequence generator. For the old hi-lo generator you can have problems if an external connection tries to insert records in the same table Hibernate uses an old hi/lo identifier generator.
This problem can also occur if there is a master/master replication anomaly. If you have multiple nodes and there is no strict consistency replication you can end up with primar key constraint violations.
Update
Solution 1:
When coordinating the new and the old code trying to insert the same entity, you could have a slect-than-insert logic running in a SERIALIZABLE transaction. The SERIALIZABLE transaction acquires the appropriate locks on tour behalf and so you can still have a default READ_COMMITTED isolation level, while only the problematic Service methods are marked as SERIALIZABLE.
So both the old code and the new code have this logic running a select for checking if there is already a row satisfying the select constraint, only to insert it if nothing is found. The SERIALIZABLE isolation level prevents phantom reads so I think it should prevent constraint violations.
Solution 2:
If you are open to delegate this task to JDBC, you might also investigate the MERGE SQL statement, if your current database supports it. Basically, this is an upsert operation issuing an update or an insert behind the scenes. This command is much more attractive since you can still run it with even on READ_COMMITTED. The only drawback is that you can't use Hibernate for it, and only some databases support it.
If you instanciate separately a SessionFactory for the old code and an EntityManagerFactory for new code, that can lead to different value in first level cache. If during a single Http request, you change a value in old code, but do not immediately commit, the value will be changed in session cache, but it will not be available for new code until it is commited. Independentely of any transaction or database locking that would protect persistent values, that mix of two different Hibernate session can give weird things for in memory values.
I admit that the injected EntityManager still uses Hibernate. IMHO the most robust solution is to get the EntityManagerFactory for the PersistenceUnit and cast it to an Hibernate EntityManagerFactoryImpl. Then you can directly access the the underlying SessionFactory :
SessionFactory sessionFactory = entityManagerFactory.getSessionFactory();
You can then safely use this SessionFactory in your old code, because now it is unique in your application and shared between old and new code.
You still have to deal with the problem of session creation-close and transaction management. I suppose it is allready implemented in old code. Without knowing more, I think that you should port it to JPA, because I am pretty sure that if an EntityManager exists, sessionFactory.getCurrentSession() will give its underlying Session but I cannot affirm anything for the opposite.
I've run into a similar problem when I had a list of enumerated lookup values, where two pieces of code would check for the existence of a given value in the list, and if it didn't exist the code would create a new entry in the database. When both of them came across the same non-existent value, they'd both try to create a new one and one would have its transaction rolled back (throwing away a bunch of other work we'd done in the transaction).
Our solution was to create those lookup values in a separate transaction that committed immediately; if that transaction succeeded, then we knew we could use that object, and if it failed, then we knew we simply needed to perform a get to retrieve the one saved by another process. Once we had a lookup object that we knew was safe to use in our session, we could happily do the rest of the DB modifications without risking the transaction being rolled back.
It's hard to know from your description whether your data model would lend itself to a similar approach, where you'd at least commit the initial version of the entity right away, and then once you're sure you're working with a persistent object you could do the rest of the DB modifications that you knew you needed to do. But if you can find a way to make that work, it would avoid the need to share the Session between the different pieces of code (and would work even if the old and new code were running in separate JVMs).
ThreadLocal<Session> tl = new ThreadLocal<Session>();
tl.set(session);
to get the session,
Employee emp = (Employee)((Session)tl.get().get(Employee.class, 1));
If our application is web based, the web container creates a separate thread for each request.
If all these requests concurrently using the same single Session object , we should get
unwanted results in our database operations.
To overcome from above results, it is good practice to set our session to threadLocal object
which does not allows concurrent usage of session.I think, If it is correct the application performance should be very poor.
What is the good approach in above scenarios.
If I'm in wrong track , in which situations we need to go for ThreadLocal.
I'm new to hibernate, please excuse me if this type questioning is silly.
thanks in advance.
Putting the Hibernate Session in ThreadLocal is unlikely to achieve the isolation between requests that you want. Surely you create a new Session for each request using a SessionFactory backed by a connection pooling implementation of DataSource, which means that the local reference to the Session is on the stack anyway. Changing that local reference to a member variable only complicates the code, imho.
Anyhow, ensuring isolation within a single container doesn't address the actual problem - how is data accessed efficiently while maintaining consistency within a multi-threaded environment.
There are two parts to the problem you mention - the first is that a database connection is an expensive resource, the second that you need to ensure some level of data consistency between threads/requests.
The general approach to the resource problem is to use a database connection pool (which I'd guess you're already doing). As each request is processed, connections are obtained from the pool and returned when finished but importantly the connections in the pool are maintained beyond the lifetime of a request thus avoiding the cost of creating a connection each time it is needed.
The consistency problem is a little trickier and there's no one size fits all model. What you need to be doing is thinking about what level of consistency you need - questions like does it matter if data is read at the same time it's being written, do updates absolutely have to be atomic, etc.
Once you know the answer to these questions there two places you need to look at consistency - in the database and in the code.
With the database you need to look at database level locks and create a scheme suitable for your application by applying that appropriate isolation levels.
With the code, things are a little more complicated. Data is often loaded and displayed for a period of time before updates are written back - no problem if there's a single user but in a multi-user system it's possible that updates are made based on stale data or multiple updates occur simulatiously. It may be acceptable to have a policy of last update wins, in which case it's simple, but if not you'll need to be using version numbers or old/new comparisons to ensure integrity at the time the updates are applied.
I am not sure if you have compulsion of using ThreadLocal. Using ThreadLocal to store session object is definitely is not a good idea, specially when you are using hibernate along with spring.
A typical scheme for using Hibernate with Spring is:
Inject the sessionFactory in your DAO. I assume that you have sessionFactory already configured which is backed by a pooled datasource.
Now in your DAO class, a session can be accessed as follows.
Session session = sessionFactory.getCurrentSession();
Here is a link to related article.
Please note that this example is specific to Hiberante 3.x APIs. This takes care of session creation/closure/thread-safety aspect internally and its neat too.
I'm coaching a student project which uses hibernate as a persistence layer. From my projects at work I'm already quite familiar with hibernate and can use it with few 'troubles'. But with this project we have constantly problem with sessions, stale objects and and 'object was loaded from a different session'-errors.
So what I am looking for the simplest possible way to use sessions:
Ideal would be:
Sessions can be fetched from anywhere
It shouldn't matter whether or not a given object was loaded with session A and then updated with Session B
Its a single-process GUI application. The current setting for current_session_context_class is thread. But I use a static field for the session variable (which I think causes some of my troubles) and only fetch it ONCE.
Thanks for your assistance!
Cheers,
Reto
Assuming you're not teaching ORM, the understanding of why these errors happen isn't part of the knowledge the students are supposed to come away with etc etc etc and you just want Hibernate to work as a database wrapper so they can get data to use while learning other things.
This is probably your best bet:
StatelessSession session = sessionFactory.openStatelessSession();
A stateless session is effectively "auto-commit mode for ORM" and as close to raw-JDBC wrapper as hibernate gets. No Sessions, no L1 caches, no persistence context. Just SQL/HQL that returns objects.
I'm developing a web app with Spring and Hibernate and I was so obsessed by making he application thread safe and being able to support heavy load that based on my boss recommendation I end up writing my own session and a session container to implement a session per request pattern. Plus I have a lot of DAOs and me not willing to write the same save method for all the DAOs I copy paste this Hibernate GenericDAO (I can't tell it's the same thing because at the time hibernate wasn't owned by jboss) and do the plumbing stuff, and under pressure, all become quickly complicated and on production, the is StaleObjectException and duplicated data right, and i have the feeling that it's time to review what I've done, simplify it and make it more robust for large data handling. One thing you should know is that one request involves many DAO's.
There is quartz running for some updates in the database.
As much as I want to tune everything for the better I lack time to do the necessary research plus Hibernate is kind of huge (learning).
So this is it, I'll like to borrow your experience and ask for few question to know what direction to take.
Question 1 : is Hibernate generated uuid safe enough for threading environment and avoiding StaleObjectException?
Question 2 what are best strategy to use hibernate getCurrentSession in threadSafe scenario (I've read about threadlocal stuff but didn't get too much understanding so didn't do it)
Question 3 : will HIbernateTemplate do for the simplest solution approach?
Question 4 : what will be your choice if you were to implement a connection pool and tuning requirement for production server?
Please do no hesitate to point me to blogs or resources online , all that I need is a approach that works for my scenario. your approach if you were to do this.
Thanks for reading this, everybody's idea is welcomed...
I'm developing a web app with Spring and Hibernate and I was so obsessed by making he application thread safe and being able to support heavy load that based on my boss recommendation I end up writing my own session and a session container to implement a session per request pattern.
You should just drop all this code and use Spring/Hibernate APIs instead: less bugs, less maintenance.
I copy paste this Hibernate GenericDAO (I can't tell it's the same thing because at the time hibernate wasn't owned by jboss) and do the plumbing stuff, and under pressure, all become quickly complicated (...)
You can use a GenericDao and inject the required stuff with Spring.
Question 1: is Hibernate generated uuid safe enough for threading environment and avoiding StaleObjectException?
To strictly answer your question, here is what Reference Guide writes about the uuid generator:
5.1.4.1. Generator
...
uuid
uses a 128-bit UUID algorithm to
generate identifiers of type string
that are unique within a network (the
IP address is used). The UUID is
encoded as a string of 32 hexadecimal
digits in length.
So I consider it as safe. But I think your StaleObjectException are unrelated (it's another problem).
Question 2: what are best strategy to use hibernate getCurrentSession in threadSafe scenario (I've read about threadlocal stuff but didn't get too much understanding so didn't do it)
The best strategy is to just use it, sessionFactory.getCurrentSession() will always give you a Session scoped to the current database transaction aka a "contextual session". Again, quoting the Reference Documentation:
2.5. Contextual sessions
Most applications using Hibernate need
some form of "contextual" session,
where a given session is in effect
throughout the scope of a given
context. However, across applications
the definition of what constitutes a
context is typically different;
different contexts define different
scopes to the notion of current.
Applications using Hibernate prior to
version 3.0 tended to utilize either
home-grown ThreadLocal-based
contextual sessions, helper classes
such as HibernateUtil, or utilized
third-party frameworks, such as Spring
or Pico, which provided
proxy/interception-based contextual
sessions.
(...)
However, as of version 3.1, the
processing behind
SessionFactory.getCurrentSession()
is now pluggable. To that end, a new
extension interface,
org.hibernate.context.CurrentSessionContext,
and a new configuration parameter,
hibernate.current_session_context_class,
have been added to allow pluggability
of the scope and context of defining
current sessions.
See the Javadocs for the
org.hibernate.context.CurrentSessionContext
interface for a detailed discussion of
its contract. It defines a single
method, currentSession(), by which
the implementation is responsible for
tracking the current contextual
session. Out-of-the-box, Hibernate
comes with three implementations of
this interface:
org.hibernate.context.JTASessionContext:
current sessions are tracked and
scoped by a JTA transaction. The
processing here is exactly the same as
in the older JTA-only approach. See
the Javadocs for details.
org.hibernate.context.ThreadLocalSessionContext:
current sessions are tracked by thread
of execution. See the Javadocs for
details.
org.hibernate.context.ManagedSessionContext:
current sessions are tracked by thread
of execution. However, you are
responsible to bind and unbind a
Session instance with static methods
on this class: it does not open,
flush, or close a Session.
(...)
There is no need to implement your own ThreadLocal-based solution nowadays, don't do that.
Question 3 : will HIbernateTemplate do for the simplest solution approach?
Well, the HibernateTemplate is not deprecated but it is not recommended anymore and I prefer to implement template-less DAOs:
public class ProductDaoImpl implements ProductDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Collection loadProductsByCategory(String category) {
return this.sessionFactory.getCurrentSession()
.createQuery("from test.Product product where product.category=?")
.setParameter(0, category)
.list();
}
}
Where the SessionFactory is injected by Spring. I suggest to read So should you still use Spring's HibernateTemplate and/or JpaTemplate?? for complete background and also the whole section 13.3. Hibernate in the Spring documentation on ORM Data Access.
Question 4 : what will be your choice if you were to implement a connection pool and tuning requirement for production server?
Hmm... What? I would never implement my connection pool but use the one from my application server. Maybe you should clarify this question.
Update: In production, I wouldn't use Hibernate built-in connection pool but configure Hibernate to use an application server provided JNDI datasource (and thus the application server connection pool). From the documentation:
3.3. JDBC connections
...
Here is an example hibernate.properties file for an application server provided JNDI datasource:
hibernate.connection.datasource = java:/comp/env/jdbc/test
hibernate.transaction.factory_class = \
org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \
org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
JDBC connections obtained from a JNDI datasource will automatically participate in the container-managed transactions of the application server.
For each client, I have separate databases but business logic and tables are same for each client. I want common service and dao layer for each client. In dao, I select datasource based on logged user client. In #Transactional, I have to pass bean id of transaction manager. How to make common service layer with #Transactional annotation.
Same question is here
Multiple transaction managers - Selecting a one at runtime - Spring
Choose between muliple transaction managers at runtime
but nobody reply
If you want to create a database connection dynamically, then have a look at this SO post.
From the post linked : Basically in JDBC most of these properties are not configurable in the
API like that, rather they depend on implementation. The way JDBC
handles this is by allowing the connection URL to be different per
vendor.
So what you do is register the driver so that the JDBC system can know
what to do with the URL:
DriverManager.registerDriver((Driver)
Class.forName("com.mysql.jdbc.Driver").newInstance());
Then you form
the URL:
String url =
"jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]"
And finally, use it to get a connection:
Connection c = DriverManager.getConnection(url);
In more
sophisticated JDBC, you get involved with connection pools and the
like, and application servers often have their own way of registering
drivers in JNDI and you look up a DataSource from there, and call
getConnection on it.
In terms of what properties MySQL supports, see here (The link is dead).
EDIT: One more thought, technically just having a line of code which
does Class.forName("com.mysql.jdbc.Driver") should be enough, as the
class should have its own static initializer which registers a
version, but sometimes a JDBC driver doesn't, so if you aren't sure,
there is little harm in registering a second one, it just creates a
duplicate object in memeory.
I don't know if this will work, since I have not tested it, but you
could try.
Now what you could do is, use the #Transactional annotation on top of the DAOs without specifying any values (That works). Now in your DAO classes, instead of injecting any DataSource bean, create your own dataSource dynamically as specified in the above link and then either inject that dependency at runtime, use getter setter methods, or just use the new keyword. I hope that'd do the trick.
NOTE: I have not tested it myself yet, so if this works, do let me know.
You do not need to configure and switch between multiple transaction managers to accomplish your end goal. Instead use the Spring provided org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource mechanism.
Detailed examples can be found here :
https://spring.io/blog/2007/01/23/dynamic-datasource-routing/
http://howtodoinjava.com/spring/spring-orm/spring-3-2-5-abstractroutingdatasource-example/