2014-10-07 2 views
0

Недавно у меня возникла проблема с веб-приложением. Я использую Spring mvc restful application вместе с hibernate как jpa.spring mvc hibernate restful (concurrency) issue

Клиент может создать файл XML, используя этот формат:

<SCCF> 
    <registerSCCF>...</registerSCCF> 
    ... 
    <registerSCCF>...</registerSCCF> 
</SCCF> 

Веб-приложение будет отображение каждые данные внутри registerSCCF тега класса и сохранить его в базе данных.

Теперь мучаюсь с проблемой, что когда я проверить его с помощью SoapUI и тест многопоточность, я всегда получаю исключение

[ERROR] сбой утверждение произошло (это может указывать на ошибку в Hibernate, но более вероятно, из-за небезопасное использование сессии) org.hibernate.AssertionFailure: нулевой идентификатор в записи draft.persistence.entity.dcrm.CustomersNoneSSO (не сбрасывают сессии после того, как происходит исключение)

или

Вызванный: org.hibernate.HibernateException: Промывка в процессе каскада опасно

или

org.hibernate.SessionException: Сессия закрыта!

Вот код службы слой:

@Transactional("dcrm") 
public boolean postSCCFService(SCCFVO sccf){ 
    CustomersNoneSSO cns = new CustomersNoneSSO(); 
    cns.setAppid(sccf.getAppid()); 
    cns.setCustomer_name(sccf.getCustomer_name()); 
    cns.setCustomer_gender(sccf.getCustomer_gender()); 
    cns.setContact_mobile(sccf.getContact_mobile()); 
    cns.setContact_email(sccf.getContact_email()); 
    cns.setAddress_province(sccf.getAddress_province()); 
    cns.setAddress_city(sccf.getAddress_city()); 
    cns.setCustomer_address(sccf.getCustomer_address()); 
    cns.setCustomer_occupation(sccf.getCustomer_occupation()); 
    cns.setPurchase_brand(sccf.getPurchase_brand()); 
    cns.setPurchase_model(sccf.getPurchase_model()); 
    cns.setPurchase_date(sccf.getPurchase_date()); 
    cns.setPurchase_budget(sccf.getPurchase_budget()); 
    cns.setOwncar_selected(sccf.getOwncar_selected()); 
    cns.setOwncar_model(sccf.getOwncar_model()); 
    cns.setTestdrive_permission(sccf.getTestdrive_permission()); 
    cns.setMarketing_permission(sccf.getMarketing_permission()); 
    Timestamp t = new Timestamp(new Date().getTime()); 
    cns.setInsert_timestamp(t); 
    cns.setUpdate_timestamp(t); 
    cnsDao.makePersistent(cns); 
} 

, если я установить все сеттера от статических значений, как:

cns.setContact_email("[email protected]"); 

вместо использования значения от параметра, то приложение хорошо работает с тестом многопоточности.

Существует контроллер вызывает метод службы:

@RequestMapping(value = "/test",method=RequestMethod.POST) 
public @ResponseBody SCCFResponseList getPostResults(@RequestBody SCCFVOList sccf){ 
    ... 
    for(SCCFVO sccfvo : sccf.getSCCFVOList()){ 
     ... 
     boolean result = sccfservice.postSCCFService(sccfvo); 
     ... 
    } 
    ... 
} 

public class SCCFVOList { 

А вот класс тело запроса:

@XmlElement(name="registerSCCF") 
public class SCCFVOList { 
private Vector<SCCFVO> SCCFVOList = null; 

public Vector<SCCFVO> getSCCFVOList(){ 
    return SCCFVOList; 
} 

public void setSCCFVOList(Vector<SCCFVO> SCCFVOList){ 
    this.SCCFVOList = SCCFVOList; 
} 

} 

А вот дао

public class CNSDao extends GenericHibernateDAO<CustomersNoneSSO, Long> {} 

public abstract class GenericHibernateDAO<T, ID extends Serializable> 
    implements GenericDAO<T, ID> { 

private Class<T> persistentClass; 
private Session session; 

SessionFactory sessionFactory; 

public void setSessionFactory(SessionFactory sessionFactory){ 
    this.sessionFactory = sessionFactory; 
} 

public GenericHibernateDAO() { 
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass() 
      .getGenericSuperclass()).getActualTypeArguments()[0]; 
} 

@SuppressWarnings("unchecked") 
public void setSession(Session s) { 
    this.session = s; 
} 

protected Session getSession() { 
    session = sessionFactory.getCurrentSession(); 
    if (session == null) 
     throw new IllegalStateException(
       "Session has not been set on DAO before usage"); 
    return session; 
} 

public Class<T> getPersistentClass() { 
    return persistentClass; 
} 

@SuppressWarnings("unchecked") 
public T makePersistent(T entity) { 
    getSession().saveOrUpdate(entity); 
    return entity; 
} 

public void makeTransient(T entity) { 
    getSession().delete(entity); 
} 

... 
} 

Там должно быть что-то неправильный метод контроллера или метод обслуживания. По-прежнему не знаю, что было не так.

+0

Сначала я ожидал бы, что служба сохранит все или нет, я бы не зациклился на контроллере, но это я. Похоже, у вас есть проблема в вашем сообщении о дао. –

+0

Это хороший момент, когда цикл должен проходить в контроллере. Но они действительно сохранены в базе данных, за исключением нескольких случаев, когда исполнилось. Я все равно отправлю дао. – fe3o4

+1

И есть ваша проблема ... НИКОГДА * НИКОГДА * ** НИКОГДА ** (я не упоминал НИКОГДА) хранят сеанс в переменной-члене ... «Сессия» не является потокобезопасной, у вас есть один экземпляр дао, теперь представьте, что происходит с несколькими потоками .... Удалите хранилище (и setter!) и всегда используйте 'sessionFactory.getCurrentSession()'. –

ответ

1

Ваш dao является недостатком.

Ваш дао - одноэлементный, есть только один. Объект Hibernate Session не является потокобезопасным и не должен использоваться по потокам.

У вас есть 1 dao, 2 потока, Thread один получает экземпляр X1 сеанса, Thread два сбрасывает его в экземпляр X2, теперь внезапно они используют один и тот же сеанс, не говоря уже о том, что Thread 1 может работать даже на двух разных сеансах.

Как я уже упоминал в комментариях, НИКОГДА не сохраняйте Session в переменной экземпляра. Убери это.

public abstract class GenericHibernateDAO<T, ID extends Serializable> implements GenericDAO<T, ID> { 

    private Class<T> persistentClass; 

    private SessionFactory sessionFactory; 

    public GenericHibernateDAO() { 
     this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
    } 

    public void setSessionFactory(SessionFactory sessionFactory){ 
     this.sessionFactory = sessionFactory; 
    } 


    protected Session getSession() { 
     return sessionFactory.getCurrentSession(); 
    } 

Кроме того, я хотел бы предложить сбросив это и вместо того, чтобы использовать Spring Data JPA избавляет вас от создания и поддержания вашего собственного общего дао. (Вы упоминаете, что используете JPA, если сущности аннотированы, это должно быть довольно легко сделать).

+0

Удивительно. Я только что отредактировал метод getSession(), как вы и предложили. Он прошел идеально! И я собираюсь позже выкопать данные JPA Spring. – fe3o4