想了几天,终于知道sql语句的发出问题。查了很多书,感觉都没有说清楚,有的还是错的。请看下面:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.bjpowernode.hibernate.Classes" table="t_classes"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="students" cascade="save-update"> <!-- <key column="classesid" not-null="true"/> --> <key column="classesid"/> <one-to-many class="com.bjpowernode.hibernate.Student"/> </set> </class> </hibernate-mapping>
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.bjpowernode.hibernate.Student" table="t_student"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <many-to-one name="classes" column="classesid" cascade="save-update"/> </class> </hibernate-mapping>
测试的语句:
session = HibernateUtils.getSession(); session.beginTransaction(); Student student1 = new Student(); student1.setName("张三"); Classes classes = new Classes(); classes.setName("动力节点"); student1.setClasses(classes); //Set students = new HashSet(); //students.add(student1); classes.getStudents().add(student1); //抛出TransientObjectException //因为Student不是Persistent状态的对象,它是Transient状态的对象 session.save(classes);
Hibernate: insert into t_classes (name) values (?)
Hibernate: insert into t_student (name, classesid) values (?, ?)
Hibernate: update t_student set classesid=? where id=?
问题一:既然是两端维持关系,为什么不发出
Hibernate: insert into t_classes (name) values (?)
Hibernate: insert into t_student (name, classesid) values (?, ?)
而是发出三条语句呢?
答:我猜想内部机制,当它发现session.save(classes)时,也就是保存一的一端的时候,他会使用一的一端来维持关系,这时候student1.setClasses(classes);这句话就不管了。所以此时Hibernate: insert into t_student (name, classesid) values (?, ?)中的那个字段还是为空。它看不到关系。(孙卫琴老师的精通hibernate这本书这个地方说发出两条sql语句是错误的)
当保存多的一端的时候,他会使用多的一端来维持关系,这时候classes.getStudents().add(student1);这句话就不管了。此时它能够看到student1.setClasses(classes);所以保存Hibernate: insert into t_student (name, classesid) values (?, ?)中的那个字段不会为空。它能够看到关系。
总结一句话:保存一的一端会发出多条update的语句。而保存多的一端不会发出多条update的语句(尽管是两端维持关系,但是会只用一端控制机制)。
问题二:级联保存的时候,是先保存多的一端还是先保存一的一端呢?
答:不管是session.save(classes);还是session.save(students);一定是先保存一的一端,再保存多的一端。而不是先保存级联的那个对象,再保存save的这个对象(我以前一直是这样理解的,后来发现我错了)。