How to implement updating of a table in a DB from different threads with Hibernate-based DAOs?
I have a class, let's call it UserGenerator
. It contains several injected DAOs (spring singleton beans), let's say UserDao
and OrganizationDao
.
UserGenerator
's purpose is creating users for a new organization. So, what I want to have is:
@Transactional
public void createOrganizationWithUsers(Organization org, int userCount) {
organizationDao.persist(org);
//run (userCount / 100) threads, let them do something like
// userDao.persist(new User(randomParams()));
}
The problem is that the organization is created successfully, but userDaos throw hardly-debugged exceptions and as I understand, they state that Hibernate session is closed (or, maybe, something else):
//this line (only if runs in a new thread) produces the exceptions
//shown below (it tries to retrieve the organization by its Id)
getSession().createCriteria(getDomainEntityClass()).add(Restrictions.eq("id",id)).uniqueResult();
//Exceptions
org.hibernate.exception.JDBCConnectionException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:97)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.loader.Loader.doList(Loader.java:2235)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2129)
at org.hibernate.loader.Loader.list(Loader.java:2124)
at org开发者_运维知识库.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:118)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1597)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:306)
at org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:328)
...
Caused by: org.postgresql.util.PSQLException: An I/ error occured while sending to the backend.
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:220)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:254)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1812)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.doList(Loader.java:2232)
... 28 more
Caused by: java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:135)
at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:104)
at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:73)
at org.postgresql.core.PGStream.ReceiveChar(PGStream.java:259)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1182)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:194)
... 36 more
What is the correct way to do this task?
P.S. I know that the design is far from perfect, but I just curious how to achieve the goal even if it worth to redesign the system and avoid the problem.
The problem may be related to the following:
- Hibernate
Session
s are not thread-safe - Spring-managed transactions are thread-bound
So, I guess each thread should start its own transaction (e.g. with TransactionTemplate
) and obtain its own Session
via SessionFactory.getCurrentSession()
. But note that in this case the whole operation would be not transactional.
精彩评论