Hibernate面向对象特性:继承和组成:
Hibernate 支持三种继承映射策略table per class hierarchy(TPH):子类父类共用一张表table per subclass(TPS):每一个子类都有一张表,要求父类是抽象的table per concrete class(TPC):对于每一个具体的类都对应着一张表,没有 主外键对应关系implicit polymorphism(IP)
TPH下,一般只为父类创建一个表,在表中设置字段区分对象种类。不同子类具有的不同属性保存在同一张表中,不具备的属性保存值为空。比如学生有学分,没有工资;老师有工资,没有学分,于是对应学分和工资字段会为null
映射的时候要映射父类:
//如果course_type字段的值是GC,就属于course;如果是PC的话,就属于PractiseCourse//如果是CC的话,就属于CertificationCourse<class name="Course" table="course" discriminator-value="GC" > <id name="id" column="course_id"> <generator class="identity" /> </id> <discriminator column="course_type" type="string" /> <property name="name" column="course_name" /> <property name="period" column="total_period" /> <property name="notes" /> //name、period和notes是父类和子类共有的属性 <subclass name="PractiseCourse" discriminator-value="PC"> <property name="projectName" column="project_name" /> <property name="projectPeriod" column="project_period" /> </subclass> <subclass name="CertificationCourse" discriminator-value="CC"> <property name="certificationName" column="cert_name" /> <property name="examTime" column="exam_time"/> </subclass></class>-----------------------------------------------------数据库表:
courses表:
course_id : Integercourse_name : varchartotal_period : Integer
practice_name varcharpractice_period Integer
cert_name varcharexam_time Datetime
course_type char(2)建立实体类:public class Course{ private Integer course_id ; private String courseName ; private Integer total_Period ;}
public class PracticeCourse extends Course{ private String practiceName ; private Integer practicePeriod ;}
public class CertificationCourse extends Course{ private String certName ; private Timestamp examTime ;}
映射关系:
<class name="Course" table="courses" discriminator-value="GC" > <id name="id" column="course_id"> <generator class="identity" /> </id>//discriminator必须放在id元素的后面 <discriminator column="course_type" type="string" /> <property name="courseName" column="course_name" /> <property name="totalPeriod" column="total_period" /> <subclass name="PracticeCourse" discriminator-value="PC"> <property name="practiceName" column="practice_name" /> <property name="practicePeriod" column="practice_period" /> </subclass> <subclass name="CertificationCourse" discriminator-value="CC"> <property name="certName" column="cert_name" /> <property name="examTime" column="exam_time"/> </subclass></class>
示例Demo:
public class Demo{ public static void main(String[] args) { SessionFactory factory = new Configuration().addClass(Course.class) .configure() .buildSessionFactory(); Course gc = new Course() ; gc.setCourseName("a general course"); gc.setTotalPeriod(new Integer(40)) ;
PracticeCourse pc = new PracticeCourse() ; pc.setCourseName("a new project") ; pc.setPracticeName("a project name") ; pc.setPracticePeriod(new Integer(30)) ; pc.setTotalPeriod(new Integer(50)) ;
CertificationCourse cc = new CertificationCourse(); cc.setCertName("java 275") ; cc.setCourseName("java 275 course") ; cc.setExamTime(new Timestamp(System.currentTimeMillis())) ; cc.setTotalPeriod(new Integer(50));
Session session = factory.getCurrentSession() ; session.beginTransaction() ;
session.save(gc); session.save(pc); session.save(cc);
//多态查询,将所有课程的子类信息包括课程信息全部取出 Query q = session.createQuery("from Course") ; //如果写成:Query q = session.createQuery("from CertificationCourse") ; //等价于: //Query q = session.createQuery("from Course c where c.class = 'CC'"); //可以自己试一下上面两条语句,结果是一样的,注意第二种写法,必须使用别名! Iterator it = q.list().iterator() ; while(it.hasNext()) { Course c = (Course)it.next() ; System.out.println(c.getCourseName()) ; }
session.getTransaction().commit();
session.close() ; }}
===============================================================
TPS:
在TPH下,由于不同的子类包含有不同的字段值,因此在表中必然有空的字段,存储空间浪费比较严重从数据库表设计出发,应该将那些非共性的字段单独建立表,共有数据存在另外一张表中。这就要求每个类都对应一个单独的表,子类表维护一个到父类表的外键。
新建两个子表,将主表中的无用字段去掉子表practiceCourse:
courseId Integer (既是主键又是外键,不要设为自增的)practiceName varcharpracticePeriod Integer
子表certificationCourse:
courseId Integer (既是主键又是外键,不要设为自增的)certificationName varcharexaminationTime Datetime
<class name="Course" table="courses"> <id name="id" column="course_id"> <generator class="identity" /> </id>//discriminator必须放在id元素的后面 <property name="courseName" column="course_name" /> <property name="totalPeriod" column="total_period" /> <joined-subclass name="PracticeCourse" table="practice_courses"> <key column="course_id" /> <property name="practiceName" column="practiceName" /> <property name="practicePeriod" column="practicePeriod" /> </joined-subclass> <joined-subclass name="CertificationCourse" table="cert_courses"> <key column="course_id" /> <property name="certificationName" column="certificationName" /> <property name="examinationTime" column="examinationTime"/> </joined-subclass></class>
-------------------------------------------------------老师写的配置文件:<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="vo" auto-import="true">
<class name="Course" table="courses" > <id name="id" column="course_id"> <generator class="identity" /> </id> <property name="courseName" column="course_name" /> <property name="totalPeriod" column="total_period" /> <joined-subclass name="PracticeCourse" table="practise_courses"> <key column="course_id" /> <property name="practiceName" column="project_name" /> <property name="practicePeriod" column="project_period"/> </joined-subclass> <joined-subclass name="CertificationCourse" table="cert_courses"> <key column="course_id" /> <property name="certName" column="cert_name" /> <property name="examTime" column="exam_time"/> </joined-subclass> </class> </hibernate-mapping>=========================================================================
TPC:
TPC情况下,每具体类对应一张表,不管是子类还是父类,只是不是抽象类均有一张表与之对应。表与表之间不存在主外键对应关系,数据存在冗余TPC情况下,主键不能使用identity生成器,并且必须保证子表中的字段名与父表中的字段名完全相同
和TPS不同的是,课程表中的那些共有信息比如CourseName和TatalPeriod都放到子表中来。表和表之间不再有关联了……
也就是说现在只需要两个表就成了
把courseName和totalPeriod都加到子表中去,不需要父表了,但是注意这两个从父表上继承下来的这两个属性在两个表里面必须同名!
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="vo" auto-import="true">
<class name="Course" abstract="true">//表明父类是抽象的,不能插入到一张表中去! <id name="id" column="course_id"> <generator class="increment" />//这里的配置不可以写identity!!!!!写别的可以 </id> <property name="courseName" column="course_name" /> <property name="totalPeriod" column="total_period" /> <union-subclass name="PracticeCourse" table="practise_courses"> <property name="practiceName" column="project_name" /> <property name="practicePeriod" column="project_period"/> </union-subclass>
<union-subclass name="CertificationCourse" table="cert_courses"> <property name="certName" column="cert_name" /> <property name="examTime" column="exam_time"/> </union-subclass> </class> </hibernate-mapping>
老师写的配置文件:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="vo" auto-import="true">
<class name="Course" abstract="true"> <id name="id" column="course_id"> <generator class="increment" /> </id> <property name="courseName" column="course_name" /> <property name="totalPeriod" column="period" /> <union-subclass name="PracticeCourse" table="practise_courses"> <property name="practiceName" column="project_name"/> <property name="practicePeriod" column="project_period"/> </union-subclass> <union-subclass name="CertificationCourse" table="cert_courses"> <property name="certName" column="cert_name"/> <property name="examTime" column="exam_time"/> </union-subclass> </class> </hibernate-mapping>
============================================================================================================================================
多模块登录:
数据库表:
users表:
user_id Integerusername varcharpassword varcharloginTimes integervisitTime dateTime(最近访问时间)registerTime dateTime(注册时间)
student表
user_id integerstu_no varchargrade Integerstu_name varchar
teacher表
user_id integeremp_no varcharsalary float
建立Struts的学生模块和老师模块(web.xml和struts-config-student.xml、struts-config-teacher.xml),然后建与模块同名的文件夹。
登录页面在默认模块中:index.jsp:
<html:form action="/login"> username:<html:text property="username"/><br> password:<html:password property="password" /><br> <html:submit /></html:form>
package vo
public class User{ private integer id ; private String username ; private String password ; private Integer loginTimes ; private Timestamp visitTime ; private Timestamp registerTime ;
//getter、setter方法}
package vo ;
public class Student extends User{ private String stuNo ; private Integer grade ;}
package vo ;
public class Teacher extends User{ private String empNo ; private Float salary ;}
实体映射:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="vo" auto-import="true">
<class name="User" table="users" > <id name="id" column="userId"> <generator class="identity" /> </id> <property name="username" column="username" type="string"/> <property name="password" column="password" /> <property name="loginTimes" column="loginTimes" /> <property name="visitTime" column="visitTime" /> <property name="registerTime" column="registerTime" /> <joined-subclass name="Teacher" table="teachers"> <key column="userId" /> <property name="empNo" column="emp_no" /> <property name="salary" column="salary"/> </joined-subclass> <joined-subclass name="Student" table="students"> <key column="userId" /> <property name="stuNo" column="stu_no" /> <property name="grade" column="grade"/> </joined-subclass> </class> </hibernate-mapping>
----------------------
public ActionForward execute(){ LoginForm loginForm = (LoginForm)form ; String target = "failure"; SessionFactory factory = new Configuration().addClass(User.class) .configure() .buildSessionFactory() ;
Session session = null ; try { session = factory.getCurrentSession() ; session.beginTransaction() ; Query q = session.createQuery("from User where"+ "username=:username and password=:password") ; q.setProperties(form); User u = (User)q.uniqueResult() ; if(u!=null) { if(u instanceof Teacher) { target = "teacher" ; request.getSession.setAttribute("teacher",u) ; } else if(u instanceof Student) { target = "student" ; request.getSession.setAttribute("student",u) ; } u.setLoginTimes(new Integer(u.getLoginTimes().intValue()+1)) ; u.setVisitTime(new Timestamp(System.currentTimeMillis())); } session.getTransaction().commit() ; } catch(Exception ex) { if(session!=null&&session.getTransaction()!=null) { session.getTransaction().rollback() ; } } finally { if(session!=null) { session.close() ; } } factory.close() ; return mapping.findForward(target) ;
}