如何使用基于Hibernate的DAO从不同的线程实现数据库中表的更新?

时间:2010-11-08 13:40:32

标签: java multithreading hibernate spring

我有一节课,我们称之为UserGenerator。它包含几个注入的DAO(spring singleton beans),比方说UserDaoOrganizationDao

UserGenerator的目的是为新组织创建用户。所以,我想要的是:

@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())); 

}

问题是组织是成功创建的,但是userDaos抛出了很少调试的异常,据我所知,他们声明Hibernate会话已关闭(或者,可能还有别的东西):

//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

执行此任务的正确方法是什么?

P.S。我知道设计远非完美,但我只是好奇如何实现目标,即使值得重新设计系统并避免问题。

1 个答案:

答案 0 :(得分:0)

问题可能与以下内容有关:

  • Hibernate Session不是线程安全的
  • Spring管理的事务是线程绑定的

所以,我猜每个帖子应该开始自己的交易(例如TransactionTemplate)并通过Session获得自己的SessionFactory.getCurrentSession()。但请注意,在这种情况下,整个操作将不是交易操作。