Hibernate 3.x

来源:互联网 发布:dnf韩服体验服账号淘宝 编辑:程序博客网 时间:2024/06/05 19:32

----------------------------Hibernate简介----------------------------

模型不匹配(阻抗不匹配)

Java面向对象语言,对象模型,其主要概念有:继承、关联、多态等;

数据库是关系模型,其主要概念有:表、主键、外键等。

想用Java来操作关系型数据库的时候,就会有阻抗不匹配的情况出现

 

解决办法

使用JDBC手工转换。

使用ORM(ObjectRelation Mapping对象关系映像)框架来解决,主流的ORM框架有HibernateTopLinkOJB

 

衔接对象和关系模型完全是由映像文件办到的

 

 

--------------------------------安装配置------------------------------

下载地址http://www.hibernate.org,本教程使用3.2.5

将下载目录/hibernate3.jar/lib下的hibernate运行时必须的包加入classpath中:

antlr.jar,

cglib.jar,

asm.jar,

commons-collections.jar,

commons-logging.jar,

jta.jar,

dom4j.jar

配置文件hibernate.cfg.xmlhibernate.propertiesXMLproperties两种,这两个档的作用一样,提供一个即可,推荐XML格式,下载目录/etc下是示例配置文件。

可以在配置文件指定:

       数据库的URL、用户名、密码、JDBC驱动类、方言等。

启动时Hibernate会在CLASSPATH里找这个配置文件。

映射文件(hbm.xml,对象模型和关系模型的映像)。在/eg目录下有完整的hibernate示例。

 

 

--------------------------- Domain Object限制-------------------------

1.   默认的构造方法(必须具有的一个无参的默认构造方法)

如果含有一个有参的构造方法的,这样的JavaBeanHibernate是没有办法给管理的

2有无意义的标示符id(主键)(可选)

可以在JavaBean中没有主键id,但是没有的话,有一些方法就会受到一些限制,就不能完全发挥hibernate的一些特性,这样操作起来就会方便一些

3final的,对懒载入有影响(可选)

因为加上final的类,会不能被继承等限制

DomainJava Object(User)

publicclass User {

    private int id;

    private Stringname;

    private DatebirthDay;

    //getter setter…

}

 

 

---------------------------一个简单的映射档-------------------------

hbm.xml

<?xmlversion="1.0"?>

<hibernate-mappingpackage=“cn.itcast.domain">

<classname="User" table="user">

    <idname="id">

       <generatorclass="native"/>

    </id>

    <propertyname="name"/>

    <propertyname="birthday”/>

</class>

</hibernate-mapping>

Hibernate的映像文件就是用于说明java对象与哪个表中的记录相对应,以及Java对象中的各个属性分别对应表中的哪一列,不同性质的属性(例如主键和普通属性)用不同的标签来映像,如果Java对象中的某个属性不需要存储在数据库中,那么在Hibernate映像文件就不需要配置这个属性!

 

 

------------------------------简化Session----------------------------

创建一个工具类HibernateUtil,用来打开和关闭session,以简化每次重复的操作

public final class HibernateUtil {

    private static SessionFactory sessionFactory;

    private static ThreadLocal session = new ThreadLocal();

 

    private HibernateUtil() {

}

 

    static {

       Configuration cfg = new Configuration();

       cfg.configure();

       sessionFactory = cfg.buildSessionFactory();

    }

 

    public static void closeSession() {

       Session s = (Session) session.get();

       if (s != null) {

           s.close();

           session.set(null);

       }

    }

 

    public static SessionFactorygetSessionFactory() {

       return sessionFactory;

    }

 

    public static Session getSession() {

       return sessionFactory.openSession();

    }

}

 

 

-------------------------Session的几个主要方法-------------------------

1.save,persist保存数据,persist在事务外不会产生insert语句。

2.delete,删除对象

3.update,更新对象,如果数据库中没有记录,会出现异常。

4.get,根据ID查,会立刻访问数据库。

5.Load,根据ID查,(返回的是代理,不会立即访问数据库)

6.saveOrUpdate,merge(根据IDversion的值来确定是saveupdate),调用merge你的物件还是托管的。

