由于在数据表之间可以通过外键进行关联,在使用Hibernate操作映射到存在关联关系的数据表的对象时,需要将对象的关联关系与数据表的外键关联进行映射。

  首先建立hibernate.cfg.xml和会话工厂类HibernateUtil,然后添加两个待操作的实体类和相应的映射文件。

HibernateUtil如下:

package com.zzh.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration; public class HibernateUtil {
private static SessionFactory sessionFactory;
private static Session session; static {
// 创建Configuration对象,读取hibernate.cfg.xml文件,完成初始化
Configuration config = new Configuration().configure();
StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder()
.applySettings(config.getProperties());
StandardServiceRegistry ssr=ssrb.build();
sessionFactory=config.buildSessionFactory(ssr);
} //获取SessionFactory
public static SessionFactory getSessionFactory(){
return sessionFactory;
} //获取Session
public static Session getSession(){
session=sessionFactory.openSession();
return session;
} //关闭Session
public static void closeSession(Session session){
if(session!=null){
session.close();
}
}
}

两个实体类班级Grade和学生Student

package com.zzh.entity;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set; public class Grade implements Serializable {
private int gid;
private String gname;
private String gdesc; public int getGid() {
return gid;
} public void setGid(int gid) {
this.gid = gid;
} public String getGname() {
return gname;
} public void setGname(String gname) {
this.gname = gname;
} public String getGdesc() {
return gdesc;
} public void setGdesc(String gdesc) {
this.gdesc = gdesc;
} public Grade() {
super();
} public Grade(int gid, String gname, String gdesc) {
super();
this.gid = gid;
this.gname = gname;
this.gdesc = gdesc;
} public Grade(String gname, String gdesc) {
super();
this.gname = gname;
this.gdesc = gdesc;
} }
package com.zzh.entity;

import java.io.Serializable;

