zoukankan      html  css  js  c++  java
  • 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

    数据库:

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

  • 相关阅读:
    51nod 1227 平均最小公倍数
    51nod 1238 最小公倍数之和 V3
    「G2016 SCOI2018 Round #2」B
    51nod 1258 序列求和 V4
    2301: [HAOI2011]Problem b
    POJ
    NOIP2017解题报告
    笔记-[ZJOI2014]力
    题解-Little C Loves 3 III
    李超线段树
  • 原文地址:https://www.cnblogs.com/Joke-Jay/p/8776764.html
Copyright © 2011-2022 走看看