Java 使用相同的服务&;从两条线开始

Java 使用相同的服务&;从两条线开始,java,database,hibernate,spring,Java,Database,Hibernate,Spring,我用Spring3.0.0.RC1制作了一个非常简单的REST控制器方法,它使用hibernate执行查询。查询大约需要10秒钟才能完成。我这样做是有意的,这样我可以向我的控制器发出两个请求 然后我启动这两个请求,并在MySQL(我的DB后端)中查询“ShowfullProcessList”,令我大吃一惊的是,只有一个请求在进行。一个请求将成功,一个请求将失败,异常为“org.hibernate.SessionException:会话已关闭!”。如果我执行两个以上的请求,则只有一个请求将成功,其

我用Spring3.0.0.RC1制作了一个非常简单的REST控制器方法,它使用hibernate执行查询。查询大约需要10秒钟才能完成。我这样做是有意的,这样我可以向我的控制器发出两个请求

然后我启动这两个请求,并在MySQL(我的DB后端)中查询“ShowfullProcessList”,令我大吃一惊的是,只有一个请求在进行。一个请求将成功,一个请求将失败,异常为“org.hibernate.SessionException:会话已关闭!”。如果我执行两个以上的请求,则只有一个请求将成功,其他请求将以相同的方式失败。而且每次只会有一个查询,即使应该有多个查询

这怎么可能?有什么建议吗

为了向您介绍我的配置,以下是我用于控制器的配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc:mysql://127.0.0.1:3306/MyDb" />
  <property name="username" value="angua" />
  <property name="password" value="vonU" />
  <property name="initialSize" value="2" />
  <property name="maxActive" value="5" />
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  <property name="dataSource" ref="dataSource"/>
  <property name="annotatedClasses">
    <list>
      <value>tld.mydomain.sample.entities.User</value>
      <value>tld.mydomain.sample.entities.Role</value>
    </list>
  </property>
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
      <prop key="hibernate.show_sql">false</prop>
    </props>
  </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

<bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
  <property name="sessionFactory" ref="sessionFactory"/>
  <property name="flushMode" value="0" />
</bean> 

<bean id="txProxyTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
  <property name="transactionManager" ref="transactionManager"/>
  <property name="transactionAttributes">
    <props>
      <prop key="create*">PROPAGATION_REQUIRED</prop>
      <prop key="update*">PROPAGATION_REQUIRED</prop>
      <prop key="delete*">PROPAGATION_REQUIRED</prop>
      <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
    </props>
  </property>
</bean>

<bean id="userService" parent="txProxyTemplate">
  <property name="target">
    <bean class="tld.mydomain.business.UserServiceImpl"/>
  </property>
  <property name="proxyInterfaces" value="tld.mydomain.business.UserService"/>
</bean>

<context:component-scan base-package="tld.mydomain"/>  

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
  <property name="interceptors">
    <list>
      <ref bean="openSessionInViewInterceptor" />
    </list>
  </property>
</bean>

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="" p:suffix=".jsp"/>

<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
  <property name="encoding" value="ISO-8859-1"/>
  <property name="contentType" value="application/json"/>
</bean>
更新:这里是UserServiceImpl

public class UserServiceImpl extends AbstractCRUDServiceImpl<User, String> {

@SuppressWarnings("unchecked")
@Override
public List<User> longQuery(String username) {
  String like = "0" + username + "-%";
  return DAO.getSession().createCriteria(User.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).addOrder(Order.asc("name"))
          .createCriteria("interests").add(Restrictions.like("userPrefixedId", like))
          .createCriteria("community").add(Restrictions.like("userPrefixedAuthorId", like))
          .createCriteria("member").add(Restrictions.like("userPrefixedGroupId", like))
          .add(Restrictions.isNotEmpty("skills"))
          .list();
  }
}
公共类UserServiceImpl扩展了AbstractCRUDServiceImpl{
@抑制警告(“未选中”)
@凌驾
公共列表长查询(字符串用户名){
类似字符串=“0”+用户名+“-%”;
返回DAO.getSession().createCriteria(User.class).setResultTransformer(Criteria.DISTINCT\u ROOT\u ENTITY).addOrder(Order.asc(“name”))
.createCriteria(“兴趣”).add(限制.like(“userPrefixedId”,like))
.createCriteria(“community”).add(Restrictions.like(“userPrefixedAuthorId”,like))等限制)
.createCriteria(“成员”).add(限制.like(“userPrefixedGroupId”,like))
.add(限制.isNotEmpty(“技能”))
.list();
}
}
(故意使查询变慢,以便我可以轻松再现多个请求同时运行的错误,并查看数据库中同时运行了多少查询)

