hibernate进阶--一对多映射配置

                Hibernate作为一款优秀的ORM框架,广受大家喜爱,也被Java社区公认为持久层的首选。虽然jdbc为Java数据库操作带来了诸多便利,但是并没有统一SQL语句的写法,而且具体操作数据库的代码也足够复杂,且存在大量重复。所以有了ORM框架,让Java程序员可以从SQL语句中解放,Hibernate就是其中的翘楚。Hibernate将JDBC进一步的封装了,在SQL的可移植性方面表现优秀,并且使Hibernate程序代码足够简化。

       ORM(对象关系映射)是面向对象程序员在代码的编写过程中更舒服,不用处理繁杂的SQL,每个对象映射到数据库中的一条记录,一个实体类对应数据库里的一张表,所有这些都让面向对象程序员处理起来得心应手。Hibernate的开发环境搭建我已经在另一篇博客中介绍了,本文主要介绍一下Hibernate的基本配置与使用。

    关于session的获取、以及基本的增删改查操作:

@Before  
    public void init(){  
        config = new Configuration().configure();  
        serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();  
        sessionFactory = config.buildSessionFactory(serviceRegistry);  
        session = sessionFactory.openSession();  
        transaction = session.getTransaction();  
        transaction.begin();  
    }  
上面这段代码主要是session的获取以及开启事务,Hibernate的CRUD都是在事务中进行的,如果不开启事务所有的操作都不会主动提交到数据库的。关于CRUD操作,在session中有对应的API,不但功能强大而且使用方便,包括:save,update,delete,get,load等,其中注意get和load方法:get会直接获取数据库记录对象、load则是生成代理对象,只有该对象在被第一次使用的时候才向数据库发送SQL语句,真正的获得对象。当然还包括其他一些强大的API我们以后在学习。


配置---Hibernate的核心:

   Hibernate最主要的就是配置了,首先就是hibernate.cfg.xml文件,如以前环境搭建时讲到的一样,关于数据库的基本配置信息都要在该文件中配置好,包括对数据源的支持等以及实体类与数据表的映射关系。另一个重要的配置文件为XXX.hbm.xml文件,主要配置的是数据表与实体类之间的映射关系,如下面User类与USER表之间的对应:

<hibernate-mapping>  
    <class name="com.song.hibernate.User" table="USER">  
        <id name="id" type="int">  
            <column name="ID" />  
            <generator class="assigned" />  
        </id>  
        <property name="uname" type="java.lang.String">  
            <column name="UNAME" />  
        </property>  
        <property name="birth" type="java.util.Date">  
            <column name="BIRTH" />  
        </property>  
    </class>  
</hibernate-mapping> 

下文主要介绍xxx.hbm.xml文件的配置:

       首先,数据类型,Java的数据类型与数据库的数据类型并不是一一对应的,所以就有了hibernate的中间类型:

Java数据类型 Hibernate数据类型 标准SQL数据类型
(PS:对于不同的DB可能有所差异)
byte、java.lang.Byte byte TINYINT
short、java.lang.Short short SMALLINT
int、java.lang.Integer integer INGEGER
long、java.lang.Long long BIGINT
float、java.lang.Float float FLOAT
double、java.lang.Double double DOUBLE
java.math.BigDecimal big_decimal NUMERIC
char、java.lang.Character character CHAR(1)
boolean、java.lang.Boolean boolean BIT
java.lang.String string VARCHAR
boolean、java.lang.Boolean yes_no CHAR(1)('Y'或'N')
boolean、java.lang.Boolean true_false CHAR(1)('Y'或'N')
java.util.Date、java.sql.Date date DATE
java.util.Date、java.sql.Time time TIME
java.util.Date、java.sql.Timestamp timestamp TIMESTAMP
java.util.Calendar calendar TIMESTAMP
java.util.Calendar calendar_date DATE
byte[] binary VARBINARY、BLOB
java.lang.String text CLOB
java.io.Serializable serializable VARBINARY、BLOB
java.sql.Clob clob CLOB
java.sql.Blob blob BLOB
java.lang.Class class VARCHAR
java.util.Locale locale VARCHAR
java.util.TimeZone timezone VARCHAR
java.util.Currency currency VARCHAR
一般我们使用hibernate的中间类型,但是也可以使用Java类型。比如java.util.Date类型并不能详细表达该date类型是日期还是时间还是日期+时间的形式,而hibernate中间类型就有详细的区分:date表示日期,time表示时间,timestamp表示日期+时间类型。


配置主键的生成策略:

    在配置文件中<generator class="assigned" />标签代表主键的生成策略,最常用的是assigned和native:

      assigned:由程序控制、就是手动赋值

      native:根据数据库类别使用其原生的主键生成方式,MySQL是auto_increment;

还有几种生成策略,identity自增的方式、sequence适用于oracle的sequence方式、hilo使用hige/low算法生成主键、还有包括seqhilo、uuid.hex、guid、select等以后用到再说。


