Spring:非法尝试将代理与两个打开的Sessions关联起来

时间:2013-04-27 17:21:50

标签: spring hibernate session annotations

我有一个页面来创建出租车,它包含一个简单的表格来填充我的数据库。这个类和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;
}

}

Taxi.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();
    }
}

这是stacktrace:

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

1 个答案:

答案 0 :(得分:0)

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

我最终找到的解决方案是使用Taxi,它连接同一会话中的所有事务。要做到这一点,你只需要在web.xml中添加这段代码。

OpenEntityManagerInViewFilter