7.lock(把对象变成持久对象,但不会同步对象的状态)

 

 

---------------------------save-persist方法--------------------------

这两个方法都表示insert,效果是一样的,但是在有关事务的操作上有区别

如果你不开启事务:

save方法是先执行插入操作,由于没有提交,然后再回滚数据,数据库中也不会含有该记录

但是如果使用了show_sql特性,那么会显示出来insert的插入语句

persist方法是根本就不执行,即使使用了show_sql特性也不会看到会有insert语句的

 

static void addUser(User user) {

       Session s = null;

       Transaction tx = null;

       try {

           s = HibernateUtil.getSession();//通过HibernateUtil自定义的工具类来获取session

           tx = s.beginTransaction();//开启事务

           s.save(user);

           //s.persist(user);

           tx.commit();//提交

          

       } catch (HibernateException e) {

           if (tx != null)

              tx.rollback();

           throw e;

       } finally {

           if (s != null)

              s.close();

       }

    }

 

 

-----------------------------get-load方法----------------------------

static User getUser(int id) {

       Session s = null;

       try {

           s = HibernateUtil.getSession();

          

           Query q = s.createQuery("from Userwhere id=:id");

           q.setInteger("id", id);

           q.uniqueResult();

           //User user = (User) s.get(User.class, id);

           /* 查询操作,根据主键id的值获取相应的一条记录(返回一个对象),

           User.class表示通过反射机制来找到相应的xxx.hbm.xml文件并匹配 */

           User user1 = (User) s.load(userClass, id);

           /* load方法虽然写法上与get方法很相似,但是他不是立刻访问数据库,

           返回的对象第一次使用的时候才去真正的加载数据库

           例如:

           User user1 = (User) s.load(userClass, id);

           return user1; 

           这样执行以后如果user1并没有去获取某个属性的值,那么返回的user1对象里边不会包含任何数据

           只有当:User user1 = (User) s.load(userClass, id);

           System.out.println(user1.getName());

           return user1;

           这样返回的user1对象,才包含了查询数据库以后所得到的数据

           这个技术叫做懒加载,它不是真正的访问数据库,而是第一次使用时才去访问数据库的

           load方法所返回的对象永远不会为空(null),永远不要写这样的代码

           if(user1==null){

           }

           if(user1!=null){

           }

           即使参数主键id的值不存在,返回的对象也不会为空

           因为前面讲过定义的Javabean不能为finalload方法所加载的类会通过继承该Javabean

           而得到一个子类,这个类是直接new出来的

          

           查看load方法所返回的Javabean子类的名称:

           System.out.println(user1.getClass().getName());

           */

           Hibernate.initialize(user1);

           System.out.println(user1.getName());

           return user1;

       } finally {

           if (s != null)

              s.close();

       }

    }

 

 

-----------------------saveOrUpdate-merge方法------------------------

saveOrUpdate方法根据IDversion的值来自动判断是saveupdate

如果javabean中包含有id,说明对象是脱管状态,就执行update

反之,如果不包含id,说明瞬时状态,执行save

调用saveOrUpdate方法后,对象会变成持久的

调用merge方法后,对象还是脱管的

 

 

--------------------------------对象状态------------------------------

1.    瞬时(transient):数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器回收,一般是new出来且与session没有关联的对象。

2.    持久(persistent):数据库中有数据与之对应,当前与session有关联,并且相关联的session没有关闭,事务没有提交;持久对象状态发生改变,在事务提交时会影响到数据库(hibernate能检测到)

3.    脱管(detached)(也可称为游离态):数据库中有数据与之对应,但当前没有session与之关联;托管对象状态发生改变,hibernate不能检测到。

 

public class Test1 {

    //考虑持久化物件的生命周期