public class Student implements Serializable {
private int sid;
private String sname;
private String sex;
//在多方定义一个一方的引用
private Grade grade; public Grade getGrade() {
return grade;
} public void setGrade(Grade grade) {
this.grade = grade;
} public int getSid() {
return sid;
} public void setSid(int sid) {
this.sid = sid;
} public String getSname() {
return sname;
} public void setSname(String sname) {
this.sname = sname;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public Student() {
super();
} public Student(String sname, String sex) {
super();
this.sname = sname;
this.sex = sex;
} }

可以看出我在Student类中使用Grade类声明了grade属性,并添加了getter和setter,以体现实体类Student对Grade的关联关系,在下面的映射表中只需要在“多”的一方配置。注意,Student类中添加的grade属性为Grade,它是一个持久化类Grade的对象属性,不是一个基本类型属性,因此不能用<property>元素来映射grade属性,又因为是多对一关联关系,要使用<many-to-one>元素。

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">
<!-- Generated 2016-8-31 11:19:40 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.zzh.entity.Grade" table="GRADE">
<id name="gid" type="int">
<column name="GID" />
<generator class="increment"/>
</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>

Student.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">
<!-- Generated 2016-8-31 11:19:40 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.zzh.entity.Student" table="STUDENT">
<id name="sid" type="int">
<column name="SID" />
<generator class="increment" />
</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.zzh.entity.Grade" fetch="join">
<column name="GRADE" />
</many-to-one>
</class>
</hibernate-mapping>

<many-to-one>元素中的name指定Student类中关联类的属性名,column指定数据表关联的外键。换句话说,实体类Student对Grade的多对一关联在本质上是通过数据表student中的外键GRADE与数据表grade关联实现的,但Hibernate将表之间的关联通过<many-to-one>元素进行了封装。

2.编写与数据库交互的UserDAO接口和其实现类UserDAOImpl,将数据的添加,查找,修改,删除等方法封装其中。

UserDAO:

package com.zzh.dao;

public interface UserDAO {
void save(Object obj);
Object findById(int id,Object obj);
void delete(Object obj);
void update(Object obj);
}

UserDAOImpl:

package com.zzh.dao;

import org.hibernate.Session;
import org.hibernate.Transaction; import com.zzh.util.*; public class UserDAOImpl implements UserDAO { @Override
public void save(Object obj) {
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
try {
session.save(obj);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
HibernateUtil.closeSession(session);
} } @Override
public Object findById(int id, Object obj) { Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
try {
obj = session.get(obj.getClass(), id);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
return obj;
} @Override
public void delete(Object obj) {
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
try {
session.delete(obj);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
} } @Override
public void update(Object obj) {
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
try {
session.update(obj);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
} } }

注意:我的这个DAO使用的是Object对象,很多书上都是针对多个的对象建立多个DAO,也就是拆分为StudentDAOImpl和GradeDAOImpl,这样里面的Object就变为了相应的Student或者Grade。

如果你要改写为我这样的通用DAO,尤其要注意里面的findById()方法,对于拆分写的DAO,这个方法很简单,只需要传入参数id然后Grade grade=(Grade) session.get(Grade.class, id);而我的方法因为是通用的,所有要传入id和对应的实体对象,obj = session.get(obj.getClass(), id),这里面运用了java的有关反射的知识,顺便拓展一下。

1.利用对象调用getClass()方法获取该对象的Class实例。比如 Students s = new Students();  Class c = s.getClass();2.使用Class的静态方法forName(),用类的名字获取一个Class实例;比如 Class c = Class.forName("Students");3.运用.class的方式获取Class实例,对基本数据类型的封装类,还可以采用.TYPE来获取对应的基本数据类型的Class实例;Class c = Students.class; 所以对于我的例子而言,就是利用了obj.getClass()等价于Object.class这个特性来修改这个方法,大家可以自己试试。

3.添加测试案例JUnit

  请注意看我上面给出的hbm.xml文件,主键生成机制是increment

                                                   

现在问题又来了!!!当我用工具通过实体类生成hbm.xml文件时,主键生成机制是

assigned表示对象标识符由应用程序产生,如果不指定<generator>节点,则默认使用该策略。此时数据表还没有建立,当我开始测试的时候,Hibernate根据cfg.xml中的数据库信息和相关映射信息建立表,问题来了,Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'PRIMARY'。 数据表grade中出现 “0 Java一班 Java软件开发一班 ”一条记录,数据表student中出现 “ 0 慕女神  女 0 ”一条记录,提示已经告诉我们主键重复,0主键已经存在,不能再进行添加了。assigned表示主键有程序代码负责,你要保证这个主键数据是唯一的。这时我在想,那我用identity生成策略会怎么样,identity表示对象标识符由底层数据库的自增主键生成机制产生。这样一搞 Caused by: java.sql.SQLException: Field 'SID' doesn't have a default value,马上反应过来自己没有在数据库设置AUTO_increment,需要去设置两个表的这个值。

这样一搞,就可以正常添加了。

当我设置好自动递增后,又想试试assigned,于是又改为了assigned,问题又来了Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 ;百度之后,有人这样解释:这个异常是由于主键设置为自增长,而在我们插入记录的时候设置了ID的值导致的。懵逼了,到现在我还在找怎样解决,如果你有答案请告诉我。

之后我选用了increment生成策略,这个策略不需要在数据库中设置自动递增,感觉应付这种小例子很方便,不过他的局限性在于如果有多个应用实例向同一张表中插入数据时,则会出现重复的主键。需谨慎使用。

4.总结

  这篇文章感觉挺凌乱的,一会是DAO修改一会又是反射,最后还自己搞了一堆BUG,自己还是需要慢慢积累知识才行,如果你觉得这篇文章有点用,请帮忙点个赞,谢谢观看。

  

Hibernate 之单向多对一映射及其衍生问题的更多相关文章

  1. hibernate笔记--单向多对一映射方法

    假设我们要建两张表,学生信息表(student)和年级信息表(grade),关系是这样的: 我们可以看出学生表和=年级表是多对一的关系,多个学生会隶属于一个班级,这种关系在hibernate中成为单边 ...

  2. Hibernate框架单向多对多关联映射关系

    建立单向多对多关联关系    Project.java (项目表)                private Integer proid;                private Strin ...

  3. hibernate(四) 双向多对多映射关系

    序言 莫名长了几颗痘,真TM疼,可能是现在运动太少了,天天对着电脑,决定了,今天下午花两小时去跑步了, 现在继上一章节的一对多的映射关系讲解后,今天来讲讲多对多的映射关系把,明白了一对多,多对多个人感 ...

  4. 【Hibernate步步为营】--多对多映射具体解释

    上篇文章具体讨论了一对多映射,在一对多映射中单向的关联映射会有非常多问题,所以不建议使用假设非要採用一对多的映射的话能够考虑使用双向关联来优化之间的关系,一对多的映射事实上质上是在一的一端使用< ...

  5. Hibernate框架单向多对一关联映射关系

    建立多对一的单向关联关系    Emp.java            private Integer empNo //员工编号            private String empName / ...

  6. Hibernate学习之单向多对一映射

    © 版权声明:本文为博主原创文章,转载请注明出处 说明:该实例是通过映射文件和注解两种方式实现的.可根据自己的需要选择合适的方式 实例: 1.项目结构 2.pom.xml <project xm ...

  7. hibernate单向多对一映射

    n21: 1.new 两个实体类,一个代表"多"的一端,一个代表"一"的一端. Customer类: public class Customer { priva ...

  8. Hibernate中的多对多映射

    1.需求 项目与开发员工 一个项目,有多个开发人员 一个开发人员,参与多个项目 [多对多] 2.实体bean设计 Project: public class Project { private int ...

  9. --------------Hibernate学习(四) 多对一映射 和 一对多映射

    现实中有很多场景需要用到多对一或者一对多,比如上面这两个类图所展现出来的,一般情况下,一个部门会有多名员工,一名员工只在一个部门任职. 多对一关联映射 在上面的场景中,对于Employee来说,它跟D ...

随机推荐

  1. ROS使用国内的DDNS服务

    未测试.转载余松老师的作品 虽然RouterOS 加入了cloud功能,但最近在配置RB2011的时候发现不好使,更新域名后无法正确解析到我的IP地址,虽然在cloud的public address中 ...

  2. 使用Java配置SpringMVC

    在此之前,一直使用的是XML的方式配置SpringMVC,现在为了适应Servlert3.0以及JavaConfig的Spring配置方式,在这里记录一下使用Java代码配置SpringMVC.首先, ...

  3. SpringBoot入门(2)

    一.上一篇 上一篇最后说到,可以把启动类放到非上级目录“@Componentscan这个注解后面指定扫描的包名(value=“com.zbb”)”,这里的value是一个数组,我们可以写多个目录,进行 ...

  4. Nginx代理配置文件

    #user nginx; worker_processes 5; #error_log /var/log/nginx/error.log warn; #pid /var/run/nginx.pid; ...

  5. zookeeper分布式锁和服务优化配置

    转自:https://www.jianshu.com/p/02eeaee4357f?utm_campaign=maleskine&utm_content=note&utm_medium ...

  6. nodejs-supervisor

    小技巧——使用 supervisor 如果你有 PHP 开发经验,会习惯在修改 PHP 脚本后直接刷新浏览器以观察结果,而你在开发 Node.js 实现的 HTTP 应用时会发现,无论你修改了代码的哪 ...

  7. ajax传参里含有特殊字符的坑

    问题场景:今天在测试自己手上的页面功能时,发现一个小bug,在用ajax向后台发数据时,只要参数中出现一些特殊字符,控制台会报错http 400的问题,其实就是特殊字符服务器不能解析.好了,问题是找到 ...

  8. 学习 java 编程语言两个月来的感受

    今天是我接触java编程的第81天, 现在的感受是觉得非常快乐, 每次看着自己的写的代码能成功运行的时候那种喜悦是无法言表的, 最初接触电脑还是在小学, 后来到了初中觉得电脑无非就是点点鼠标, 按按键 ...

  9. 01b-1: 性能测度

  10. Linux文件权限查看及修改命令chmod,chown

    查看权限 Linux文件访问权限分为可读,可写和可执行三种. 可用ls -l命令查看,例: ls -l或者 ll 显示为 -r--r--r--. 1 root root 21 Jan 5 23:02 ...