Hibernate初级知识学习(2)

1.POJO类之数据类型注意事项

   当我们创建了一个POJO类Dept部门。有主键字段deptNo int,cid int,name String ,loc String..导入hibernate相关包,创建hibernate.cfg.xml.创建Dept.hbm.xml。这些都设定完毕,用List<Dept> list = session.find("from Dept");用HQL来查询Dept表的所有字段,然后用增加的for循环遍历查出来的ist。for(Dept d:list)System.out.println(d.getdeptNo+":"+d.getName+":"+d.getLoc);执行时却报了一个"Null value was assigned to a property of primitive type setter of com.ts.pojo.Dept.cid".经查发现数据库中的cid字段有null值的。于是尝试抛开cid字段,用session.find("select new Dept(deptNo,dname,loc) from Dept d");注意要创建带这个三个字段的参数的构造方法。这样就不会报上面的错误。或者把POJO类里的基本数据类型int,boolean,float这些换成Integer,Boolean,Float就不会出现上面的错误而会把NULL值给显示出来。

2.hibernate之HQL语言

查询表College,通过HQL

try {
   Session session = HibernateFactory.getHibernateSession();
   Query query = session.createQuery("from College c");//如果要加条件可以+c.cid=2
   List<College> list = query.list();
   for(College c:list)//增加的for循环格式:元素类型 空格 元素变量 冒号 要循环的集合
    System.out.println(c);//c要实现toString方法,否则打印出内存地址
  } catch (HibernateException e) {
   // TODO Auto-generated catch block()
   e.printStackTrace();
  }

通过标准SQL语句查询