       public static void main(String[] args) {

          

       Books book=new Books("java", "Java2学习11", 12.36f, "123.jpg");

//不包含任何的数据库的信息,只是数据的封装

       //此时book对象在内存中自由的存在,他与数据库无关,随程序的执行而消失(Transient)

       //瞬态向持久态转换

       Session session=HibernateSessionFactory.getSession();  

       Transaction tx = session.beginTransaction();

       session.save(book);

//此时book对象由Hibernate管理,此时book对象在hibernate管理内存(persistent)

       System.out.println(book.getBid());

       tx.commit();

//持久化,保存在数据库中,管理器中应该含有一个book对象(该对象和数据库中的内容一致的)

       book.setBname("C#");

//在管理器中修改了book对象    ? :数据库中的数据改变吗  改变,因为是持久化

       tx.commit();

//再一次的持久化

       //?:执行了Update操作 ,修改的是那里的数据

          

       session.close();

//关闭了session的管理

       System.out.println(book.getBid());

//游离态(Detached)

       //? TransientDetached的区别

       /*

       Detached状态的对象可以再次与某个session进行关联 ,再次变成persistent

       */

       session=HibernateSessionFactory.getSession();

       session.saveOrUpdate(book);//再次发生持久,id信息保存的

       session.beginTransaction().commit();

       session.close();

       //?TransientDetached 都与Hibernate的容器无关 ,有什么差异

       //Detached: 包含一些额外的信息(持久化的信息)

    }

}

 

------------------------------HQL --------------------------

1.    HQL(Hibernate Query Language)

面向对象的查询语言,与SQL不同,HQL中的对象名是区分大小写的(除了JAVA类和属性其他部分不区分大小写);HQL中查的是对象而不是和表,并且支持多态;HQL主要通过Query来操作,Query的创建方式:

Query q = session.createQuery(hql);

from Person

from User user whereuser.name=:name

from User user whereuser.name=:name and user.birthday < :birthday

2.    hql的命名参数

这个是普通的写法

s = HibernateUtil.getSession();

String hql = "from User asuser where user.name=?;// from Object

Query query = s.createQuery(hql);

query.setString(0, name);

0这个索引号必须要和?的位置一一对应,这种对应的维护起来可能就稍微麻烦一些

所以就有一种更好的方式,叫做命名参数

String hql = "from User asuser where user.name=:n";

query.setString("n",name);

就是把?给起个名字,query.setString("n", name);这样对应的就是名字,而不依赖于位置了

3.    分页查询

query.setFirstResult(200);//第一条记录从哪开始取

query.setMaxResults(10);//取多少条

这两个方法是可以实现分页的

这种分页的好处是可以实现跨数据库,可移植的

Mysqllimit分页,sqlServertopOraclenumber,这些关键词都是不一样的

那么hibernate是通过哪个参数知道要用哪个分页的呢

hibernate.cfg.xml配置文件中配置

<propertyname="dialect">org.hibernate.dialect.MySQLDialect

</property>

4.   查询只取一个对象

User u = (User) query.uniqueResult();

结果集如果确定只有一行,就可以用这个方法,如果返回的是多行,就会报异常了

 

 

--------------------------------Criteria-----------------------------

1.   Criteria

Criteria是一种比HQL更面向对象的查询方式;Criteria的创建方式:

Criteria crit = session.createCriteria(DomainClass.class);

简单属性条件如:criteria.add(Restrictions.eq(propertyName,value)),

criteria.add(Restrictions.eqProperty(propertyName,otherPropertyName))

 

 

---------------------------自定义主键的生成----------------------------

产生一些有规律的主键(唯一值 id),要求:yyyymmdd+流水号

1.   创建表

create table orders(

    idvarchar(50) primary key,

    pricefloat not null

)

2.   创建Orders表的javabean,及配置文件Orders.hbm.xml

3.   hibernate.cfg.xml配置文件中添加对类配置文件的映射

4.    创建一个工具类OrderPKGen,该类实现了IdentifierGenerator接口

public class OrderPKGen implements IdentifierGenerator{

    //自定义主键的生成

    //创建一个日期的输出格式

    private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd-");

    //这里一定得是小写y,大写M,小写d,否则其表示的意义会变化

    public Serializablegenerate(SessionImplementor arg0, Object arg1) throws HibernateException {

       //生成主键的方法,需要使用hibernate所提供的身份生成器的接口

       String dataPart=sdf.format(new Date());

       return dataPart+System.currentTimeMillis();

       //返回的逐渐值为 当前的年月日+系统当前时间的毫秒数

    }

}

