Java Hibernate-SpringMVC-llegal尝试将集合与两个打开的会话相关联

Java Hibernate-SpringMVC-llegal尝试将集合与两个打开的会话相关联,java,hibernate,spring-mvc,Java,Hibernate,Spring Mvc,有很多相同类型的问题,但没有一个适合我 我有Spring MVC hibernate应用程序 这是我的两个模型课 Config.java public class Config implements java.io.Serializable { private Integer configId; private String configName; private Set<ConfigFields> ConfigFieldses = new HashSet

有很多相同类型的问题,但没有一个适合我

我有Spring MVC hibernate应用程序

这是我的两个模型课

Config.java

public class Config  implements java.io.Serializable {

    private Integer configId;
    private String configName;
    private Set<ConfigFields> ConfigFieldses = new HashSet<ConfigFields>(0);

    //getters and setters

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="configuration")
    public Set<ConfigFields> getConfigFieldses() {
            return this.ConfigFieldses;
    }

    public void setConfigFieldses(Set<ConfigFields> ConfigFieldses) {
            this.ConfigFieldses = ConfigFieldses;
    }
}
public class ConfigFields  implements java.io.Serializable {


    private Integer configFieldId;
    private Confign config;
    private String configFieldName;

    //getteres and setters

    @XmlTransient
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="ConfigId")
    public Config getConfig() {
        return this.config;
    }

    public void setConfig(Config configu) {
        this.config = config;
    }
}
@Repository
@Transactional
public class GenericHibernateDao<T extends Serializable>
implements GenericDao<T>{

    @Resource
        protected SessionFactory sessionFactory;

    @Override
    public void insert(T transientInstance) {
        sessionFactory.getCurrentSession().persist(transientInstance);
    }

    @Override
    public void update(T instance) {
        sessionFactory.getCurrentSession().saveOrUpdate(instance);
    }

    @Override
    public void delete(T persistentInstance) {
        sessionFactory.getCurrentSession().delete(persistentInstance);
    }

    @SuppressWarnings("unchecked")
    @Override
    public T merge(Serializable detachedInstance) {
        return (T) sessionFactory.getCurrentSession().merge(detachedInstance);
    }

    @SuppressWarnings("unchecked")
    @Override
    public T findById(Class<?> clazz, Serializable id) {
        T t= (T) sessionFactory.openSession().get(clazz, id);
        return t;
    }

    @SuppressWarnings("unchecked")
    public  List<T> findByNamedQuery(Class<T> clazz, String queryName, Map<String, Object> queryParams) {
        Query namedQuery = sessionFactory.getCurrentSession().getNamedQuery(queryName);

        for (String s : queryParams.keySet()) {
            namedQuery.setParameter(s, queryParams.get(s));
        }

        return namedQuery.list();
    }

}
下面是generichbernatedao.java

public class Config  implements java.io.Serializable {

    private Integer configId;
    private String configName;
    private Set<ConfigFields> ConfigFieldses = new HashSet<ConfigFields>(0);

    //getters and setters

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="configuration")
    public Set<ConfigFields> getConfigFieldses() {
            return this.ConfigFieldses;
    }

    public void setConfigFieldses(Set<ConfigFields> ConfigFieldses) {
            this.ConfigFieldses = ConfigFieldses;
    }
}
public class ConfigFields  implements java.io.Serializable {


    private Integer configFieldId;
    private Confign config;
    private String configFieldName;

    //getteres and setters

    @XmlTransient
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="ConfigId")
    public Config getConfig() {
        return this.config;
    }

    public void setConfig(Config configu) {
        this.config = config;
    }
}
@Repository
@Transactional
public class GenericHibernateDao<T extends Serializable>
implements GenericDao<T>{

    @Resource
        protected SessionFactory sessionFactory;

    @Override
    public void insert(T transientInstance) {
        sessionFactory.getCurrentSession().persist(transientInstance);
    }

    @Override
    public void update(T instance) {
        sessionFactory.getCurrentSession().saveOrUpdate(instance);
    }

    @Override
    public void delete(T persistentInstance) {
        sessionFactory.getCurrentSession().delete(persistentInstance);
    }

    @SuppressWarnings("unchecked")
    @Override
    public T merge(Serializable detachedInstance) {
        return (T) sessionFactory.getCurrentSession().merge(detachedInstance);
    }

    @SuppressWarnings("unchecked")
    @Override
    public T findById(Class<?> clazz, Serializable id) {
        T t= (T) sessionFactory.openSession().get(clazz, id);
        return t;
    }

    @SuppressWarnings("unchecked")
    public  List<T> findByNamedQuery(Class<T> clazz, String queryName, Map<String, Object> queryParams) {
        Query namedQuery = sessionFactory.getCurrentSession().getNamedQuery(queryName);

        for (String s : queryParams.keySet()) {
            namedQuery.setParameter(s, queryParams.get(s));
        }

        return namedQuery.list();
    }

}
我的测试用例

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration("classpath:webapptest")
@ContextConfiguration(locations = {"classpath:test-applicationcontext.xml"})
public class ConfigurationsControllerTest {

    private MockMvc springMvc;

    @Autowired
    WebApplicationContext wContext;

    @Before
    public void init() throws Exception {
        springMvc = MockMvcBuilders.webAppContextSetup(wContext).build();
    }

    @Test
    public void deleteConfiguration() throws Exception {
        ResultActions resultActions=springMvc.perform(MockMvcRequestBuilders.post("/deleteConfig/117").accept(MediaType.APPLICATION_JSON));
        resultActions.andDo(MockMvcResultHandlers.print());
        resultActions.andExpect(MockMvcResultMatchers.status().isOk());
    }

}
当我在控制台中运行testcase时,logger显示

Illegal attempt to associate a collection with two open sessions
JUnit测试用例stacktrace是

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is bitronix.tm.internal.BitronixRollbackException: transaction was marked as rollback only and has been rolled back
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:932)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:66)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:168)
Config类中,我有Set,它被设置为CASCADE ALL。因此,我能够在插入配置的同时插入一组配置字段。但现在我想通过传递config对象来删除。所以它应该根据configId从config表中删除1行,从configfields表中删除几行


这里怎么了?如何在不影响应用程序的情况下解决问题(我的意思是插入)

您的控制器方法真的像您在这里发布的那样吗?看起来您正在某处检索
config
对象,保留对该对象的引用,然后尝试在后续请求中使用它,您在那里提到的两个变量看起来可能不匹配。您的findById方法有缺陷。永远不要使用
openSession()
,而是使用
getCurrentSession()
。除了将业务逻辑放在控制器中之外,这实际上属于一种服务方法,该方法将标记为
@Transactional
。实际上,注入
会话
(或
EntityManager
)而不是
会话工厂
,通常是一种更安全、更干净的方法。@chrylis-OOps。那是打字错误。我有edited@M.Deinum我有服务课,只有我在打电话。在这个控制器中,我有一些其他事务。所以我把
事务性