JPA学习(基于hibernate)


参考博客:https://blog.csdn.net/baidu_37107022/article/details/76572195

常用注解:

https://blog.csdn.net/eastlift/article/details/2463243

https://www.cnblogs.com/a8457013/p/7753575.html

https://blog.csdn.net/u014421556/article/details/52040263

----------------------

所需jar

persistence.xml(注意文件的位置一定要在类路径下META-INF文件夹下)

<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<!-- 事务类型使用本地事务 -->      
<persistence-unit name="simple" transaction-type="RESOURCE_LOCAL">  
      
  <properties>    
   <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
   <property name="hibernate.hbm2ddl.auto" value="update"/>
    
   <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />    
   <property name="hibernate.connection.username" value="root" />    
   <property name="hibernate.connection.password" value="jay571018"/>
   <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3308/jpatest?useUnicode=true&amp;characterEncoding=UTF-8" />    
     <!-- 
   <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />  
   <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3308/jpatest?useUnicode=true&amp;characterEncoding=UTF-8" />  
   <property name="javax.persistence.jdbc.user" value="root" />  
   <property name="javax.persistence.jdbc.password" value="jay571018"></property> 
      -->
  </properties>    
 </persistence-unit>    
</persistence>      
    
    
      
View Code

---------------------------------------

实体类:Person

package org.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;



@Entity
//@Table(name="xxx")  创建的表名称为xxx  如果不写 默认为类名称首字母小写
public class Person {
    private Integer id;
    private String name;
    private Date birthday;
    //性别
    private Gender gender=Gender.Man;//默认值为Man

    public Person() {}

    public Person(String name) {
        super();
        this.id = id;
        this.name = name;
    }
    
    
    
    public Person(String name, Date birthday) {
        super();
        
        this.name = name;
        this.birthday = birthday;
    }

    //可省略  默认为自动生成策略
    //数据库中的主键字段名称为id  主键增长类型为自动选择
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    //数据库中的字段personame和该实体类中的name属性进行映射  不为空  长度为10 
    @Column(length=10,name="personname",nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //TemporalType.DATE:数据格式为2018-04-04  数据库字段类型为date
    //TemporalType.TIMESTAMP:数据格式为2018-04-03 20:56:53   数据库字段类型为datetime
    @Temporal(TemporalType.TIMESTAMP)
    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    
    //EnumType.STRING保存进数据库时 是字符串的形式 Man或者Momen
    //EnumType.ORDINAL保存进数据库时 是以索引值的形式  0或者1
    @Enumerated(EnumType.STRING) @Column(nullable=false,length=5)
    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }
    

}
View Code

实体类:Gender

package org.model;
//创建枚举  性别
public enum Gender {
    Man,Women
}
View Code

建表和插入测试:

    //建表测试
    @Test
    public void createtable() {
        //该方法中的参数就是配置文件中  持久化单元的名称
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        factory.close();
    }
    
    //插入测试
    @Test
    public void save() {
        //该方法中的参数就是配置文件中  持久化单元的名称
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//开启事务
        em.persist(new Person("张三",new Date()));//持久化  即保存一个对象到数据库中
        em.getTransaction().commit();//提交事务
        em.close();
        factory.close();
    }
View Code

数据库表结构以及数据记录

--------------------------------

大文本以及延迟加载等注解的使用

    //大文本类型   例如个人信息说明
    private String info;
    //大文本类型  文件
    private Byte[] file;
    //图片路径  //需求:该字段不作为持久化字段  使用@Transient
    private String imgpath;

    //大文本类型 如果没有特殊的表明 那么默认255长度 不能满足需求 
    //使用该注解的话String类型映射到数据库的类型为:   Byte类型映射到数据库中的类型为:
    @Lob
    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
    //该字段内容在执行查询的时候  按需加载
    @Lob @Basic(fetch=FetchType.LAZY)
    public Byte[] getFile() {
        return file;
    }

    public void setFile(Byte[] file) {
        this.file = file;
    }
    @Transient
    public String getImgpath() {
        return imgpath;
    }
    
    public void setImgpath(String imgpath) {
        this.imgpath = imgpath;
    }