5.   写一个测试类

public class IDTest {

 

    public static void main(String[] args) {

      

       Configuration cfg=new Configuration();

       cfg.configure();

       SessionFactory sf=cfg.buildSessionFactory();

       Session s=sf.openSession();

       Transaction tx=s.beginTransaction();

      

       Orders o=new Orders();

       o.setDesc(27.8f);

       s.save(o);

       System.out.println(o.getId()+" "+o.getPrice());

      

       tx.commit();

       s.close();

    }

}

---------------------------------多对一-------------------------------

多对一(Employee -Department)

ER

一个部门包含了多个员工,但从员工的角度来看问题,就是多对一了

1.   创建数据表

createtable Department(

    id int primarykey,

    name varchar(10)

);

createtable Employee(

    id int primarykey,

    name varchar(10),

    depart_id int

);

2.   创建javabean Department类和Employee

Department.java

public class Department {

 

    private int id;

    private String name;

   

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

}

 

Employee.java

public class Employee {

 

    private int id;

    private String name;

    private Department depart;

   

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Department getDepart() {

       return depart;

    }

    public void setDepart(Department depart) {

       this.depart = depart;

    }

}

3.   创建配置文件

Department.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="Department">

       <id name="id">

           <generator class="native"/>

       </id>

       <property name="name"/>

    </class>

</hibernate-mapping>

 

Employee.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="Employee">

       <id name="id">

           <generator class="native"/>

       </id>

       <property name="name"/>

       <!--我们用property所映像的属性只能是简单属性,字符串或者是整型的 -->

       <!--根据对象之间的关系,来判断使用什么标签-->

       <many-to-one name="depart"column="depart_id" ></many-to-one>

       <!--<many-to-one>专门用来描述多对一的关系,

           name表示多对一关系中n所定义的1的对象名,

           column表示与数据表中所对应的字段,若不设置该属性,默认的字段名为该对象名

              该字段默认对应1的主键id,如果1的主键是name属性或者其他

              而不是id,则需要使用property-ref="name"属性来设置对应1的主键  -->

    </class>

</hibernate-mapping>

4.   hibernate.cfg.xml配置文件中添加对类配置文件的映射

<mapping resource="com/domain/Department.hbm.xml"/>

<mapping resource="com/domain/Employee.hbm.xml"/>

5.   测试类

public class ManyToOne {

 

    public static void main(String[] args) {

       Session s=HibernateUtil.getSession();

       Transaction tx=s.beginTransaction();

      

       Department depart=new Department();

       depart.setName("会计");

      

       Employee emp=new Employee();

       emp.setName("Shiki");

       emp.setDepart(depart);

      

       s.save(depart);

       s.save(emp);

      

       tx.commit();

       s.close();

    }

}

 

这里有个小插曲,执行的时候报错了

Could not find the class,Problem will exit

一开始不明白,后来上网查查原来是因为我们使用高版本的JDK编译的Java class档试图在较低版本的JVM上运行,所报的错误。   因为,高版本的JDK生成的class档使用的格式,可能与低版本的JDK.class文件格式不同。这样,低版本的JVM无法解释执行这 .class文件,会抛出Could not find the main class.program will exit不支持的Class版本错误。 这个错误尤其在JDK5JDK5之前的版本上表现明显。因为,JDK5Java语法上作了不少增强,引入了一 些新的.class文件的元素,导致旧版本的JVM无法解释、执行.class文件。例如这个类并没有使用任何JDK5的新元素,但是JDK1.5生成 .class文件,JDK1.4及其以前的JVM都无法辨认。

解决方法:

1. 弄清楚该程序是在哪个JDK版本下开发的 

2. myEclipse 菜单->Windows->Proferences->java-> Installs Jres重新设置JDK路径,改为开发程序时的JDK版本(我做到这一步就可以了!我的eclipse7.0jdk6u13的。)

3. Windows->Proferences->java->Compiler,将compilercompliance level设置为与上面相同的JDK

