hibernate入门四(表关系映射配置)

在这里遇到了两个坑,
第一个坑是Could not determine type for: java.util.List, at table 项目启动报这种错误的解决方案(JPA),这样报错是因为我的注解配置一部分写在bean的属性上,一部分写在了bean的方法上。
第二个坑是配置的坑
在配置一对多的时候,
(维护端,无外键方,一方) 设置懒加载,设置mappedBy=”“,后面的值是多的一方的主键。,当然也可以不设置,这样没有设置外键,表的自由度就高很多了。同时也可以设置懒加载。
(被维护端,有外键方,多方) 指定外键列 @JoinColumn(name = “order_id”) ,可设置级联刷新(@ManyToOne(optional=参数))

实例一:两个一对多的关系
关系图如下:
关系图
不多逼逼,直接上代码:
课程类 Class

package model;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import jdk.nashorn.internal.ir.annotations.Ignore;
@Entity
@Table(name="class")
public class Class {
    @Id
    @GeneratedValue(generator="native")
    @GenericGenerator(name="native",strategy="native")
    private long id;
    @OneToMany //(mappedBy="id")  **//一门课对应多名学生,了mappedBy参数,相当于建立外键,class里面存在这个值时,才能对Student操作成功,当先保存一个不存在的class的值时会报错org.hibernate.AssertionFailure: null id in model.Student entry (don't flush the Session after an exception occurs),即模型输入中的空ID(在异常发生后不刷新会话)**
    private Set<Student> s;
        @OneToMany//(mappedBy="id") //一门课对应多名老师
    private Set<Teacher> t;
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
        public Set<Student> getS() {
        return s;
    }
    public void setS(Set<Student> s) {
        this.s = s;
    }
    public Set<Teacher> getT() {
        return t;
    }
    public void setT(Set<Teacher> t) {
        this.t = t;
    }   
}

学生类 Student

package model;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="student")
public class Student {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String name;
    private Date birthDay;
    @ManyToOne  //多名学生对应一门课
    @JoinColumn(name="classid") //这里的@JoinColumn也可以不要,自动默认值为 被控方实例名_主控方主键  例如这里注释掉以后就是c_id,c是Class的实例名,id是Class表的主键
    private Class c;

    public Class getC() {
        return c;
    }
    public void setC(Class c) {
        this.c = c;
    }
    public Date getBirthDay() {
        return birthDay;
    }
    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", birthDay=" + birthDay + "]";
    }
}

老师类 Teacher

package model;

import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name = "teacher")
public class Teacher {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;

    @ManyToOne //多名老师对应一门课
    @JoinColumn(name="classid")
    private Class c;
    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 Class getC() {
        return c;
    }
    public void setC(Class c) {
        this.c = c;
    }
}

HibernateUtil类的源码附上

package util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateUtil {
    private static final SessionFactory sessionFactory=buildSessionFactory();
    private static SessionFactory buildSessionFactory() {
        Configuration configuration=new Configuration().configure(); // 实例化配置文件
        ServiceRegistry serviceRegistry=new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); // 实例化服务登记
        return configuration.buildSessionFactory(serviceRegistry); // 获取Session工厂
    }
    public static SessionFactory getSessionFactory(){
        return sessionFactory;
    }
}

配置文件hibernater.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/myhibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>


        <!-- 方言 -->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

        <!-- 在控制台中输出 sql -->
        <property name="show_sql">true</property>
        <!-- 格式化控制台中的 sql -->
        <property name="format_sql">true</property>
        <!-- 自动更新表结构 -->
        <!-- 
            hbm2ddl.auto的作用为:自动创建/更新/验证数据库表结构 
            有以下值:
                  create:      表示启动的时候先drop,再create
                  create-drop: 也表示创建,只不过再系统关闭前执行一下drop
                  update:      这个操作启动的时候会去检查schema是否一致,如果不一致会做scheme更新
                  validate:    启动时验证现有schema与你配置的hibernate是否一致,如果不一致就抛出异常,并不做更新
            -->
        <property name="hbm2ddl.auto">update</property>
        <!-- 映射 -->
        <mapping class="model.Class"/>
        <mapping class="model.Student"/>
        <mapping class="model.Teacher"/>
    </session-factory>

</hibernate-configuration>

测试类 TestMapping.java

package service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.Test;

import model.Class;
import model.Student;
import model.Teacher;
import util.HibernateUtil;
public class TestMapping {

    @Test
    public void test1(){
        SessionFactory sessionFactory= HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();//开启事物

        session.getTransaction().commit(); // 提交事务
        session.close(); // 关闭session
        sessionFactory.close(); // 关闭session工厂
    }