View Code

------------------------------------------

查询测试

为了方便观察,我们让查询的sql语句在控制台中打印,在persistence.xml配置如下内容:

 <!-- 配置控制台打印sql -->
   <property name="hibernate.show_sql" value="true"/>
   <!-- sql语句格式化配置 -->
   <property name="hibernate.format_sql" value="true"/>

测试1:

//查询测试1
    @Test
    public void getPerson1() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        System.out.println("---------------0");
        Person p = em.find(Person.class,1);//相当于hibernate中的get方法
        System.out.println("---------------1");
        em.close();
        System.out.println("---------------2");
        System.out.println(p.getName());
    }

测试2:

//查询测试2
    @Test
    public void getPerson2() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();    
        //相当于hibernate中的load方法
        System.out.println("---------------0");
        Person p = em.getReference(Person.class,1);//该方法和find方法的不同再于:第一次访问对象中的属性时才会发生数据的装载行为
        System.out.println("---------------1");
        System.out.println(p.getName());
        System.out.println("---------------2");
        //但是必须保证EntityManager没有关闭
        em.close();
        factory.close();
    }

使用该方法时,如果是第一次加载对象属性,那么EntityManager不能关闭 否则异常

    //查询测试2
    @Test
    public void getPerson2() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();    
        //相当于hibernate中的load方法
        System.out.println("---------------0");
        Person p = em.getReference(Person.class,1);//该方法和find方法的不同再于:第一次访问对象中的属性时才会发生数据的装载行为
        System.out.println("---------------1");
        //System.out.println(p.getName());
        //System.out.println("---------------2");
        //但是必须保证EntityManager没有关闭
        em.close();
        factory.close();
        //如果是第一次加载属性这里将报错:nosession异常
        System.out.println(p.getName());
    }

这两个方法如果在执行查询的时候,数据库中没有查询的对象时 产生的结果也不同 前者不会报异常,而后者会报

//异常测试  正常执行  输出null
        Person p = em.find(Person.class,3);
        System.out.println(p);
        em.close();
        factory.close();
View Code

正常执行,输出null(不是打印地址,这里需要注意,如果没有close语句的时候,则会打印对象地址,这个地方我也没有搞明白)

    //异常测试   出现异常  实体类找不到  而且出现异常的时机在输出p的时候产生  而不是在执行查询的时候产生
        Person p = em.getReference(Person.class,3);//
        System.out.println(p);//在执行该语句的时候  产生异常  而不是在查询的时候
        em.close();
        factory.close();
View Code

-----------------------------

更新测试

    //更新测试
    @Test
    public void updatePerson() {
        //该方法中的参数就是配置文件中  持久化单元的名称
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//开启事务
        Person p = em.find(Person.class,1);//此时处于托管态
        p.setName("xx3");
        em.getTransaction().commit();//提交事务  此时会执行批处理程序 把数据更新到数据库  所以该语句很重要  不能省略
        //em.close();
        //factory.close();
    }
View Code

介绍两个方法

第一个方法:

    //更新测试2
    @Test
    public void updatePerson2() {
        //该方法中的参数就是配置文件中  持久化单元的名称
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//开启事务
        Person p = em.find(Person.class,1);//此时处于托管态
        em.clear();//把实体管理器中的所有对象变成游离状态  然后此时更新就无法完成了
        p.setName("xx4");
        em.getTransaction().commit();//提交事务
    }

控制台只有查询语句而没有更新语句

第二个方法:

    //更新测试2
    @Test
    public void updatePerson2() {
        //该方法中的参数就是配置文件中  持久化单元的名称
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//开启事务
        Person p = em.find(Person.class,1);//此时处于托管态
        em.clear();//把实体管理器中的所有对象变成游离状态  然后此时更新就无法完成了
        p.setName("xx5");
        em.merge(p);//用于把游离状态的更新同步回数据库
        em.getTransaction().commit();//提交事务
    }