我所使用的hibernate的版本为3.5.4,错误不知为何

 

 

---------------------------------一对多-------------------------------

一个部门包含了多个员工,从部门的角度来看问题,就是一对多了

 

Department檔中,增加一个泛型为Employee类型的Set集合

private Set<Employee> emps=new HashSet<Employee>();

用来存储多个员工对象,也就是一个部门包含多个员工

 

修改1方的配置文件

<set name="employees">

           <key column="depart_id"/><!--column描述n的外键,用于与1集合中的数据对应上 -->

           <one-to-many class="Employee"/><!--class指定集合中存放数据的类型 -->

</set>

 

 

---------------------------------一对一-------------------------------

基于主键的一对一(Person - IdCard)

ER

一个人有一个身份证卡,从两边来看都是一对一的关系

Person为主表,id为主键,从表id_card表的id为外键,在配置文件中设置id_card的外键引用

1.   创建表

hibernate.cfg.xml配置文件中,设置

<property name="hbm2ddl.auto">update</property>

自动创建表格,并自动更新数据

2.   Javabean

创建Person类和ID_Card类,因为是一对一关系,所以各自的类中都包含一个对应类的实例对象

Person.java

public class Person {

 

    private int id;

    private String name;

    private int age;

    private ID_Card card;

   

    public int getAge() {

       return age;

    }

    public void setAge(int age) {

       this.age = age;

    }

    public ID_Card getCard() {

       return card;

    }

    public void setCard(ID_Card card) {

       this.card = card;

    }

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

   

}

 

ID_Card.java

public class ID_Card {

 

    private int id;

    private String name;

    private Person person;

   

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Person getPerson() {

       return person;

    }

    public void setPerson(Person person) {

       this.person = person;

    }

   

}

3.   配置文件

Person.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="Person">

       <id name="id">

           <generator class="native"/>

       </id>

 

       <property name="name"/>

       <property name="age"/>

       <one-to-one name="card"></one-to-one><!-- 一对一关系,对应在Person类中所定义的card对象 -->

    </class>

</hibernate-mapping>

 

ID_Card.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="ID_Card">

       <id name="id">

           <generator class="foreign">

              <param name="property">person</param>

           </generator>

       </id>

 

       <property name="name"/>

       <one-to-one name="person"constrained="true"></one-to-one>

       <!--对应person对象,constrained属性表示创建表时带有外键关联,使用show create table xxx 可查看建表语句  -->

    </class>

</hibernate-mapping>

4.   hibernate.cfg.xml配置文件中添加对类配置文件的映射

5.    测试类

OneToOne.java

public class OneToOne {

 

    public Person add(){

      

       Session s=HibernateUtil.getSession();

       Transaction tx=s.beginTransaction();

      

       Person p=new Person();

       p.setName("1");

       p.setAge(22);

      

       ID_Card card=new ID_Card();

       card.setName("120101xxxxxxxxxxxx");

      

       //p.setCard(card);

       card.setPerson(p);

      

       s.save(p);

       s.save(card);

       tx.commit();

       s.close();

      

       return p;

    }

   

    public void query(int id){

      

       Session s=HibernateUtil.getSession();

       Transaction tx=s.beginTransaction();

      

       //查询主对象person

       //Person p=(Person) s.get(Person.class,id);

       //System.out.println(p.getCard().getName());

      

       //查询从对象id_card

       ID_Card card=(ID_Card)s.get(ID_Card.class,id);

       System.out.println(card.getPerson().getName());

      

       tx.commit();

       s.close();

      

    }

   

    public static void main(String[] args) {

       OneToOne o=new OneToOne();

       Person p=o.add();

       o.query(p.getId());

    }

}

 

基于外健的一对一(Person - IdCard)

PersonOneToOne,而id_card采用ManyToOne,也就是一个Person可以有多个id_card,但是从id_card中来限制其唯一性,就演变成唯一的多对一,其实就变成了一对一了

修改配置文件及表结构

Person.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="Person">

       <id name="id">

           <generator class="native"/>

       </id>

       <property name="name"/>

       <property name="age"/>

       <one-to-one name="card"property-ref="person"/>

       <!--property-ref用于指定关联类的一个属性,这个属性将会和本外键相对应-->

    </class>

