xskow's road.

做好自己,做好一切。
数据加载中……
华南理工大学校运会计分系统项目总结(一)
        这么一个项目,确实,用了我很多时间,原因是自己在项目开始时可以说对SSH只有一知半解,就坚决地要采用这三个优秀框架来搭建服务。不过,学到的确实不少啊,起码对于这样的应用还是有一定底子了,呵呵。。。
        在这个项目当中,有什么值得写在我的小博客上面呢?有的。本项目分层也是采用经典的贫血模式。由底向上共四层,model-->dao-->service-->action。其中model采用Hibernate,底层数据库用MySQL5,在Hibernate方面,我用了比较新的annotations,而不是平常的*.hbm.xml。确实,annotations用起来比较方便,但是和POJO的耦合度就大多了。记得有些配错的时候要一个一个getter去找annotation,呵呵。。。
        在Hibernate annotation方面,还是有些东西值得总结一下,首先就是annotation写在是什么地方,最方便的方法是写在各个field的getter上面,这样就不用额外的annotation,也建议大家采用此方法,另一种也就是写在field声明上面,这样的话需要在类上方添加其他annotation,我当时是没成功,呵呵。其次是级联操作,也就是cascade,需要注意的是当两个实体关系是一对多和多对多的时候,比如班级与学生,学生与课程,明显班级与学生是一对多,学生与课程是多对多关系,那么当我们需要设置级联时候怎么办呢?在hibernate中,cascade分有4种,分别是CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH,CascadeType.REMOVE。比如是persist,如果在刚才的例子来说,应该这样配置:
 1//班级实体
 2@Entity
 3@Table(name="T_CLASS")
 4public class Clazz{
 5  
 6  private Set<Student> students;
 7  
 8  
 9  @OneToMany
10  (cascade={CascadeType.REMOVE,CascadeType.MERGE, CascadeType.PERSIST}, fetch=FetchType.LAZY, mappedBy="clazz")
11  public Set<Student> getStudents(){
12    return students;
13  }
 
14}

15

 1//学生实体
 2@Entity
 3@Table(name="T_STUDENT")
 4
 5public class Student{
 6  
 7  private Clazz clazz;
         private Set<Course> courses;
 8  
 9  @ManyToOne
10  @JoinColumn(name="CLAZZ_ID")
11  public Clazz getClazz(){
12    return clazz;
13  }

14  
          @ManyToMany
          @JoinTable(name="T_STUDENT_COURSE")
          public Set<Course> getCourses(){
                return courses;
         } 
15}

 1//课程实体
 2public class Course{
 3  
 4  private Set<Student> students;
 5  
 6  @ManyToMany(mappedBy="courses" cascade={CascadeType.PERSIST, CascadeType.REMOVE})
 7  public Set<Student> getStudents(){
 8    return students;
 9  }

10}

在Clazz的OneToMany和Course的ManyToMany中,我们都可以看到有CascadeType.PERSIST和CascadeType.REMOVE。具体到底是什么意思呢?persist是指当持久化实体的时候,如果有关联的集合,并且设成persist时,连集合也一并存入数据库当中。但是如果真正写一下,然后使用的话,我们会发现:OneToMany设置这个根本不起作用。比如我新建一个班级,并直接赋予60个学生的一个集合,然后调用dao的save方法,看看数据库,怎么回事,怎么只有班级持久化了,关联学生一个没存到数据库?然后试试新建课程,并且选上要修这门课的学生,然后持久化课程,看看数据库,怎么搞的,这次双方都持久化了,即中间表已经插入了相关的记录。造成OneToMany用persist是什么原因?个人理解:学生属于一个实体,其持久化应当依靠自己相应的dao,一个一个student的存储。就好比student和course的中间表,我们上面假设中间表只有STUDENT_ID和COURSE_ID,并且分别连向student表和course表的主键,如果你有特殊需求,比如是要一个score列(课程成绩),那么这时候你还想用ManyToMany配置的话,会出现好多问题,除非你允许成绩是空的,但是即使成绩可以为空,如果你需要修改成绩怎么办呢?先取出这个学生,然后遍历其课程集合,找到这个课程然后再持久化不行?应该可以吧,但是是不是指需要先删除这个学生选的课程,然后再将这些再次持久化一次?这个方法绝对可以,不过我没人会这样。。。呵呵。。。当中间表有其他与两方表都没有关系的列时,你应当为中间表也映射一个实体,用这个实体的相应dao修改相应的记录。在这种情况下用ManyToMany还有另一个问题,如果你的hibernate session还没有关闭,你会发现提错,说你打算删除即将再次持久化的记录。使用OpenSessionInViewFilter的时候你就会发现这个问题了。呵呵。。。
        还有一个,Hibernate官方不推荐使用联合主键,原来的我就不相信用联合主键会怎样,还不行吗?要不行那还不是你框架太烂?实践过之后,我改变了我的看法。。。假如你是普通的一个表,使用联合主键没有任何问题,但是假如你的表是一个中间表,并且有和两个关联表无关的列,就像T_STUDENT_COURSE,我们在设计数据库的时候,很容易想到用STUDENT_ID和COURSE_ID来作为主键,不错,但是如果你用hibernate映射实体的时候你知道有什么麻烦吗?首先这两个都是外键,在hibernate中就是需要有两个关联实体的对象引用,那么这两个作为@Id是吧?可以啊!但是当你持久化的时候,会提示student在T_STUDENT_COURSE中无法找到。为什么?因为你数据库就一个ID呀,而你这里配的可是一个实体引用呀!其实这也是可以解决了,就是解决办法迂回一点点,在hibernate外键关联的时候可以指定实体引用,就是说比如你StudentCourse实体,有一个student的引用,可以定义这样一个column:studentId,这个Id可以关联student引用,具体写法我就不写出来了,在hibernate官方文档写得相当详细,很容易验证。看,就一个外键都这样了,多个外键还得了?当然,如果普通的单外键引用不会产生这样的问题,直接配一个实体引用就可以解决问题。问题是可以解决的,关键是以后维护起来是否方便?我做过就知道,一点不简单,所以后来还是改了。。。不推荐大家使用联合主键。

posted on 2008-11-10 20:39 xskow! 阅读(831) 评论(1)  编辑  收藏 所属分类: SSH探索

评论

# re: 华南理工大学校运会计分系统项目总结(一) 2008-12-17 22:28 ytl

不错,想你学习啦。可和你成为朋友不??我的QQ号是:543893878 Email:ytl_zlq@163.com
  回复  更多评论    

只有注册用户登录后才能发表评论。


网站导航:
 
links:shaojiahao's blog