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&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&characterEncoding=UTF-8" /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="jay571018"></property> --> </properties> </persistence-unit> </persistence>
---------------------------------------
实体类: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; } }
实体类:Gender
package org.model; //创建枚举 性别 public enum Gender { Man,Women }
建表和插入测试:
//建表测试 @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(); }
数据库表结构以及数据记录
--------------------------------
大文本以及延迟加载等注解的使用
//大文本类型 例如个人信息说明 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; }
------------------------------------------
查询测试
为了方便观察,我们让查询的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();
正常执行,输出null(不是打印地址,这里需要注意,如果没有close语句的时候,则会打印对象地址,这个地方我也没有搞明白)
//异常测试 出现异常 实体类找不到 而且出现异常的时机在输出p的时候产生 而不是在执行查询的时候产生 Person p = em.getReference(Person.class,3);// System.out.println(p);//在执行该语句的时候 产生异常 而不是在查询的时候 em.close(); factory.close();
-----------------------------
更新测试
//更新测试 @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(); }
介绍两个方法
第一个方法:
//更新测试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=?
可以完成更新操作
----------------------------------------------------
删除测试
//删除 @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();//提交事务 }
完成删除
控制台打印:
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=?
---------------------------------------------
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()); }
即使查询不到也没有关系 ,而下面的这种结果返回情况就不行了
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(); }
删除的对象不存在也没有关系
----------------------------------
更新:
//更新 @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();//提交事务 执行了两次更新 }
-------------------------------------
命名查询
实体类:
测试代码:
//命名查询 在实体上边直接写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();//提交事务 执行了两次更新 }
----------------------------
一对多
实体代码
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); } }
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; } }
测试类:
@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(); }
----------------------------
一对一
实体类代码
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; } }
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; } }
测试:
//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(); }
--------
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; } }
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; } }
建表测试:
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(); }
数据库:
目前中间表是没有数据的,现在进行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(); }
现在开始解除关系,即删除中间表的数据:
测试类:
@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(); }
可以看到解除关系之后,执行代码,中间表的数据已经被删除
----------------------
思考:当中间表数据存在时,删除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(); }
提示,存在外键约束,不能正常删除
下面是正确的代码:
@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(); }
这样就删除成功了
---------------------------------------
删除学生对象,可以直接进行删除,因为该对象是关系维护端,有对中间表进行操作的权限,所以在执行删除的时候,是先删除中间表,然后删除学生
//删除学生 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(); }
删除了学生表中的对象,以及相关的中间表的数据
-------------------------
联合主键
联合主键类: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; } }
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; } }
测试:
//联合主键测试 @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(); }
数据库:
----------------------------------------------
继承注解配置
参考博客: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(); }
数据库:
---------------------------------