    @Test
    public  void test() {
        SessionFactory sessionFactory= HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();//开启事物

        Class c = new Class();
        Student s = new Student();
        Teacher t = new Teacher();
        t.setName("王老师");
        s.setName("张三");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date;
        try {
            date = sdf.parse("1996-3-2");
            s.setBirthDay(date);
            c.setName("计算机基础");
            Set<Student> set = new HashSet<Student>();
            Set<Teacher> set2 = new HashSet<Teacher>();
            set.add(s);
            t.setC(c);
            c.setS(set);
            c.setT(set2);
            s.setC(c);
            session.save(s);
            session.save(c);
            session.save(t);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{

            session.getTransaction().commit(); // 提交事务
            session.close(); // 关闭session
            sessionFactory.close(); // 关闭session工厂
        }
    }
}

使用Junit执行成功够就可以生成3张表的表信息。并且可以分别插入一条信息,因为这里没有使用级联插入,所以我们保存的时候都需要手动去调用Save;

一对多映射配置总结:
1.先写实体类
2.设置好单表的映射
3.按照逻辑约建立联系,建立联系的时候只需在多的一段增加@ManyToOne即可
4.编写hibernate.cfg.xml,引入实体类

实例二:多对多
看了上面的架构设计图很明显我的设计结构是不对的,教师和课程之间的关系不会是多对一的。而应该是多对多的关系。
一门课程有多个教师教授,一名教师也可以教授多门课程。(教师 n : m 课程)
一门课程有多名童鞋学习,一名童鞋也可以学习多门课程。(学生 n : m 课程)
坑:Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: model
这个报错多半是你的多对多中的多端还是一个非集合属性。

注意的是:
在配置多对多映射的时候,我们需要指定生成的表的名字,因为在
配置多对多的时候,存在一个manyToMany,就会建一张表。但是为了不重复生成表,我们让我们的表的名字相同,这时候hibernate会报一个error,但是不至于是异常。发现的原因是每次都重新生成表,然后看我们的sql语句,会发现这一点。

然后我们开始看我们新设计的表关系:
表结构

实体类代码:
课程类Class

package model;

import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name="class")
public class Class {
    @Id
    @GeneratedValue(generator="native")
    @GenericGenerator(name="native",strategy="native")
    private long id;
    private String name;
    @ManyToMany(mappedBy="c")//这里的c是指Student里面的set<Class> c,设置了Student与Class的维护方
    private Set<Student> s;
    @ManyToMany(mappedBy="c")//这里的c是指teacher里面的Set<Class> c,设置了teacher与 class的维护方
    private Set<Teacher> t;
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public Set<Student> getS() {
        return s;
    }
    public void setS(Set<Student> s) {
        this.s = s;
    }
    public Set<Teacher> getT() {
        return t;
    }
    public void setT(Set<Teacher> t) {
        this.t = t;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

学生类Student

package model;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="student")
public class Student {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String name;
    private Date birthDay;

    @ManyToMany//多名学生对应多门课
    @JoinTable(
            name="sc",
            joinColumns = @JoinColumn(name = "sid"),
            inverseJoinColumns = @JoinColumn(name = "cid")
            )
    private Set<Class> c;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getBirthDay() {
        return birthDay;
    }
    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }
    public Set<Class> getC() {
        return c;
    }
    public void setC(Set<Class> c) {
        this.c = c;
    }
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", birthDay=" + birthDay + "]";
    }
}

教师类Teacher

package model;

import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name = "teacher")
public class Teacher {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    @ManyToMany //多名老师对应多门课
    @JoinTable(
            name="tc",
            joinColumns = @JoinColumn(name = "tid"), //这里是把Teacher的主键在关系表的字段中的值,有参数为指定值,不指定则默认 当前类名+另一个类的主键属性名
            inverseJoinColumns = @JoinColumn(name = "cid") //这里是把Class的主键在关系表的字段中的值,有参数为指定值,不指定则默认 当前类实例名+另一个类的主键属性名
            )
    private Set<Class> c ;
    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 Set<Class> getC() {
        return c;
    }

    public void setC(Set<Class> c) {
        this.c = c;
    }
    @Override
    public String toString() {
        return "Teacher [id=" + id + ", name=" + name + ", c=" + c + "]";
    }
}

配置文件 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/myhibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="hbm2ddl.auto">create</property>
        <mapping class="model.Class"/>
        <mapping class="model.Student"/>
        <mapping class="model.Teacher"/>
    </session-factory>
</hibernate-configuration>

测试类

package service;

import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.Test;
import model.Class;
import model.Student;
import model.Teacher;
import util.HibernateUtil;

public class TestMapping2 {
    @Test
    public void  test(){
        SessionFactory sessionFactory= HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();//开启事物
        session.getTransaction().commit(); // 提交事务
        session.close(); // 关闭session
        sessionFactory.close(); // 关闭session工厂
    }

    @Test
    public void test2(){

        SessionFactory sessionFactory= HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();//开启事物

        Student s1 = new Student();
        Class c1 = new Class();
        Teacher t1 = new Teacher();
        s1.setName("张三");
        s1.setBirthDay(new Date());
        c1.setName("计算机基础");
        t1.setName("王老师");
        Set<Student> slist = new HashSet<Student>();
        Set<Teacher> tlist = new HashSet<Teacher>();
        Set<Class> clist = new HashSet<Class>();
        slist.add(s1);
        tlist.add(t1);
        clist.add(c1);
        c1.setS(slist);
        c1.setT(tlist);
        s1.setC(clist);
        t1.setC(clist);

        session.save(s1);
        session.save(t1);
        session.save(c1);

        session.getTransaction().commit(); // 提交事务
        session.close(); // 关闭session
        sessionFactory.close(); // 关闭session工厂
    }

    @Test
    public void test3(){
        SessionFactory sessionFactory= HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();//开启事物
        session.getTransaction().commit(); // 提交事务

        Student s1 = (Student) session.get(Student.class, Long.valueOf(1));
        Set<Class> c1 = s1.getC();
        Iterator<Class> iter = c1.iterator();
        while(iter.hasNext()){
            Class c = iter.next();
            System.out.println(c.getName());
        }
        session.close(); // 关闭session
        sessionFactory.close(); // 关闭session工厂
    }

}

总结:hibernate多对多配置
1.首先写实体类
2.配置好单表
3.配置好逻辑键,在维护的一方配置@manyToMany(mappedBy=”“),值为维护方在关系中的值。
4.配置hibernate.cfg.cml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值