控制台打印:

Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.birthday as birthday2_0_0_,
        person0_.file as file3_0_0_,
        person0_.gender as gender4_0_0_,
        person0_.info as info5_0_0_,
        person0_.personname as personna6_0_0_ 
    from
        Person person0_ 
    where
        person0_.id=?
Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.birthday as birthday2_0_0_,
        person0_.file as file3_0_0_,
        person0_.gender as gender4_0_0_,
        person0_.info as info5_0_0_,
        person0_.personname as personna6_0_0_ 
    from
        Person person0_ 
    where
        person0_.id=?
Hibernate: 
    update
        Person 
    set
        birthday=?,
        file=?,
        gender=?,
        info=?,
        personname=? 
    where
        id=?
View Code

可以完成更新操作

----------------------------------------------------

删除测试

    //删除
    @Test
    public void deletePerson() {
        //该方法中的参数就是配置文件中  持久化单元的名称
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//开启事务
        Person p = em.find(Person.class,1);//此时处于托管态
        em.remove(p);
        em.getTransaction().commit();//提交事务
    }
View Code

完成删除

控制台打印:

Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.birthday as birthday2_0_0_,
        person0_.file as file3_0_0_,
        person0_.gender as gender4_0_0_,
        person0_.info as info5_0_0_,
        person0_.personname as personna6_0_0_ 
    from
        Person person0_ 
    where
        person0_.id=?
Hibernate: 
    delete 
    from
        Person 
    where
        id=?
View Code

---------------------------------------------

JPQL语句

--------------------------

HQL:https://www.imooc.com/article/15791

JQPL:https://blog.csdn.net/czp11210/article/details/50799489

查询测试:

EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        Query createQuery = em.createQuery("select a from Person a where a.id=:id");
        createQuery.setParameter("id",1);
        
        List<Person> resultList =createQuery.getResultList();//这种返回结果可以允许查询的实体不存在
        for(Person p:resultList) {
            System.out.println(p.getName());
        }
View Code

即使查询不到也没有关系 ,而下面的这种结果返回情况就不行了

Object singleResult = createQuery.getSingleResult();

如果查询的实体不存在 那么就如下:

--------------------------------

删除测试:

    //删除
    @Test
    public void delete() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        Query createQuery = em.createQuery("delete from Person where id=?1");
        createQuery.setParameter(1,2);
        createQuery.executeUpdate();
        em.getTransaction().commit();
    }
View Code

删除的对象不存在也没有关系

----------------------------------

更新:

//更新
    @Test
    public void update() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        //命名参数
        Query createQuery = em.createQuery("update Person set name=:name where id=:id");
        createQuery.setParameter("name","xx3");
        createQuery.setParameter("id",3);
        createQuery.executeUpdate();
        
        //第二条更新语句  使用位置参数
        createQuery = em.createQuery("update Person set name=?100 where id=?250");
        createQuery.setParameter(100, "xx4");
        createQuery.setParameter(250,4);
        createQuery.executeUpdate();
        
        em.getTransaction().commit();//提交事务  执行了两次更新
    }
View Code

-------------------------------------

命名查询

实体类:

测试代码:

//命名查询  在实体上边直接写JPQL语句
    @Test
    public void update2() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        Query createNamedQuery = em.createNamedQuery("updateSiggle");
        createNamedQuery.setParameter("name","fffff");
        createNamedQuery.setParameter(1,4);
        createNamedQuery.executeUpdate();
        em.getTransaction().commit();//提交事务  执行了两次更新
    }
    @Test
    public void execute() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        //执行查询
        Query createNamedQuery = em.createNamedQuery("queryPersonById");
        createNamedQuery.setParameter("id",4);
        List<Person> resultList = createNamedQuery.getResultList();
        for(Person p:resultList) {
            System.out.println(p.getName());
        }
        //执行更新
        Query createNamedQuery2 = em.createNamedQuery("updatePersonById");
        createNamedQuery2.setParameter("name","hhhh");
        createNamedQuery2.setParameter("id",4);
        createNamedQuery2.executeUpdate();
        em.getTransaction().commit();//提交事务  执行了两次更新
    }
