1. 程式人生 > >Hibernate 學習心得1: 多對多關係中,中間表無法插入資料。

Hibernate 學習心得1: 多對多關係中,中間表無法插入資料。

Hibernate 學習心得之一 多對多關係中,中間表無法插入資料。

最近學習 spring4+hibernate4,學習中遇到了很多坑。在這裡我來說說我遇到的坑,這裡就不介紹如何spring如何整合hibernate。目前學習過程中,我遇到的兩個問題1.為何在hibernate多對多關係中,無法插入中間表的資料2.為何配置了spring事務註解。可是在使用@transactional Hibernate儲存資料還是沒能正常執行事務。先貼出兩個類,Person 和 Song,人物類和歌曲類。get,set方法等略掉
@Entity
@Table(name = "Person")
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "name")
    private String name;
    //身高 單位cm
    @Column(name = "height")
    private float height;
    //體重 單位kg
    @Column(name = "weight")
    private float weight;
    //性別
    @Column(name = "gender")
    private boolean gender;
    //年齡
    @Column(name = "age")
    private int age;
    @ManyToMany()
    @Cascade(value = {CascadeType.SAVE_UPDATE})
    @JoinTable(name = "Song_Person",
    joinColumns = {@JoinColumn(name = "personId", referencedColumnName="id")},
    inverseJoinColumns = {@JoinColumn(name = "songId", referencedColumnName="id")})
    private Set<Song> songs = new HashSet<Song>();
}

@Entity
@Table(name = "Song")
public class Song {
    @Id
    @GeneratedValue
    private int id;
    @Column(name = "songName")
    private String songName;
    //演唱者
    @ManyToMany()
    @Cascade(value = {CascadeType.SAVE_UPDATE})
    @JoinTable(name = "Song_Person",
            //本表與中間表的外來鍵對應關係
            joinColumns = {@JoinColumn(name = "songId", referencedColumnName="id")},
            //另一張表與中間表的外來鍵的對應關係
            inverseJoinColumns = {@JoinColumn (name = "personId", referencedColumnName="id")})
    private Set<Person> singers = new HashSet<Person>();
}
Person 和 Song 存在多對多的關係1.第一個問題,為何在hibernate多對多關係中,無法插入中間表的資料一開始使用這種方法儲存資料。
public Integer savePerson(String songName){
Song song = new Song();
song.setSongName(songName);
Person person = new Person("張國榮", 180.0F, 56.8F, true, 40);
person.getSongs().add(song);
personDao.save(person);
}
public Integer save(Person entity) {
    int id = (Integer) sessionFactory.openSession().save(entity);
    return id;
}
save() 方法 使用 sessionFactory.openSession() 儲存資料,結果死活中間表儲存不了資料。也沒有報錯,一開始的解決方法是看註解有沒有用錯。後來查資料發現並沒有用錯。經過各種測試後發現 需要呼叫事務開啟和提交。改成:
public Integer save(Person entity) {
      //開啟一次事物
     Session session = sessionFactory.openSession();
     Transaction tran = session .beginTransaction();
     int id = (Integer) session .save(entity);
     tran.commit();
      return id;
 }
2.第二個問題,配置了spring事務註解,可是在使用@transactional Hibernate儲存資料還是沒能正常執行事務首先新增Spring配置
<!-- 事物管理器配置  -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<!-- 註解實現事務 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
然後我就開始使用@Transactional註解
@Transactional
public Integer save(Person entity) {
     Session session = sessionFactory.openSession();
     int id = (Integer) session .save(entity);
     return id;
 }
可是結果發現,使用了這個註解,之後,反而又再一次不能插入中間表資料了。最後解決辦法是使用sessionFactory.getCurrentSession(),而不是使用sessionFactory.openSession(),具體原理,請大家谷歌查。這裡就不介紹了。
@Transactional
public Integer save(Person entity) {
     Session session = sessionFactory.getCurrentSession();
     int id = (Integer) session .save(entity);
     return id;
}
改成這樣就可以順利地執行事務,中間表資料也就自然有了。