try {
   Session session = HibernateFactory.getHibernateSession();
   Query query = session.createSQLQuery("select * from t_college");//如果要加条件可以+cid=2
   List<Object[]> list = query.list();
   for(Object[] c:list){
    StringBuffer sb = new StringBuffer();
    for(Object o:c)
    sb.append(o+"   ");
    System.out.println(sb);
   }
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

通过对比HQL和SQL。可以得出

1.两者都可以通过接口org.hibernate.Query来接收查询结果。

2.org.hibernate.Session既可以通过createQuery(HQL)来接收HQL查询语法,也可以通过createSQLQuery(SQL)来执行标准SQL查询语法。

3.查询出的结果,当使用HQL时直接返回具体的java类,像上面的College。方便我们使用类的方法进行操作。而使用SQL时只能用Object数组来接收每条纪录。

通过HQL更新表College。

Session session = HibernateFactory.getHibernateSession();
  Transaction ts = session.beginTransaction();//纳入事务管理
  try {
   
   Query query = session.createQuery("update College c set  c.cname='北大' where c.cid=2");//注意字符串里的字符要加引号的,且是单引号的。

  //Query query = session.createQuery("update College c set  c.cname=:cname where c.cid=:cid");//注意字符串里参数,要加=:。这个跟pascal的有点相似,嘻嘻
   //query.setInteger("cid", 2);
  // query.setString("cname", "福州大学");

//Query query = session.createQuery("update College c set  c.cname=? where c.cid=?");//注意字符串里占位符

   //query.setInteger(0, 2);
  // query.setString(1, "福州大学");
   int count = query.executeUpdate();
   ts.commit();
   if (count>0){
    System.out.println("成功修改了"+count+"行");
   }
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally{
   HibernateFactory.closeSession(session);
  }

总结:更新表语句和查询表语句是HQL时都是通过session.createQuery(HQL)来接收语句的。查询通过.list()方法返回查出实体对象List集合,而更新语句是通过org.hibernate.Query的executeUpdate()返回整数类型,即更新或删除的数量。数量大于0表示执行成功。更新,保存操作一般都要纳入session的事务管理。

HQL可以通过在HQL语句中用=:指定参数。然后紧接着用query.setString(" 参数串",参数值);给参数赋值。

HQL可以通过在HQL语句中用占位符?来指定参数。然后紧接着用query.setString(" 参数位置",参数值);给参数赋值。参数位置从0开始。

HQL还可以通过setParametor来指定参数。

3.hibernate之主键生成策略

被映射类必须定义对应数据库主键字段,<id>元素定义了该属性到数据库主键字段的映射。<generator>子元素是一个java类的名字,用来为该持久化类的实例生成唯一标识。

 Asigned

由程序设置主键。设置必须在save之前完成。

Increment

由hibernate维护生成策略。找出主键字段最大值加1

Indentity

由底层数据库维护的主键生成策略。

需要特定数据库特性支持。mysql或sqlserver

Sequence

Oracle,ProgreSQL数据库支持。底层数据库维护

Native

根据底层数据库特性,自动选择Identity,Sequence.只可以是整型。

UUID

复合主键

需要配置<composite-id>

4.hibernate之主键外键关联

College类还用上面的类.创建一个学生类。

public class Student{

  private int sid;

  private Stirng

 private College college;

set get 方法

}

Student的hbm.xml映射文件如下:

<?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="com.ts.pojo" >
    <class name="Student" table="t_Student" lazy="true">
      <!-- 持久化标识即主键 -->
      <id name="stuId" column="sid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="identity"></generator>
      </id>
      <property name="stuName" column="s_name" type="string" length="20"></property>
      <many-to-one name="college" class="College" column="cid" unique="true" cascade="all"></many-to-one>
    </class>
</hibernate-mapping>

}

一个学校有多个学生。所以学生和学校是多对一的关系。学生类里面有一个学校的属性,对应学生表里就是cid。如果在保存学生信息的时候,给学生指定了学校,当学校表里

又没有这个学校时。会自动在学校表里插入一条纪录。注意many-to-one是在多的一方的映射文件中配置的。这里学生是多的一方,要配置的name是多的一方Student类中的一的一方的关联属性即college,而class是关联属性所指向的类即College。column是多的一方所对应的表中关联的那个字段即cid来关联指向学校表的主键id。

在保存学生信息到学生表里时,也会保存一条学生所在学校的信息到学校表里去。

代码如下:Session session = HibernateFactory.getHibernateSession();
  Transaction ts = session.beginTransaction();//纳入事务管理
  try {
   College c1 = new College();
   c1.setCname("zhongsandaxue");
   c1.setProvince("guangdong");
   c1.setCity("guangzhou");
   c1.setCdate(new Date(System.currentTimeMillis()));
   Student s1 = new Student();
   s1.setStuName("xiaohong");
   s1.setCollege(c1);
   //session.save(c1);//即使不要这句。只要在Student.hbm.xml中配置了many-to-one。也会在数据库中保存一条C1的信息的。叫级联操作。上面设了cascade为all的。
   session.save(s1);
   ts.commit();
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally{
   HibernateFactory.closeSession(session);
  }

 一对一,假如一个学校仅且只仅有一个学生。那么我们保持学生的class是Student和映射文件不变。给学校的类增加一个Student类型的属性。然后在College.hbm.xml中配置

one-to-one。如下

<class name="College" table="t_College" lazy="false">
      <!-- 持久化标识即主键 -->
      <id name="cid" column="cid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="identity"></generator>
      </id>
      <property name="cname" column="c_name" type="string" length="20"></property>
      <property name="province" column="c_province" type="string" length="20"></property>
      <property name="city" column="c_city" type="string" length="10"></property>
      <property name="cdate" column="c_date" type="date"></property>
      <one-to-one name="stu" class="Student" cascade="all" property-ref="college"></one-to-one>
    </class>

<one-to-one>配置属性name为和本类一对一对应的那个类在本类中的属性。class指和本类一对一对应的那个类,而property-ref指和本类一对一对应的那个类的属性中指定

本类的那个属性名,即主键表中指定外键表中关联本表的那个属性

这样和上面一样,保存student的时候自动保存college.

下面是查询。查询可以实现双向。查出任一方,带出另一方。

Session session = HibernateFactory.getHibernateSession();
  Transaction ts = session.beginTransaction();//纳入事务管理
  try {
   College c1 = null;
   c1 = (College)session.get(College.class, 5);
   System.out.println(c1);
   Student s1 = c1.getStu();//通过查询出College,可以带出和College相关联的Student。反之,先查Student然后也会关联到College.
   System.out.println(s1);
   ts.commit();
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally{
   HibernateFactory.closeSession(session);
  }

 

 hibernate之外键关联一对多

一个公司Company有多个员工Emp。对应一个公司表,compid公司ID,compname公司名称。一个员工表empid员工IDempname员工姓名compid员工公司。

现在要新增一条公司信息,公司有三个员工,由于公司表的主键compid是员工表的外键,所以通过配置Company.hbm.xml和Emp.hbm.xml可以实现增加一个公司纪录,同时增加几条员工纪录,当然要提前指定员工属于哪个公司。

公司类

public class Company {
 private int compId;
 private String compName;
 private Set<Emp> set;//注意这个属性是一个由员工作为元素的set集合

员工类

public class Emp {
 private int empId;
 private String empName;
 private Company comp;//注意这里是类类型。指明员工的所在公司。

上面别忘了get/set方法。

Company.hbm.xml

<hibernate-mapping package="com.ts.pojo" >
    <class name="Company" table="company">
      <!-- 持久化标识即主键 -->
      <id name="compId" column="compid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="identity" ></generator>
      </id>
      <property name="compName" column="compname" type="string" length="20"></property>
      <set name="set" cascade="all" inverse="true">
         <key column="compid"></key>
         <one-to-many class="Emp" />
      </set>
    </class>
</hibernate-mapping>

//重点关注<set>元素的配置,cascade表明所有操作都会级联,要指明set集的子元素key也就是本关联表的关键字段。compid.本表主键。

要指明set集的子元素<one-to-many>的class属性是set集合中元素的类。Emp

 

Emp.hbm.xml

<hibernate-mapping package="com.ts.pojo" >
    <class name="Emp" table="t_Emp">
      <!-- 持久化标识即主键 -->
      <id name="empId" column="empid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="native"></generator>
      </id>
      <property name="empName" column="empName" type="string" length="20"></property>

      <many-to-one name="comp" class="Company" column="compid"></many-to-one>
    </class>
</hibernate-mapping>

 

关注多的一方的<many-to-one>元素。它的name即指表多的一方Emp类的指向一的一方的属性。这里是comp指向Company。class要指明作为一方的那个类。column当然是本表中指向主表的关联字段compid

 

代码如下:公司增加一条。员工增加三条。

Company c = new Company();
  c.setCompName("aaa有限公司");
  Set<Emp> set = new HashSet<Emp>();
  Emp e1 = new Emp();
  e1.setEmpName("shangsan1");
  e1.setComp(c);
  
  Emp e2 = new Emp();
  e2.setEmpName("shangsan2");
  e2.setComp(c);
  
  Emp e3 = new Emp();
  e3.setEmpName("shangsan3");
  e3.setComp(c);
  
  set.add(e1);
  set.add(e2);
  set.add(e3);
  c.setSet(set);
  
  Session session = null;
  Transaction ts = null;
  try {
   session = HibernateFactory.getHibernateSession();
   ts = session.beginTransaction();
   session.save(c);
   ts.commit();
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   if(session!=null){
    session.close();
   }
  }

 

hibernate之外键关联多对多<many-to-many>

多对多,举例老师和学生。一个老师可以教多个学生。一个学生可以被多名老师带。定义一个类Teacher一个类Stu

老师类

public class Teacher {
 private int tid;
 private String tname;
 private int tage;
 private Set<Stu> stus;

学生类

public class Stu {
   private int stuid;
   private String stuname;
   private int stuage;
   private Set<Teacher> teas;

Teacher.hbm.xml配置文件如下

<hibernate-mapping package="com.ts.pojo" >
    <class name="Teacher" table="t_Teacher" lazy="true">
      <!-- 持久化标识即主键 -->
      <id name="tid" column="tid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="native">
         </generator>
      </id>
      <property name="tname" column="tname" type="string" length="20"></property>
      <property name="tage" column="tage" type="integer"></property>
     
      <set name="stus" cascade="save-update" table="teas_stus">
         <key column="teaid"></key>
         <many-to-many class="Stu" column="stuid"></many-to-many>
      </set>
     
    </class>
</hibernate-mapping>

重点关注配置文件的红色部分及Teacher的private Set<Stu> stus;

既然Teacher用Set集合来存储一个老师教的多个学生。那么自然要在Teacher.hbm.xml中配置set元素了。

<set>里的name属性是指Set集合类型的成员名, 这里是stus。cascade是级联方式。这里是用save-update.就是保存老师信息,同时保存学生信息。如果是all那么会删除老师信息并且也删除该老师带的学生的信息。这样当然是不合理的,因为老师辞职,学生不一定离校,所以不用all.另外还要强调一点的是,还有一个table属性。 这个属性是指定一个中间表的,用来关联老师表和学生表。当出现多对多的关联时,必然会出现一张中间表来进行关联。  这里是teas_stus.

<set>里有一个元素key,就是主键的意思,它的name属性指定与Set集合关联的主键字段,当然是teaid.,多个Stu纪录都指向同一个teaid。

最后配置多对多<many-to-many>它的class属性指向Set集合中元素类型这里是Stu类。column属性指向Set元素的主键stuid

OK让我们一块看下Stu.hbm.xml吧。

<hibernate-mapping package="com.ts.pojo" >
    <class name="Stu" table="t_Stu" lazy="true">
      <!-- 持久化标识即主键 -->
      <id name="stuid" column="sid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="native">
         </generator>
      </id>
      <property name="stuname" column="sname" type="string" length="20"></property>
      <property name="stuage" column="sage" type="integer"></property>
      <set name="teas" cascade="save-update" table="teas_stus">
         <key column="stuid"></key>
         <many-to-many class="Teacher" column="teaid"></many-to-many>
      </set>
    </class>
</hibernate-mapping>

这里也要注意红色的配置部分。其它是和老师的配置是一样的。他们刚好构成一个双向多对多的关系。如果不这样配置Stu.hbm.xml那么就是一个一对多的关系。

也就是当增加一个老师信息时,如果指定了这个老师带的几个学生信息,并把学生信息存到Set集合中,保存老师信息时,自动保存该老师的学生信息。反之亦然。

代码示例如下:

public static void save_tea_stu(){
  Teacher t1 = new Teacher();
  t1.setTname("MrZhang");
  t1.setTage(40);
  Teacher t2 = new Teacher();
  t2.setTname("MrLi");
  t2.setTage(40);
  Teacher t3 = new Teacher();
  t3.setTname("MrLiu");
  t3.setTage(40);
  
  Stu s1 = new Stu();
  s1.setStuname("xiaohonng");
  s1.setStuage(12);
  
  Stu s2 = new Stu();
  s2.setStuname("xiaojun");
  s2.setStuage(15);
  Stu s3 = new Stu();
  s3.setStuname("xiaokai");
  s3.setStuage(13);
  Stu s4 = new Stu();
  s4.setStuname("xiaochen");
  s4.setStuage(16);
  
  Set<Stu> set1 = new HashSet<Stu>();
  set1.add(s1);
  set1.add(s2);
  set1.add(s3);
  t1.setStus(set1);
  
  
  Session session = null;
  Transaction ts = null;
  try {
   session = HibernateFactory.getHibernateSession();
   ts = session.beginTransaction();
   session.save(t1);
   ts.commit();
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   if(session!=null){
    session.close();
   }
  }
 }

补充:在POJO类中,多的一方作为一的一方的成员时,除了用Set作为集合来接收多的一方的数据外还可以使用List集合来接收多的一方数据。例如下:

public class Teacher {
 private int tid;
 private String tname;
 private int tage;
 /*private Set<Stu> stus;
 public Set<Stu> getStus() {
  return stus;
 }
 public void setStus(Set<Stu> stus) {
  this.stus = stus;
 }*/
 private List<Stu> stus;

 

如果这样的类,那Teacher.hbm.xml也要按下面来设置才行。

<hibernate-mapping package="com.ts.pojo" >
    <class name="Teacher" table="t_Teacher" lazy="true">
      <!-- 持久化标识即主键 -->
      <id name="tid" column="tid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="native">
         </generator>
      </id>
      <property name="tname" column="tname" type="string" length="20"></property>
      <property name="tage" column="tage" type="integer"></property>
      <!-- 
      <set name="stus" cascade="save-update" table="teas_stus">
         <key column="teaid"></key>
         <many-to-many class="Stu" column="stuid"></many-to-many>
      </set>
      -->
      <list name="stus" cascade="save-update" table="teas_stus">
         <key column="teaid"></key>
         <index column="stuid_index"></index>
         <many-to-many class="Stu" column="stuid"></many-to-many>
      </list
>
    </class>
</hibernate-mapping>

还要着重关注红色的配置部分。这个跟Set也差不多,不同之处有二:一是List配置文件要配索引,二是List配置的index元素的column不能字段或列名重名。

List<Stu> list1 = new ArrayList<Stu>();
  list1.add(s1);
  list1.add(s2);
  list1.add(s3);
  t1.setStus(list1);

Hibernate之由表反向生成类和映射文件

这个功能在MyEclpse的最近几个版本上都可以直接使用。使用MyEclipse Database Explorer视图,在里面连接好数据库,建好表和字段,选择表后右键反向生成。如果是Eclips需要下载相关插件。

 

Hibernate之类与类之间Has a的关系

例如Person类里有一个成员是Address。即人有自己的地址。而地址也是一个类。这种情况还是很觉见的。

Person类

public class Person {
 private int pid;
 private String pname;
 private Address address;

Address类

public class Address {
   private String province;
   private String city;
   private String street;

 

Person.hbm.xml的映射文件

<hibernate-mapping package="com.ts.pojo" >
    <class name="Person" table="t_person">
      <!-- 持久化标识即主键 -->
      <id name="pid" column="pid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="identity" ></generator>
      </id>
      <property name="pname" column="pname" type="string" length="20"></property>
     <component name="address" class="Address">
       <property name="province" column="province" type="string" length="20"></property>
       <property name="city"  column="city" type="string" length="20"></property>
       <property name="street"  column="street" type="string" length="20"></property>
     </component>
    </class>
</hibernate-mapping>

重点关注红色部分。配一个component的元素。属性name就是该component在主类Person中的成员名。classs指向该成员的类类型。

component下的有三个子属性,分别是类Addrss的三个成员。要分别指定每个成员对应的数据库的column即列名。还有数据类型,这样才能在创建表时创建相应字段,生成数据时自动关联到对应列中去。

 

public static void generatePerson(){
  Person p= new Person();
  p.setPname("gaoyang");
  Address addr = new Address();
  addr.setProvince("henane");
  addr.setCity("anyang");
  addr.setStreet("gaugngmingdadao45hao");
  p.setAddress(addr);
  Session session = null;
  Transaction ts = null;
  try {
   session = HibernateFactory.getHibernateSession();
   ts = session.beginTransaction();
   session.save(p);
   ts.commit();
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   if(session!=null){
    session.close();
   }
  }
 }

执行脚本如下

Hibernate:
    insert
    into
        t_person
        (pname, province, city, street)
    values
        (?, ?, ?, ?)

 

Hibernater的继承关系使用

新建两个类Farmer和Worker继承自Person

public class Farmer extends Person{

private String farm;

}

public class Worker extends Person{

private String factory';

}

不要忘了getset方法

Person.hbm.xml配置文件

hibernate-mapping package="com.ts.pojo" >
    <class name="Person" table="t_person">
      <!-- 持久化标识即主键 -->
      <id name="pid" column="pid" type="integer">
      <!-- 主键的生成策略 -->
         <generator class="identity" ></generator>
      </id>
      <discriminator column="category" type="string" length="20"></discriminator>
      <property name="pname" column="pname" type="string" length="20"></property>
     <component name="address" class="Address">
       <property name="province" column="province" type="string" length="20"></property>
       <property name="city"  column="city" type="string" length="20"></property>
       <property name="street"  column="street" type="string" length="20"></property>
     </component>
     <subclass name="Farmer" discriminator-value="STUDENT">
       <property name="farm" column="farm" type="string" length="20"></property>
     </subclass>
     <subclass name="Worker" discriminator-value="WORKER">
        <property name="factory" column="factory" type="string" length="30"></property>
     </subclass>
    </class>
</hibernate-mapping>

注意discriminator要紧接着id放,否则会报错,column会在Person对应的表里增加的字段。默认值就是下面<subclass>中的discriminator-value的值,不同的子类可以设不同

<subclass的name指定子类的类名discriminator-value也在这个地方>子元素指定子类独有的属性<property>name是子类中的成员名,column是指在表中生成的字段,type指定该字段的数据类型

生成数据代码如下

public static void generatePerson(){
    Address addr = new Address();
  addr.setProvince("henane");
  addr.setCity("anyang");
  addr.setStreet("gaugngmingdadao45hao");
  Worker w = new Worker();
  w.setPname("work");
  w.setFactory("Factory");
  w.setAddress(addr);
  Farmer f = new Farmer();
  f.setPname("farmer");
  f.setFarm("farm");
  f.setAddress(addr);
  Session session = null;
  Transaction ts = null;
  try {
   session = HibernateFactory.getHibernateSession();
   ts = session.beginTransaction();
   session.save(w);
   session.save(f);
   ts.commit();
  } catch (HibernateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   if(session!=null){
    session.close();
   }
  }
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值