</hibernate-mapping>

 

ID_Card.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="ID_Card">

       <id name="id">

           <generator class="foreign">

              <param name="property">person</param>

           </generator>

       </id>

       <property name="name"/>

       <many-to-one name="person"column="person_id" unique="true" not-null="true"/>

    </class>

</hibernate-mapping>

 

 

---------------------------------多对多-------------------------------

多对多(teacher -student)

在操作和性能方面都不太理想,所以多对多的映射使用较少,实际使用中最好转换成一对多的对象模型;Hibernate会为我们创建中间关联表,转换成两个一对多。

 

ER

Teacher有多个studentstudent也可以有多个教师

多对多就是由两个一对多组合而成(数据库由hibernate自动生成)

1.   Javabean

 

Teacher.java

public class Teacher {

 

    private int id;

    private String name;

    private Set<Student> student=newHashSet<Student>();

   

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Set<Student>getStudent() {

       return student;

    }

    public void setStudent(Set<Student> student) {

       this.student = student;

    }

}

 

Student.java

public class Student {

 

    private int id;

    private String name;

    private Set<Teacher> teacher=newHashSet<Teacher>();

   

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Set<Teacher>getTeacher() {

       return teacher;

    }

    public void setTeacher(Set<Teacher> teacher) {

       this.teacher = teacher;

    }

}

2.   配置文件

Teacher.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="Teacher">

       <id name="id">

           <generator class="native"/>

       </id>

       <property name="name"/>

       <set name="student"table="teacher_student"

cascade="all" inverse="true">

<!--

cascade的属性有:

1.all:所有操作情况下都进行级联操作,即save-updatedelete

2.none:所有情况下均不进行级联操作。这是默认值。

3.save-update:执行save/update/saveOrUpdate时进行级联操作。

4.delete:在执行delete操作的时候进行级联操作。

5.all-delete-orphan:当一个对象节点在对象图中成为孤儿节点时,删除该节点。比如在一个一对多的关系中,student包含多个book,当在对象关系中删除一个book时,此book即成为孤儿节点。

      

inverse属性值true或者false,默认值false(即默认己方维护关联关系)

false:代表有己方来维护关系,true代表由对方来维护关联关系。

在一个关系中,只能有一方来维护关系,否则会出问题;同时也必须有一方维护关系,否则会出现双方互相推卸责任,谁也不管。

-->       

<key column="teacher_id"></key>

           <many-to-many class="Student"column="student_id">

</many-to-many>

       </set>

    </class>

</hibernate-mapping>

 

Student.hbm.xml

<hibernate-mapping package="com.domain">

 

    <class name="Student">

       <id name="id">

           <generator class="native"/>

       </id>

       <property name="name"/>

       <set name="teacher"table="teacher_student"

cascade="all" inverse="false">

           <key column="student_id"></key>

           <many-to-many class="Teacher"column="teacher_id">

</many-to-many>

       </set>

    </class>

</hibernate-mapping>

3.   hibernate.cfg.xml配置文件中添加对类配置文件的映射

4.   测试类

public void add(){

      

       Session s=HibernateUtil.getSession();

       Transaction tx=s.beginTransaction();

      

       Teacher teacher1=new Teacher();

       teacher1.setName("1号教师");

      

       Teacher teacher2=new Teacher();

       teacher1.setName("2号教师");

      

       Student student1=new Student();

       student1.setName("1号学生");

      

       Student student2=new Student();

       student2.setName("2号学生");

      

       Student student3=new Student();

       student2.setName("3号学生");

      

       teacher1.getStudent().add(student1);

       teacher1.getStudent().add(student2);

       teacher2.getStudent().add(student3);

      

       student1.getTeacher().add(teacher1);

       student2.getTeacher().add(teacher1);

       student3.getTeacher().add(teacher2);

      

       s.save(teacher1);

       s.save(teacher2);

//配置文件中,inverse="true"表示由对方来维护关联关系,谁维护就保存谁

       tx.commit();

       s.close();

    }

   

    public void query(int id){

      

       Session s=HibernateUtil.getSession();

       Transaction tx=s.beginTransaction();

      

       //查询主对象person

       //Person p=(Person) s.get(Person.class,id);

       //System.out.println(p.getCard().getName());

      

       //查询从对象id_card

       ID_Card card=(ID_Card)s.get(ID_Card.class,id);

       System.out.println(card.getPerson().getName());

      

       tx.commit();

       s.close();

      

    }

   

    public static void main(String[] args) {

       ManyToMany m=new ManyToMany();

       m.add();

       m.query(1);

    }

}

 

 