View Code

----------------------------

一对多

实体代码

order

package org.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="orders")//因为在mysql中有关键字order  所以这里指定建立的表名称
public class Order{
    private String orderid;
    private Float amount=0f;
    //创建多方属性
    private Set<OrderItem> items=new HashSet<OrderItem>();
    //fetch加载策略:懒加载  在一方配置时默认为此方式  可不写
    //出现mappedBy时  表示该实体为被维护方  里边的属性名称表示:由OrderItem这个实体中的order属性来维护该关系
    @OneToMany(cascade= {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH,CascadeType.REMOVE}
    ,fetch=FetchType.LAZY,mappedBy="order")
    public Set<OrderItem> getItems() {
        return items;
    }
    public void setItems(Set<OrderItem> items) {
        this.items = items;
    }
    
    @Id @Column(length=12)
    public String getOrderid() {
        return orderid;
    }
    public void setOrderid(String orderid) {
        this.orderid = orderid;
    }
    @Column(nullable=false)
    public Float getAmount() {
        return amount;
    }
    public void setAmount(Float amount) {
        this.amount = amount;
    }
    //相互建立关联的过程
    public void addOrderItem(OrderItem orderItem) {
        orderItem.setOrder(this);
        this.items.add(orderItem);
        
    }

    

}
View Code

orderitem

package org.model;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import org.hibernate.boot.model.source.spi.CascadeStyleSource;

//订单项实体
@Entity
public class OrderItem {
    private Integer id;
    private String productName;
    private Float productPrice=0f;
    //创建一方属性
    private Order order;
    //级联方式:选择级联更新  级联刷新  级联保存不需要:一般都是在保存订单的时候去保存订单项
    //使用多对一注解的时候  默认加载方式为立即加载
    //optional:表示该外键字段是否可以为空   true 反映在数据库中表示该字段允许为空    false表示该字段 不可以为空 必须存在
    //JoinColumn指定生成的外键字段的名称
    @ManyToOne(cascade= {CascadeType.MERGE,CascadeType.REFRESH},optional=false)
    @JoinColumn(name="order_id")
    public Order getOrder() {
        return order;
    }
    public void setOrder(Order order) {
        this.order = order;
    }
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(length=20,nullable=false)
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    @Column(nullable=false)
    public Float getProductPrice() {
        return productPrice;
    }
    public void setProductPrice(Float productPrice) {
        this.productPrice = productPrice;
    }
    


}
View Code

测试类:

@Test
    public void save() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        //创建订单对象
        Order order=new Order();
        order.setOrderid("123");
        order.setAmount(123.3f);
        //创建多个订单项对象
        OrderItem orderItem1=new OrderItem();
        orderItem1.setProductName("A商品");
        orderItem1.setProductPrice(33.5f);
        OrderItem orderItem2=new OrderItem();
        orderItem2.setProductName("B商品");
        orderItem2.setProductPrice(66f);
        //需要相互建立关联   这个代码写在order实体中
        /*
        HashSet<OrderItem> hashSet=new HashSet<OrderItem>();
        hashSet.add(orderItem1);
        hashSet.add(orderItem2);
        order.setItems(hashSet);
        orderItem1.setOrder(order);
        orderItem2.setOrder(order);
        */
        order.addOrderItem(orderItem1);
        order.addOrderItem(orderItem2);
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();//必须开启事务  否则无法保存
        entityManager.persist(order);
        //entityManager.merge(order);如果表中order记录已经存在  而订单项中的记录不存在  即使现在已经相互关联了
        //但是调用persist方法的时候  订单项的数据并不会更新到数据库  因为只有调用merge时级联更新才会起作用
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

----------------------------

一对一

实体类代码

person

package org.OneToOne;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

