【问题标题】:Spring: Illegally attempted to associate a proxy with two open SessionsSpring:非法尝试将代理与两个打开的会话相关联
【发布时间】:2013-04-27 17:21:50
【问题描述】:

我有一个创建出租车的页面,该页面包含一个简单的表格来填充我的数据库。这个类和 dao 是由 hibernate 工具自动生成的。当我发布我的代码并且它被称为 persist 方法时,我得到一个 PersistException 代码:

Controller.java

@Controller
@RequestMapping(value="/session/taxi")
public class TaxiController {

private final Log log = LogFactory.getLog(getClass());
@Autowired
private UserManager userManager;
@Autowired 
private TaxiManager taxiManager;

/**
 * Returns the create taxi page.
 * @param model the model on which to map.
 * @return A String reference to jsp.
 */
@RequestMapping(value="/create", method=RequestMethod.GET)
public String createTaxi(ModelMap model){
    //Add the current business and city to this taxi. It can not be modified
    Taxi taxi = taxiManager.createDefaultTaxi();
    TaxiPassword taxiPass = new TaxiPassword();
    taxiPass.setTaxi(taxi);
    model.addAttribute("newTaxi", taxiPass);
    return "taxi/createtaxi";
}

/**
 * Add a new taxi to the database.
 * @param taxiPassword the taxi to be added.
 * @param result the result of binding taxi from the model.
 * @param redirectAttributes attributes to show messages when redirect.
 * @return a string that refers to jsp page.
 */
@RequestMapping(value="/create", method=RequestMethod.POST)
public String addNewTaxi(@ModelAttribute("newTaxi") @Valid TaxiPassword taxiPassword, BindingResult result, 
        final RedirectAttributes redirectAttributes){
    String newPage = "";
    Taxi taxi = taxiPassword.getTaxi();
    //Check password is correct
    if (!result.hasErrors()){
        //Set the password as md5
        taxi.setPassword(SecurityUtils.getMD5Password(taxi.getPassword()));
        //Persist it
        taxiManager.persistTaxi(taxiPassword.getTaxi());
        newPage = "redirect:/session/taxi/viewtaxi";
    }else{
        newPage = "taxi/createtaxi";
    }
    return newPage;
}

}

出租车.java

@Entity
@Table(name = "taxi", catalog = "takeme", uniqueConstraints = @UniqueConstraint(columnNames = "username"))
public class Taxi implements java.io.Serializable {

    @NotNull
    @Size(min=1, max=20)
    @Digits(integer = 15, fraction = 0)
    private String idLicense;
    @Valid
    private City city;
    @Valid
    private Business business;
    @NotNull
    @Nif
    private String dni;
    @NotNull
    @Size(min=3, max=50)
    private String username;
    @Size(min=5, max=50)
    private String password;
    @NotNull
    @Size(min=1, max=50)
    private String name;
    @NotNull
    @Size(min=1, max=45)
    private String surname;
    @NotNull
    @Size(min=1, max=30)
    private String phone;
    @NotNull
    private boolean creditCardAvailability;
    @NotNull
    private boolean taxiAdapted;
    @NotNull
    private boolean bigTaxi;
    @NotNull
    private boolean availability;
    private Double latitude;
    private Double longitude;
    private byte[] photo;
    @NotNull
    private boolean state;
    private Set<Booking> bookings = new HashSet<Booking>(0);
    private Set<MobileClientRateTaxi> mobileClientRateTaxis = new HashSet<MobileClientRateTaxi>(
            0);

    public Taxi() {
    }

    public Taxi(String idLicense, City city, Business business, String dni,
            String username, String password, String name, String surname,
            String phone, boolean creditCardAvailability, boolean taxiAdapted,
            boolean bigTaxi, boolean availability, boolean state) {
        this.idLicense = idLicense;
        this.city = city;
        this.business = business;
        this.dni = dni;
        this.username = username;
        this.password = password;
        this.name = name;
        this.surname = surname;
        this.phone = phone;
        this.creditCardAvailability = creditCardAvailability;
        this.taxiAdapted = taxiAdapted;
        this.bigTaxi = bigTaxi;
        this.availability = availability;
        this.state = state;
    }

    public Taxi(String idLicense, City city, Business business, String dni,
            String username, String password, String name, String surname,
            String phone, boolean creditCardAvailability, boolean taxiAdapted,
            boolean bigTaxi, boolean availability, Double latitude,
            Double longitude, byte[] photo, boolean state,
            Set<Booking> bookings,
            Set<MobileClientRateTaxi> mobileClientRateTaxis) {
        this.idLicense = idLicense;
        this.city = city;
        this.business = business;
        this.dni = dni;
        this.username = username;
        this.password = password;
        this.name = name;
        this.surname = surname;
        this.phone = phone;
        this.creditCardAvailability = creditCardAvailability;
        this.taxiAdapted = taxiAdapted;
        this.bigTaxi = bigTaxi;
        this.availability = availability;
        this.latitude = latitude;
        this.longitude = longitude;
        this.photo = photo;
        this.state = state;
        this.bookings = bookings;
        this.mobileClientRateTaxis = mobileClientRateTaxis;
    }

    @Id
    @Column(name = "id_license", unique = true, nullable = false, length = 20)
    public String getIdLicense() {
        return this.idLicense;
    }

    public void setIdLicense(String idLicense) {
        this.idLicense = idLicense;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_city", nullable = false)
    public City getCity() {
        return this.city;
    }

    public void setCity(City city) {
        this.city = city;
    }

    // More autogenerated setters and getters...

}

TaxiDao.java

@Repository(value = "taxiDAO")
public class TaxiDAOImpl implements TaxiDAO{

