1

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

控制器.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}"/>
4

1 回答 1

0

问题与PersistenceContextType.EXTENDED. 当我从使用扩展持久性上下文的数据库中获取嵌套对象时,它们会打开一个新会话,然后由 entityManager 返回。因此,如果我在同一个请求中使用它们并尝试将Taxi这些嵌套对象添加到实体中,City并且Business属于非封闭会话(因为范围是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>
于 2013-04-28T12:36:07.553 回答