簡體   English   中英

使用JPA,Spring,Hibernate進行多個查詢

[英]Making multiple queries using JPA, Spring, Hibernate

我最近配置了我的第一個JPA,Spring和Hibernate應用程序來管理用戶和角色。

我已使用CrudRepository創建查詢。 我有兩個存儲庫,一個用於用戶,一個用於角色。

最初,我將存儲庫自動連接到Controller,然后將其命名為:

Role godRole = roleRepository.findByName(roleName);
User newUser = new User("me@me.net", "mARK");

newUser.addRole(godRole);

userRepository.save(newUser);

這導致了一個例外:

org.hibernate.PersistentObjectException: detached entity passed to persist: uk.org.rspca.secrets.entities.Role
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:97)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:379)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:319)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:296)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:460)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:294)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)

我認為發生這種情況是因為每個查詢都在一個單獨的會話中運行,因此,當我嘗試將角色添加到用戶時,該角色不再附加到會話中,並且因為它具有一個ID,因此嘗試執行插入而不是與現有角色匹配。

我讀到,如果執行查詢的方法使用@Transaction批注,則查詢將全部在同一會話中運行,這似乎沒有什么不同!

任何人都可以對我應該如何實現這種行為有任何看法,想要做到這一點似乎很簡單!

applicationContext.xml中

<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="uk.co.secrets" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="true" />
            <property name="generateDdl" value="true" />
            <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
        </bean>
    </property>
</bean>

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="jdbc/DBPool" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="dataSource" ref="dataSource" />
</bean>

<data:repositories base-package="uk.co.secrets.repositories" />

User.java

 @Entity
@Table(name="S_User")
public class User {

    @Id
    @Column(name="u_pk_id")
    //@GeneratedValue(strategy=GenerationType.AUTO)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "S_User_Seq")
    @SequenceGenerator(name = "S_User_Seq", sequenceName = "S_User_Seq", allocationSize = 1)
    private long id;

    @Column(name="u_username")
    private String username;

    @Column(name="u_name")
    private String name;

    @Column(name="u_last_login")
    private Date lastLoggedin;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "S_UserRole", joinColumns = {
        @JoinColumn(name="u_fk_id") },
            inverseJoinColumns = { @JoinColumn(name = "r_fk_id") })
    private Set<Role> userRoles = new HashSet<Role>();
}

Role.java

@Entity
@Table(name="S_Role")
public class Role {

    @Id
    @Column(name="r_pk_id")
    //@GeneratedValue(strategy=GenerationType.AUTO)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "S_Role_Seq")
    @SequenceGenerator(name = "S_Role_Seq", sequenceName = "S_Role_Seq", allocationSize = 1)
    private long id;

    @Column(name="r_name")
    private String name;

    @Column(name="r_desc")
    private String description;

    @Column(name="r_created")
    private Date dateCreated;

    @Column(name="r_modified")
    private Date dateModified;

    @Column(name="r_removed")
    private Date dateremoved;
}

關於mARK

您的控制器方法應使用@Transactional進行注釋。 在您的代碼中,新事務在您調用存儲庫方法時創建,並在方法完成后關閉。

無論如何,在控制器中啟動事務是一個壞習慣。 最好在控制器和dao層之間創建一些服務層(事務性)。

CascadeType.ALL表示對User對象進行的所有操作都將在Role對象上進行。

在這種情況下,SAVE操作將級聯到現在已分離的對象Role中。 這就是為什么休眠拋出異常。

我很好奇,為什么將Role對象從會話中分離出來。 當您將方法設為事務性(默認傳播。要求,因此如果不存在該方法則應創建新的事務)並獲取角色時,您仍應具有相同的會話。

編輯:我檢查了我的項目。 您無法保存具有ID的實體(尤其是當您具有@GeneratedValue批注時)。 因此,您無法將持久性操作級聯到角色實體。 因此,刪除CascadeType.ALL是IMO的唯一解決方案。 當然,您可以設置CascadeType.UPDATE,CascadeType.REMOVE等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM