对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术,本质上就是将数据从一种形式转换到另外一种形式。
面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系数据库中
Hibernate在实现ORM功能的时候主要用到的文件有:映射类(*.java)、映射文件(*.hbm.xml)和数据库配置文件(*.properties/*.cfg.xml),它们各自的作用如下。
映射类(*.java):它是描述数据库表的结构,表中的字段在类中被描述成属性,将来就可以实现把表中的记录映射成为该类的对象了。
映射文件(*.hbm.xml):它是指定数据库表和映射类之间的关系,包括映射类和数据库表的对应关系、表字段和类属性类型的对应关系以及表字段和类属性名称的对应关系等。
数据库配置文件(*.properties/*.cfg.xml):它是指定与数据库连接时需要的连接信息,比如连接哪种数据库、登录数据库的用户名、登录密码以及连接字符串等。当然还可以把映射类的地址映射信息放在这里。
两个对象之间一对的关系,例如:Person(人)-IdCard(身份证)实例
有两种策略可以实现一对一的关联映射:
*主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联。
单向一对一唯一外键关联例子连接
package cn.itcast.i_hbm_oneToOne;public class Person { private Integer id; private String name; private IdCard idCard; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public IdCard getIdCard() { return idCard; } public void setIdCard(IdCard idCard) { this.idCard = idCard; } @Override public String toString() { return "[Person??id=" + id + ", name=" + name + "]"; }}
package cn.itcast.i_hbm_oneToOne;public class IdCard { private Integer id; private String number; private Person person; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Override public String toString() { return "[IdCard??id=" + id + ", number=" + number + "]"; }}
<?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 package="cn.itcast.i_hbm_oneToOne"> <class name="Person" table="person"> <id name="id"> <generator class="native"></generator> </id> <property name="name"/> <!-- idCard属性,IdCard类型。 表达的是本类与IdCard的一对一。 采用基于外键的一对一映射方式,本方无外键方。 property-ref属性: 写的是对方映射中外键列对应的属性名。 --> <one-to-one name="idCard" class="IdCard" property-ref="person"/> </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 package="cn.itcast.i_hbm_oneToOne"> <class name="IdCard" table="idCard"> <id name="id"> <generator class="native"></generator> </id> <property name="number"/> <!-- person属性,Person类型。 表达的是本类与Person的一对一。 采用基于外键的一对一映射方式,本方有外键方。 --> <many-to-one name="person" class="Person" column="personId" unique="true"></many-to-one> </class> </hibernate-mapping>
package cn.itcast.i_hbm_oneToOne;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;import com.java1234.util.HibernateSessionFactory;public class App { private static SessionFactory sessionFactory =HibernateSessionFactory.getSessionFactory(); // 保存,有关联关系 @Test public void testSave() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // -------------------------------------------- // 新建对象 Person person = new Person(); person.setName("张三"); IdCard idCard = new IdCard(); idCard.setNumber("100000011X"); // 关联起来 // person.setIdCard(idCard); idCard.setPerson(person); // 保存 session.save(person); session.save(idCard); // -------------------------------------------- session.getTransaction().commit(); session.close(); } // 获取,可以获取到关联的对方 @Test public void testGet() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // -------------------------------------------- // 获取一方,并显示另一方信息 // Person person = (Person) session.get(Person.class, 1); // System.out.println(person); // System.out.println(person.getIdCard()); IdCard idCard = (IdCard) session.get(IdCard.class, 1); System.out.println(idCard); System.out.println(idCard.getPerson()); // -------------------------------------------- session.getTransaction().commit(); session.close(); } // 解除关联关系:一对一中,只能有外键方可以维护关联关系。 @Test public void testRemoveRelation() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // -------------------------------------------- // 从有外键方解除关系,可以。 // IdCard idCard = (IdCard) session.get(IdCard.class, 1); // idCard.setPerson(null); // 从无外键方解除关系,不可以。 Person person = (Person) session.get(Person.class, 1); person.setIdCard(null); // -------------------------------------------- session.getTransaction().commit(); session.close(); } // 删除对象,对关联对象的影响 @Test public void testDelete() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // -------------------------------------------- // a, 如果没有关联的对方:能删除。 // b, 如果有关联的对方且可以维护关联关系(有外键方),他就会先删除关联关系,再删除自己。 // c, 如果有关联的对方且不能维护关联关系(无外键方),所以会直接执行删除自己,就会有异常。 IdCard idCard = (IdCard) session.get(IdCard.class, 1); session.delete(idCard); // Person person = (Person) session.get(Person.class, 1); // session.delete(person); // -------------------------------------------- session.getTransaction().commit(); session.close(); }}
配置文件hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory> <!--数据库连接设置 --> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="connection.url"> jdbc:mysql://localhost:3306/mytest </property> <property name="connection.username">root</property> <property name="connection.password">root</property> <!-- 方言 --> <property name="dialect"> org.hibernate.dialect.MySQL5Dialect </property> <!-- 控制台显示SQL --> <property name="show_sql">true</property> <!-- 自动更新表结构 --> <property name="hbm2ddl.auto">update</property> <mapping resource="cn/itcast/i_hbm_oneToOne/IdCard.hbm.xml" /> <mapping resource="cn/itcast/i_hbm_oneToOne/Person.hbm.xml" /></session-factory></hibernate-configuration>
单向一对一主键关联例子连接
其余代码不变只需修改如下文件
<?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 package="cn.itcast.i_hbm_oneToOne2"> <class name="Person" table="person2"> <id name="id"> <generator class="native"></generator> </id> <property name="name"/> <!-- idCard属性,IdCard类型。 表达的是本类与IdCard的一对一。 采用基于主键的一对一映射方式,本方无外键方。 --> <one-to-one name="idCard" class="IdCard"></one-to-one> </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 package="cn.itcast.i_hbm_oneToOne2"> <class name="IdCard" table="idCard2"> <id name="id"> <!-- 当使用基于主键的一对一映射时, 有外键方的主键生成策略一定要是foreign。 参数property: 生成主键值时所根据的对象。 --> <generator class="foreign"> <param name="property">person</param> </generator> </id> <property name="number"/> <!-- person属性,Person类型。 表达的是本类与Person的一对一。 采用基于主键的一对一映射方式,本方有外键方。 --> <one-to-one name="person" class="Person" constrained="true"></one-to-one> </class> </hibernate-mapping>