@Entity
public class Person {
    private Integer pid;
    private String pname;
    //规定该实体作为外键的维护端
    private Card card;
    @Id @GeneratedValue
    public Integer getPid() {
        return pid;
    }
    public void setPid(Integer pid) {
        this.pid = pid;
    }
    @Column(length=4,nullable=false)
    public String getPname() {
        return pname;
    }
    public void setPname(String pname) {
        this.pname = pname;
    }
    //外键不能为空  外键名称card_id
    @OneToOne(cascade={CascadeType.ALL},optional=false)
    @JoinColumn(name="card_id")
    public Card getCard() {
        return card;
    }
    public void setCard(Card card) {
        this.card = card;
    }
    
}
View Code

card

package org.OneToOne;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Card {
    private Integer cid;
    private String code;
    private Person person;
    @Id @GeneratedValue
    public Integer getCid() {
        return cid;
    }
    public void setCid(Integer cid) {
        this.cid = cid;
    }
    @Column(length=18,nullable=false)
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    //mappedBy指定关系的维护端为person  card为被维护端 属性值表示 由Person这个实体中的card属性来维护该关系
    //该实体是被维护端  主键在维护端person中  所以person表是参考该表中的主键  所以这个地方不用配置optional=false属性  也最好不要配置
    @OneToOne(cascade= {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH},mappedBy="card")
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
    

}
View Code

测试:

    //1对1 在配置文件中创建第二个持久化单元  使用新的数据库
    @Test
    public void save2() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple2");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //创建对象
        Person person=new Person();
        person.setPname("张三");
        Card card=new Card();
        card.setCode("112254563");
        person.setCard(card);//一对一的时候 不用互相关联  保存维护端的时候  被维护端可以通知时保存
        entityManager.persist(person);
        entityManager.getTransaction().commit();
        entityManager.close();
    }
View Code

--------

1-m
多的一方为关系维护端,关系维护端负责外键记录的更新(出现mappedBy时 表示该实体为被维护方),关系被维护端是没有权利更新外键记录
-----------------
级联类型:以下几种操作都是在执行实体管理器中封装的方法时才会执行的
CascadeType.REFRESH 级联刷新:在查询order的时候 对orderItem进行查询 在执行find时起作用
(在调用 object.reflush时才会触发的操作)
CascadeType.PERSIST 级联保存:在执行保存order的时候 同时执行orderItem对象的保存工作 (在执行persist方法时起作用)
CascadeTppe.MERGE 级联合并:在更新order的时候,同时更新orderItem对象 (在执行merge方法时起作用)
CascadeType.REMOVE 级联删除:没有主外键约束的情况下 在执行order删除的时候,同时执行orderItem对象的删除 否则不删除 (在执行romove方法时才起作用)
---------
以上4种级联可以使用:CascadeType.ALL代替
-----------------
一对多:在一方配置的时候 默认的延迟加载 在多方配置的时候,默认的是立即加载

--------------------
一对一:一对一的时候 不用互相关联 保存维护端的时候 被维护端可以同时进行保存

------

---------------------------------------

多对多

基本配置

实体类:

student:

@Entity
public class Student {
    private Integer id;
    private String name;
    private Set<Teacher> teachers=new HashSet<Teacher>();
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(length=10,nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //规定:学生为关系的维护端
    //@JoinTable指定中间表的名称为t_s
    @ManyToMany(cascade= {CascadeType.REFRESH})
    @JoinTable(name="t_s")
    public Set<Teacher> getTeachers() {
        return teachers;
    }
    public void setTeachers(Set<Teacher> teachers) {
        this.teachers = teachers;
    }
    
}
View Code

teacher:

@Entity
public class Teacher {
    private Integer id;
    private String name;
    private Set<Student> students=new HashSet<Student>();
    
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(length=10,nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToMany(cascade= {CascadeType.REFRESH},mappedBy="teachers")
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
    
}
View Code

建表测试:

EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
entityManagerFactory.close();

下面是所创建的数据库表:

如果不喜欢框架自动生成的字段名称,我们可以自己控制

在定义中间表的时候,加上如下属性:

//@JoinTable指定中间表的名称为t_s
    //inverseJoinColumns关系被维护端teacher 在中间表将要对应的外键名称
    //joinColumns关系维护端  即本类student  在中间表中将要对应的外键名称
    @ManyToMany(cascade= {CascadeType.REFRESH})
    @JoinTable(name="t_s",inverseJoinColumns=@JoinColumn(name="tid"),joinColumns=@JoinColumn(name="sid"))
    public Set<Teacher> getTeachers() {
        return teachers;
    }

然后重新生成的表字段:

------------------------------------------------------------

插入数据:向student和teacher表中各插入一条记录