    private final Log log = LogFactory.getLog(getClass());

    @PersistenceContext(unitName = "takemePU", type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;

    @Transactional(readOnly = false)
    public void persist(Taxi transientInstance) {
        log.debug("Persisting taxi instance: " + transientInstance.getIdLicense());
        try {
            entityManager.persist(transientInstance);
            log.debug("Persist successful");
        } catch (RuntimeException re) {
            log.error("Persist failed: ", re);
            throw re;
        }
    }

    @Transactional(readOnly = false, propagation=Propagation.REQUIRES_NEW)
    public void remove(Taxi persistentInstance) {
        log.debug("Removing taxi instance: " + persistentInstance.getIdLicense());
        try {
            entityManager.remove(persistentInstance);
            log.debug("Remove successful");
        } catch (RuntimeException re) {
            log.error("Remove failed: ", re);
            throw re;
        }
    }

    @Transactional(readOnly = false, propagation=Propagation.REQUIRES_NEW)
    public Taxi merge(Taxi detachedInstance) {
        log.debug("Merging taxi instance: " + detachedInstance.getIdLicense());
        try {
            Taxi result = entityManager.merge(detachedInstance);
            log.debug("Merge successful");
            return result;
        } catch (RuntimeException re) {
            log.error("Merge failed: ", re);
            throw re;
        }
    }

    @Transactional(readOnly = true)
    public Taxi findById(String id) {
        log.debug("Getting taxi instance with id: " + id);
        try {
            Taxi instance = entityManager.find(Taxi.class, id);
            log.debug("Get successful");
            return instance;
        } catch (RuntimeException re) {
            log.error("Get failed: ", re);
            throw re;
        }
    }

    @Transactional(readOnly = true)
    public Taxi findByUsername(String username) {
        log.debug("Getting taxi instance with id: " + username);
        try {
            Taxi instance = entityManager.find(Taxi.class, username);
            log.debug("Get successful");
            return instance;
        } catch (RuntimeException re) {
            log.error("Get failed: ", re);
            throw re;
        }
    }

    @SuppressWarnings("unchecked")
    @Transactional(readOnly = true)
    public List<Taxi> getTaxiList() {
        return entityManager.createQuery("select taxi from Taxi taxi").getResultList();
    }

    @SuppressWarnings("unchecked")
    @Transactional(readOnly = true)
    public List<Taxi> getTaxisByBusiness(String idBusiness) {
        return entityManager.createQuery("select taxi from Taxi taxi where taxi.business.idBusiness='"+ idBusiness+"'").getResultList();
    }
}

这是堆栈跟踪:

javax.persistence.PersistenceException: org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1174)
org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:674)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
com.sun.proxy.$Proxy90.persist(Unknown Source)
com.hp.unileon.takeme.dao.TaxiDAOImpl.persist(TaxiDAOImpl.java:36)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
com.sun.proxy.$Proxy100.persist(Unknown Source)
com.hp.unileon.takeme.service.SimpleTaxiManager.persistTaxi(SimpleTaxiManager.java:19)
com.hp.unileon.takeme.controller.TaxiController.addNewTaxi(TaxiController.java:112)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

如果您需要任何配置文件来知道我做错了什么,请告诉我,我认为现在代码量很大(已简化)。谢谢。

更新:我的应用程序上下文是:

<!-- Bean used by the daos to connect and make transactions with the database -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>

<!-- Activate the annotation driven configurations making useful @Transaction annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!-- Scans the classpath of this application for @Components to deploy as beans -->
<context:component-scan base-package="com.hp.unileon.takeme.service" />
<context:component-scan base-package="com.hp.unileon.takeme.dao" />

<!-- Holding properties for database connectivity -->
<context:property-placeholder location="classpath:jdbc.properties"/>

<!-- Enabling annotation driven configuration like @Component-->
<context:annotation-config/>

<!-- Selects the database data source giving username password and nedded parameters
to connect on it. You can change those parameters easily on /classes/messages.properties -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username"  value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>

<!-- Element that loads tables on the database into object entities and so on -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"
p:jpaVendorAdapter-ref="jpaAdapter">
    <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
    </property>
    <!-- This persistence unit can be found on /main/resources/META-INF/persistence.xml -->                        
    <property name="persistenceUnitName" value="takemePU"></property>
</bean>

<!-- Enable hibernate to perform the database operations -->
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="${jpa.database}"
p:showSql="${jpa.showSql}"/>

【问题讨论】:

  • 在我的情况下,我在另一个 (txn-2) 中的一个实体(从 txn-1 加载)上重新分配/填充了一个延迟加载字段;并将该“复合”实体保存在另一个(txn-3)中时,出现此错误

标签: spring hibernate session annotations


【解决方案1】:

问题与PersistenceContextType.EXTENDED 有关。当我从使用扩展持久性上下文的数据库中获取嵌套对象时,它们会打开一个新会话,然后由 entityManager 返回。所以,如果我在同一个请求中使用它们并尝试将这些嵌套对象添加到 Taxi 实体,CityBusiness 属于非封闭会话(因为范围是 EXTENDED)并且 Taxi 属于到新的会话。 Persist 方法不允许使用这种行为,因为代理惰性求值对象属于不同的会话。

我最终找到的解决方案是使用OpenEntityManagerInViewFilter,它将所有事务连接到同一个会话中。为此,您只需在 web.xml 中添加这段代码。

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>entityManagerFactory</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

【讨论】:

    猜你喜欢
    • 2015-10-11
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    相关资源
    最近更新 更多