您还需要我的AbstractCRUDServiceImpl和GenericCRUDDAO:

public abstract class AbstractCRUDServiceImpl<Entity extends PublishableEntity, PkID extends Serializable> implements CRUDService<Entity, PkID> {

    protected GenericCRUDDAO<Entity, PkID> DAO = new GenericCRUDDAO<Entity, PkID>(dataType());

    @Override
    public void create(Entity entity) {
        DAO.create(entity);
    }

    @Override
    public void delete(Entity entity) {
        DAO.create(entity);
    }

    @Override
    public Entity read(PkID entityPk) {
        return DAO.read(entityPk);
    }

    @Override
    public void update(Entity entity) {
        DAO.update(entity);
    }

    private Class<PkID> pkType = null;
    @SuppressWarnings("unchecked")
    public Class<PkID> pkType() {
        if(pkType != null)
            return pkType;

        // Backup solution in case datatype hasn't been set
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) type;
            pkType = (Class<PkID>) paramType.getActualTypeArguments()[1];
        } else if (type instanceof Class) {
            pkType = (Class<PkID>) type;
        }

        return pkType;
    }

    private Class<Entity> dataType = null;
    @SuppressWarnings("unchecked")
    private Class<Entity> dataType() {
        if(dataType != null)
            return dataType;

        // Backup solution in case datatype hasn't been set
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) type;
            dataType = (Class<Entity>) paramType.getActualTypeArguments()[0];
        } else if (type instanceof Class) {
            dataType = (Class<Entity>) type;
        }

        return dataType;
    }
}
公共抽象类AbstractCRUDServiceImpl实现CRUDService{
受保护的GenericCRUDDAO DAO=新的GenericCRUDDAO(数据类型());
@凌驾
公共作废创建(实体){
创建(实体);
}
@凌驾
公共作废删除(实体){
创建(实体);
}
@凌驾
公共实体读取(PkID entityPk){
返回DAO.read(entityPk);
}
@凌驾
公共作废更新(实体){
更新(实体);
}
私有类pkType=null;
@抑制警告(“未选中”)
公共类pkType(){
if(pkType!=null)
返回pkType;
//未设置数据类型时的备份解决方案
类型Type=getClass().getGenericSuperclass();
if(类型instanceof ParameterizedType){
ParameteredType paramType=(ParameteredType)类型;
pkType=(类)paramType.getActualTypeArguments()[1];
}else if(类型instanceof Class){
pkType=(类)类型;
}
返回pkType;
}
私有类数据类型=null;
@抑制警告(“未选中”)
私有类数据类型(){
if(数据类型!=null)
返回数据类型;
//未设置数据类型时的备份解决方案
类型Type=getClass().getGenericSuperclass();
if(类型instanceof ParameterizedType){
ParameteredType paramType=(ParameteredType)类型;
数据类型=(类)paramType.getActualTypeArguments()[0];
}else if(类型instanceof Class){
数据类型=(类)类型;
}
返回数据类型;
}
}
一般来说,PublishableEntity是我所有实体的发源地。它有一些简单方便的方法,比如检查实体是否有效,以及在toString或类似的应用程序中应该发布或保留实体的哪些部分

public class GenericCRUDDAO<EntityType extends PublishableEntity, PkID extends Serializable> implements CRUDDAO<EntityType, PkID> {

    public GenericCRUDDAO() {}

    public GenericCRUDDAO(Class<EntityType> datatype) {
        this.setDataType(datatype);
    }

    private static SessionFactory sessionFactory = null;
    public void setSessionFactory(SessionFactory sf) {
        System.err.println("Setting SessionFactory for class " + this.getClass().getName());
        sessionFactory = sf;
    }

    private Session session = null;

    public Session getSession() {

        if(session != null) {
            if(session.isOpen())
                return session;
        }

        if(sessionFactory == null)
            Util.logError("sessionFactory is null");
        session = ((SessionFactory) sessionFactory).getCurrentSession();
        return session;
    }

    public void create(EntityType entity)
    {
        getSession().save(entity);
    }

    @SuppressWarnings("unchecked")
    public EntityType read(PkID id)
    {
        return (EntityType) getSession().get(dataType(), id);
    }

    public void update(EntityType entity)
    {
        getSession().update(entity);
    }

    public void delete(EntityType entity) {
        getSession().delete(entity);
    }

    public void delete(PkID id)
    {
        EntityType entity = read(id);
        getSession().delete(entity);
    }