--------------------------component组件映像---------------------------

组件映像,也称为关联映射

一个javabean的属性不仅由数据组成,其中也包括了对象类型,也就是另一个javabean实体的对象

关联的属性是个复杂类型的持久化类,但不是实体,即:数据库中没有表与该属性对应,但该类的属性要之久保存的。所以就使用组件映像,但不是唯一的方法,也可以使用自定义类型的方式来处理,但是更复杂,更麻烦

但有的时候就必须要使用自定义类型,例如:类里边有两个属性,想要放入到数据库中表的三个列里边,这样的需求组件映像就不行了,只能使用自定义类型

1.   创建表

create table users(

    idint auto_increment primary key,

    namevarchar(20) not null,

    zipcodevarchar(20) not null,

    telvarchar(20) not null

)

2.   创建JavaBean

public class Users implements Serializable{

 

    private int id;

    private String name;

    private Address address; //此时表中的部分数据,进行了二次封装,是一个组件

   

    public Address getAddress() {

       return address;

    }

    public void setAddress(Address address) {

       this.address = address;

    }

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

}

Users类中还包含了一个Address对象

public class Address {

 

    private int id;

    private String zipcode;

    private String tel;

   

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getTel() {

       return tel;

    }

    public void setTel(String tel) {

       this.tel = tel;

    }

    public String getZipcode() {

       return zipcode;

    }

    public void setZipcode(String zipcode) {

       this.zipcode = zipcode;

    }

}

3.   创建配置文件Users.hbm.xml

<hibernate-mapping package="com.domain">

    <class name="Users"table="users">

       <id name="id"type="integer">

           <generator class="native"/>

       </id>

      

       <property name="name"type="string" not-null="true"/>

       <component name="address">

       <!--在配置文件中,视Users类中的Address为一个组件,name表示Users中所包含的对象名 -->

           <property name="zipcode"type="string"></property><!--设置Address中包含的属性-->

           <property name="tel"type="string"></property>

       </component>

    </class>

</hibernate-mapping>

4.   hibernate.cfg.xml配置文件中添加对类配置文件的映射

5.   测试类

public class ComponentTest {

 

    public static void main(String[] args) {

      

       Configuration cfg=new Configuration();

       cfg.configure();

       SessionFactory sf=cfg.buildSessionFactory();

       Session s=sf.openSession();

       Transaction tx=s.beginTransaction();

      

       Address a=new Address();

       a.setZipcode("300193");

       a.setTel("12345678901");

       Users u=new Users();

       u.setName("Shiki");

       u.setAddress(a); //Users对象中添加Address对象

       s.save(u);

       System.out.println(u.getId()+" "+u.getAddress().getTel());

      

       tx.commit();

       s.close();

    }

}

 

 

-----------------------Hibernate中使用的集合类型-----------------------

Hibernate中可以使用多种类型来保存对象实例,写法基本相同,只是配置文件的写法不同

1.   Set  不重复

<set name="emps" inverse="true">

    <key column="depart_id"/>

    <one-to-many class="Employee"/>

</set>

2.   List 带有顺序

<list name="emps">

    <key column="depart_id"/>

    <list-index column="order_col"/>

    <one-to-many class="Employee"/>

</list>

3.   Bag 类中仍然使用List,在配置文件中使用bag,表示不带有顺序的List

<bag name="emps">

    <key column="depart_id"/>

    <one-to-many class="Employee"/>

</bag>

4.   Map

<map name="emps">

    <key column="depart_id"/>

    <map-key type="string"column="name"/>

    <one-to-many class="Employee"/>