配置映射关系:

  1. 单向一对多映射:班级grade与学生student就是一对多的映射关系,通过班级可以查到属于该班级的所有学生,即一个班级对应多个学生,这就是单向的一对多,grade------>students
  2. 单向多对一映射:同样的通过每个学生可以查找到他的班级,这就是单向的多对一,即多个学生对应一个班级,students----->grade
  3. 双向的一对多映射:就是两者结合,通过一个班级可以查找到所有属于该班级的学生并且通过每个学生可以查找到他们所属的班级,几一个班级对应多个学生且多个学生对应一个班级

以grade和students为例来学习hibernate的一对多映射关系配置:

      首先是准备阶段,创建数据表grade 和 student:

create table grade(
    gid int,
    gname varchar(20) not null,
    gdesc varchar(40)
);
create table student(
    sid int,
    sname varchar(20) not null,
    sex varchar(2),
    gid int
);
alter table student add constraint fk_student-gid foregin key (gid) references grade (gid);
然后创建两个对应的实体类:

在单向一对多中:

public class Grade{
private int gid;
private String gname;
private String gdesc;
private Set<Student> students;
//对应的getter、setter方法 构造器、及其他测试需要的toString方法等

}

public class Student{
private int sid;
private String sname;
private String sex;
//对应的getter、setter方法 构造器、及其他测试需要的toString方法等

}

因为是单向的一对多关系,所以在Student类中不会含有grade的引用;

对应生成的hbm.xml文件如下:

<?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>
    <class name="com.song.entity.Grade" table="GRADE">
        <id name="gid" type="int">
            <column name="GID" />
            <generator class="assigned" />
        </id>
        <property name="gname" type="java.lang.String">
            <column name="GNAME" />
        </property>
        <property name="gdesc" type="java.lang.String">
            <column name="GDESC" />
        </property>
        <set name="students" table="STUDENT" >
            <key>
                <column name="GID" />
            </key>
            <one-to-many class="com.song.entity.Student" />
        </set>
    </class>
</hibernate-mapping>

Students.hbm.xml:
<?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>
    <class name="com.song.entity.Student" table="STUDENT">
        <id name="sid" type="int">
            <column name="SID" />
            <generator class="assigned" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="SNAME" />
        </property>
        <property name="sex" type="java.lang.String">
            <column name="SEX" />
        </property>
    </class>
</hibernate-mapping>


在单向多对一中:

与单向一对多相反,这次单方不用持有一方的集合引用;

public class Grade{
private int gid;
private String gname;
private String gdesc;

//对应的getter、setter方法 构造器、及其他测试需要的toString方法等

}

public class Student{
private int sid;
private String sname;
private String sex;
private Grade grade;
//对应的getter、setter方法 构造器、及其他测试需要的toString方法等

}

可以通过学生来查询到其所在的班级,对应的hbm.xml配置如下:
<?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>
    <class name="com.song.entity.Student" table="STUDENT">
        <id name="sid" type="int">
            <column name="SID" />
            <generator class="assigned" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="SNAME" />
        </property>
        <property name="sex" type="java.lang.String">
            <column name="SEX" />
        </property>
        <many-to-one name="grade" class="com.song.entity.Grade" >
            <column name="GID" />
        </many-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>
    <class name="com.song.entity.Grade" table="GRADE">
        <id name="gid" type="int">
            <column name="GID" />
            <generator class="assigned" />
        </id>
        <property name="gname" type="java.lang.String">
            <column name="GNAME" />
        </property>
        <property name="gdesc" type="java.lang.String">
            <column name="GDESC" />
        </property>
    </class>
</hibernate-mapping>


双向一对多:

要求两个实体类分别持有对方的引用如下:

public class Grade{
private int gid;
private String gname;
private String gdesc;
private Set<Student> students;
//对应的getter、setter方法 构造器、及其他测试需要的toString方法等

}

public class Student{
private int sid;
private String sname;
private String sex;
private Grade grade;
//对应的getter、setter方法 构造器、及其他测试需要的toString方法等

}

在hbm.xml文件中也是要两端同时配置单向一对多和单向多对一:

<hibernate-mapping>
    <class name="com.song.entity.Grade" table="GRADE">
        <id name="gid" type="int">
            <column name="GID" />
            <generator class="assigned" />
        </id>
        <property name="gname" type="java.lang.String">
            <column name="GNAME" />
        </property>
        <property name="gdesc" type="java.lang.String">
            <column name="GDESC" />
        </property>
        <set name="students" table="STUDENT" inverse="true" cascade="save-update">
            <key>
                <column name="GID" />
            </key>
            <one-to-many class="com.song.entity.Student" />
        </set>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.song.entity.Student" table="STUDENT">
        <id name="sid" type="int">
            <column name="SID" />
            <generator class="assigned" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="SNAME" />
        </property>
        <property name="sex" type="java.lang.String">
            <column name="SEX" />
        </property>
        <many-to-one name="grade" class="com.song.entity.Grade" cascade="all">
            <column name="GID" />
        </many-to-one>
    </class>
</hibernate-mapping>

其中设置了在“一”端inverse属性,默认为false这里设为true,用来优化,交给多段来维护对应关系。

还有cascade:代表级联操作,默认为none,就是不级联

                       save-update代表在save和update时级联、delete代表在删除时级联、all代表什么情况都级联。




猜你喜欢

转载自blog.csdn.net/weiguang111/article/details/50521917