    private Class<EntityType> dataType = null;
    @SuppressWarnings("unchecked")
    private Class<EntityType> dataType() {
        if(dataType != null)
            return dataType;

        // Backup solution in case datatype hasn't been set
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) type;
            dataType = (Class<EntityType>) paramType.getActualTypeArguments()[0];
        } else if (type instanceof Class) {
            dataType = (Class<EntityType>) type;
        }

        return dataType;
    }

    public void setDataType(Class<EntityType> datatype) {
        this.dataType = datatype;
    }
}
公共类GenericCRUDDAO实现CRUDDAO{
公共通用CRUDDAO(){}
公共GenericCRUDDAO(类数据类型){
this.setDataType(数据类型);
}
私有静态SessionFactory SessionFactory=null;
公共无效设置会话工厂(会话工厂sf){
System.err.println(“为类设置SessionFactory”+this.getClass().getName());
sessionFactory=sf;
}
私有会话=null;
公共会话getSession(){
if(会话!=null){
if(session.isOpen())
返回会议;
}
if(sessionFactory==null)
Util.logError(“sessionFactory为null”);
会话=((SessionFactory)SessionFactory.getCurrentSession();
返回会议;
}
公共void创建(EntityType实体)
{
getSession().save(实体);
}
@抑制警告(“未选中”)
公共EntityType读取(PkID)
{
return(EntityType)getSession().get(dataType(),id);
}
公共无效更新(EntityType实体)
{
getSession().update(实体);
}
公共作废删除(EntityType实体){
getSession().delete(实体);
}
公共无效删除(PkID)
{
EntityType实体=读取(id);
getSession().delete(实体);
}
私有类数据类型=null;
@抑制警告(“未选中”)
私有类数据类型(){
if(数据类型!=null)
返回数据类型;
//未设置数据类型时的备份解决方案
类型Type=getClass().getGenericSuperclass();
if(类型instanceof ParameterizedType){
ParameteredType paramType=(ParameteredType)类型;
数据类型=(类)paramType.getActualTypeArguments()[0];
}else if(类型instanceof Class){
数据类型=(类)类型;
}
返回数据类型;
}
public void setDataType(类数据类型){
this.dataType=数据类型;
}
}
我希望配置和代码能让我明白为什么我一次只能做一个查询,而不会让他们互相牵绊

干杯

尼克看起来
public class GenericCRUDDAO<EntityType extends PublishableEntity, PkID extends Serializable> implements CRUDDAO<EntityType, PkID> {

    public GenericCRUDDAO() {}

    public GenericCRUDDAO(Class<EntityType> datatype) {
        this.setDataType(datatype);
    }

    private static SessionFactory sessionFactory = null;
    public void setSessionFactory(SessionFactory sf) {
        System.err.println("Setting SessionFactory for class " + this.getClass().getName());
        sessionFactory = sf;
    }

    private Session session = null;

    public Session getSession() {

        if(session != null) {
            if(session.isOpen())
                return session;
        }

        if(sessionFactory == null)
            Util.logError("sessionFactory is null");
        session = ((SessionFactory) sessionFactory).getCurrentSession();
        return session;
    }

    public void create(EntityType entity)
    {
        getSession().save(entity);
    }

    @SuppressWarnings("unchecked")
    public EntityType read(PkID id)
    {
        return (EntityType) getSession().get(dataType(), id);
    }

    public void update(EntityType entity)
    {
        getSession().update(entity);
    }

    public void delete(EntityType entity) {
        getSession().delete(entity);
    }

    public void delete(PkID id)
    {
        EntityType entity = read(id);
        getSession().delete(entity);
    }

    private Class<EntityType> dataType = null;
    @SuppressWarnings("unchecked")
    private Class<EntityType> dataType() {
        if(dataType != null)
            return dataType;

        // Backup solution in case datatype hasn't been set
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) type;
            dataType = (Class<EntityType>) paramType.getActualTypeArguments()[0];
        } else if (type instanceof Class) {
            dataType = (Class<EntityType>) type;
        }

        return dataType;
    }

    public void setDataType(Class<EntityType> datatype) {
        this.dataType = datatype;
    }
}
public Session getSession() {
    return ((SessionFactory) sessionFactory).getCurrentSession();
}
 private Session session = null;
 public Session getSession() {

        if(session != null) {
                if(session.isOpen())
                        return session;
        }

        if(sessionFactory == null)
                Util.logError("sessionFactory is null");
        session = ((SessionFactory) sessionFactory).getCurrentSession();
        return session;
    }
public Session getSession() {
    return ((SessionFactory) sessionFactory).getCurrentSession();
}