</map>

集合映像(set, list, array,bag, map)

这些集合类都是Hibernate实现的类和JAVA中的集合类不完全一样,set,list,map分别和JAVA中的Set,List,Map接口对应,bag映射成JAVAList;这些集合的使用和JAVA集合中对应的接口基本一致;在JAVA的实体类中集合只能定义成接口不能定义成具体类, 因为集合会在运行时被替换成Hibernate的实现。

集合的简单使用原则:大部分情况下用set,需要保证集合中的顺序用list,想用java.util.List又不需要保证顺序用bag

 

 

---------------------------关联关系的级联操作---------------------------

cascadeinverse(Employee – Department)

Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操作,常用的cascade:

    none,all,save-update ,delete,lock,refresh,evict,replicate,persist,

    merge,delete-orphan(one-to-many)

一般对many-to-one,many-to-many不设置级联,在<one-to-one><one-to-many>中设置级联。

inverse表“是否放弃维护关联关系”(Java里两个对象产生关联时,对数据库表的影响),在one-to-manymany-to-many的集合定义中使用,inverse=”true”表示该对象不维护关联关系;该属性的值一般在使用有序集合时设置成false(注意hibernate的缺省值是false)。

    one-to-many维护关联关系就是更新外键。many-to-many维护关联关系就是在中间表增减记录。

    : 配置成one-to-one的对象不维护关联关系

 

cascadeinverse

Cascadeinverse这两个属性都用于一对多或者多对多的关系中。而inverse特别是用于双向关联关系,在单向关联关系中我们并不需要。

cascade代表是否执行级联操作,inverse代表是否由己方维护关系。

 

cascade

cascade的属性有:

1·all:所有操作情况下都进行级联操作,即save-updatedelete

2·none:所有情况下均不进行级联操作。这是默认值。

3·save-update:执行save/update/saveOrUpdate时进行级联操作。

4·delete:在执行delete操作的时候进行级联操作。

5·all-delete-orphan:当一个对象节点在对象图中成为孤儿节点时,删除该节点。比如在一个一对多的关系中,student包含多个book,当在对象关系中删除一个book时,此book即成为孤儿节点。

 

Inverse:

inverse属性值true或者false,默认值false(即默认己方维护关联关系)

false:代表有己方来维护关系,true代表由对方来维护关联关系。

在一个关系中,只能有一方来维护关系,否则会出问题;同时也必须有一方维护关系,否则会出现双方互相推卸责任,谁也不管。

 

---------------------inverse属性的作用与原理分析------------------------

 

 

--------------------继承映射——整个继承树映射到一张表--------------------

Hibernate如何将继承结构应用到数据库里

还以员工这个类来做例子,

假设员工有SkillerSales两个子类,如何将他们实现到数据库里

虽然员工有技术或者销售两种类型的,但我们可以把这些都放在员工一张表中,那么如何来区分员工呢?我们可以给员工增加若干个字段,其中有一个类型字段,来区分员工是技术还是销售,然后在skillsell字段中表现出来技能是什么或者是销售额是多少

1.   创建SkillerSales类,并分别继承Employee

 

public class Skiller extends Employee {

 

    private String skill;

 

    public String getSkill() {

       return skill;

    }

 

    public void setSkill(String skill) {

       this.skill = skill;

    }

}

 

public class Sales extends Employee{

 

    private int sell;

 

    public int getSell() {

       return sell;

    }

 

    public void setSell(int sell) {

       this.sell = sell;

    }

}

2.    修改Employee.hbm.xml文件

 

 

 

--------------------------------缓存------------------------------

缓存的作用主要用来提高性能,可以简单的理解成一个Map;使用缓存涉及到三个操作:把数据放入缓存、从缓存中获取数据、删除缓存中的无效数据。

一级缓存,Session级共享。

save,update,saveOrUpdate,load,get,list,iterate,lock这些方法都会将对象放在一级缓存中,一级缓存不能控制缓存的数量,所以要注意大批量操作数据时可能造成内存溢出;可以用evict,clear方法清除缓存中的内容。

原创粉丝点击