    //数据插入
    @Test
    public void insert() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //创建对象
        Student student=new Student();
        student.setName("肖战");
        Teacher teacher=new Teacher();
        teacher.setName("张老师");
        //保存
        entityManager.persist(student);
        entityManager.persist(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

数据库:

目前中间表是没有数据的,现在进行2个对象之间的关联,然后向中间表插入数据(建立关系,即插入数据)

插入之前,为了更加方便的建立和解除关系,所以我们在student方(关系维护方,增加如下代码)

   public void addTeacher(Teacher teacher) {
        this.teachers.add(teacher);
    }
    public void removeTeacher(Teacher teacher) {
        /*if(this.teachers.contains(teacher)) {//
            this.teachers.remove(teacher);
        }*/
        //如果集合中没有   不移除   不会报错
        this.teachers.remove(teacher);
    }

如下是添加记录的测试类:

    @Test
    public void update() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //得到对象
        Student student = entityManager.getReference(Student.class,3);
        Teacher teacher = entityManager.getReference(Teacher.class,4);
        //建立关系
        student.addTeacher(teacher);
        //建立了关系  提交之后  自动向中间表插入一条数据
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

现在开始解除关系,即删除中间表的数据:

测试类:

@Test
    public void remove() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //找出两个需要解除关系的对象
        Student student = entityManager.getReference(Student.class,3);
        Teacher teacher = entityManager.getReference(Teacher.class,4);
        //调用的是已经定义好的方法  解除关系
        student.removeTeacher(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

可以看到解除关系之后,执行代码,中间表的数据已经被删除

----------------------

思考:当中间表数据存在时,删除teacher对象 ,是否可以删除成功

【不可以,因为存在外键约束,所以在删除中间表数据之后,才能删除老师对象

删除老师 (注意老师是被维护端 所以没有权利删除外键的记录 即中间表的数据
如果非要删除 那么必须删除中间表数据(解除关系) 然后删除老师】

先看有问题的代码,直接删老师对象,如下:

    @Test
    public void removeTeacher() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        Teacher teacher = entityManager.getReference(Teacher.class,4);    
        entityManager.remove(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

提示,存在外键约束,不能正常删除

下面是正确的代码:

    @Test
    public void removeTeacher() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        Student student = entityManager.getReference(Student.class,3);
        Teacher teacher = entityManager.getReference(Teacher.class,4);
        //先解除关系
        student.removeTeacher(teacher);
        //然后执行删除
        entityManager.remove(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

这样就删除成功了

---------------------------------------

删除学生对象,可以直接进行删除,因为该对象是关系维护端,有对中间表进行操作的权限,所以在执行删除的时候,是先删除中间表,然后删除学生

    //删除学生
    public void removeStudent() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        Student student = entityManager.getReference(Student.class,3);
        //删除学生
        entityManager.remove(student);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

删除了学生表中的对象,以及相关的中间表的数据

-------------------------

联合主键

联合主键类:AirLinePK

package org.model.pk;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

//复合主键类
//有3个要求:1.必须提供无参的构造方法  2.实现序列化接口 3.覆写equals和hashCode方法
@Embeddable
public class AirLinePK implements Serializable{
    private String start;
    private String end;
    @Column(length=10)
    public String getStart() {
        return start;
    }
    public void setStart(String start) {
        this.start = start;
    }
    @Column(length=10)
    public String getEnd() {
        return end;
    }
    public void setEnd(String end) {
        this.end = end;
    }
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return super.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return super.equals(obj);
    }
    
    public AirLinePK(String start, String end) {
        super();
        this.start = start;
        this.end = end;
    }
    
    

}
View Code

AirLine类中的主键是上边的联合主键

package org.model.pk;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

@Entity
public class AirLine {
    //联合主键
    private AirLinePK id;
    private String name;
    
    
    
    public AirLine(AirLinePK id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    
    //标识复合主键的注解
    @EmbeddedId
    public AirLinePK getId() {
        return id;
    }
    public void setId(AirLinePK id) {
        this.id = id;
    }
    @Column(length=10)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    

}
View Code

测试:

    //联合主键测试
    @Test
    public void build() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple2");
        EntityManager createEntityManager = entityManagerFactory.createEntityManager();
        //开启事务
        createEntityManager.getTransaction().begin();
        //创建对象
        AirLinePK airLinePK=new AirLinePK("北京","上海");
        AirLine airline=new AirLine(airLinePK,"北京飞往上海");
        createEntityManager.persist(airline);    
        //提交事务
        createEntityManager.getTransaction().commit();
    }
View Code

数据库:

----------------------------------------------

继承注解配置

参考博客:http://cjnetwork.iteye.com/blog/974686

多方:Employee是父类,他有两个子类Sales,Skiller 一方:Department

Employee:

package org.model;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.swing.text.IconView;

import org.hibernate.annotations.ManyToAny;
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)//映射类型:单表  即所以继承的子类字段都在一个表中  默认此方式
@DiscriminatorColumn(name="type")//鉴别器的列  
//:区别不同的类  因为存在Employee Sales Skiller的数据将来都会存入employee表 区别某条数据到底是哪个类的对象
@DiscriminatorValue("0")//鉴别器的值
public class Employee {
    private int id;
    private String name;
    private Department department;
    @Id @GeneratedValue()
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(length=10,nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToOne()
    //@JoinColumn(name="depart_id")//外键名  不指定的情况下 默认: 字段名_id
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    
    
    
}

Sales:

package org.model;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue("2")//鉴别器的值
public class Sales extends Employee {
    private int sell;//出售额
    
    public int getSell() {
        return sell;
    }

    public void setSell(int sell) {
        this.sell = sell;
    }
    
}

Skiller:

package org.model;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue("3")//鉴别器的值
public class Skiller extends Employee {
    private String Skill;//技能

    public String getSkill() {
        return Skill;
    }

    public void setSkill(String skill) {
        Skill = skill;
    }
    
}

Department:

package org.model;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
@Entity
public class Department {
    private int id;
    private String name;
    //private Set<Employee> emps=new HashSet<Employee>();
    private Set<Employee> emps;
    @Id @GeneratedValue()
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(length=10)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @OneToMany(cascade= {CascadeType.MERGE,CascadeType.PERSIST},fetch=FetchType.LAZY,mappedBy="department")//mappedBy出现在该类,表示该类为关系被维护方
    public Set<Employee> getEmps() {
        return emps;
    }
    public void setEmps(Set<Employee> emps) {
        this.emps = emps;
    }
    

}

测试:

public void t1() {
        EntityManager em = rtn();
        Department department=new Department();
        department.setName("销售部");
        
        Employee e1=new Employee();
        e1.setName("张");
        e1.setDepartment(department);
        
        //创建employee的子类对象
        Sales e2=new Sales();
        e2.setName("王");
        e2.setSell(10);
        e2.setDepartment(department);
        
        Skiller e3=new Skiller();
        e3.setName("孙");
        e3.setSkill("会唱歌");
        e3.setDepartment(department);
        
        //创建员工集合
        Set<Employee> emps=new HashSet<Employee>();
        emps.add(e1);
        emps.add(e2);
        emps.add(e3);
        //互相关联  添加进部门实体中
        department.setEmps(emps);
        
        em.getTransaction().begin();
        em.persist(department);
        em.getTransaction().commit();
    }
View Code

数据库:

---------------------------------

优质内容筛选与推荐>>
1、WCF & Rest
2、enterprise architect (EA) 源码生成UML类图,帮助理解项目工程
3、(转)MySQL 线程池内幕
4、iview中,table组件在缩进时产生的bug。
5、Compared and Contrasted: OpenOffice V. LibreOffice 210


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn