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();
}
数据库:
---------------------------------
JPA学习(基于hibernate)的更多相关文章
- JPA学习---第一节:JPA详解
一.详解 JPA JPA(Java Persistence API)是Sun官方提出的Java持久化规范.它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据.他的出现主要是 ...
- JPA学习笔记
一.JPA基础1.1 JPA基础JPA: java persistence api 支持XML.JDK5.0注解俩种元数据的形式,是SUN公司引入的JPA ORM规范 元数据:对象和表之间的映射关系 ...
- 再谈Hibernate级联删除——JPA下的Hibernate实现一对多级联删除CascadeType.DELETE_ORPHAN
声明: 1.本文系原创,非抄袭或转载过来的. 2.本文论点都亲手做过实验论证. 3.本文所讲的Hibernate配置都基于注解的方式,hbm语法未提供. 非常多人对持久层概念搞不清JPA.Hibern ...
- Spring学习---JPA学习笔记
用了一段时间的Spring,到现在也只是处于会用的状态,对于深入一点的东西都不太了解.所以决定开始深入学习Spring. 本文主要记录JPA学习.在学习JPA之前,需要了解一些ORM的概念. ORM概 ...
- JPA学习(六、JPA_JPQL)
框架学习之JPA(六) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...
- JPA学习(五、JPA_二级缓存)
框架学习之JPA(五) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...
- JPA学习(三、JPA_API)
框架学习之JPA(三) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...
- JPA学习(一、JPA_Hello World)
框架学习之JPA(一) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...
- JPA学习笔记1——JPA基础
1.JPA简介: Java持久化规范,是从EJB2.x以前的实体Bean(Entity bean)分离出来的,EJB3以后不再有实体bean,而是将实体bean放到JPA中实现.JPA是sun提出的一 ...
随机推荐
- luogu 1939 【模板】矩阵加速(数列)
题目大意: a[1]=a[2]=a[3]=1 a[x]=a[x-3]+a[x-1] (x>3) 求a数列的第n项%1000000007 思路: 使用矩阵快速幂进行加速 在草稿纸上填了填数 然后就 ...
- 如何通过XInput技术针对游戏方向盘或者手柄编程
目前市面上的游戏外设,要么支持传统的DirectInput接口,要么支持最新的XInput技术.今天在这里聊一聊,如何通过XInput技术实现对这类游戏外设相关信息的捕获.关于DirectInput与 ...
- E20171006-hm
trace vt. 跟踪,追踪; 追溯,探索; 探索; 查找; vi. 沿着一小径或道路前进; 可以追溯的; n. 痕迹; 痕迹,踪迹; 微量,极少量; [植 ...
- thinkphp关联操作
比如:你要求删除用户的时候,同时删除与用户有关的所有信息. 一对一: 有 (HAS_ONE) 属于 (BELONGS_TO) 一对多: 有 (HAS_MANY) 属于 (BELONG_ ...
- Git 迁库 标签
Git迁库 (一)克隆裸库 git clone --bare https://github.com/SunArmy/Tourist.git 克隆之后进入该目录下是这样的 (二)创建新的版本库 这里我已 ...
- RocketMQ(2)
1. 消费端集群消费(负载均衡) 示例代码: /** * Producer,发送消息 * */ public class Producer { public static void main(Stri ...
- Parameter index out of range (1 > number of parameters, which is 0).
数据库错误:Parameter index out of range (1 > number of parameters, which is 0) ...
- java DDD 基于maven开发的探讨
对于DDD我目前的理解是 1.除了数据的基本操作,也可以把一些公用的方法或者类迁移到Infrastructrue 2.对于domain层可以声明各个聚合根的操作接口:例:IXXXRepository ...
- 项目管理01--使用Maven构建项目(纯干货)
目录 1. Maven基础知识 2. Maven实战.开发.测试.打包.部署一个Web项目 一.Maven基础知识 Maven坐标 Maven提供了一个中央仓库,里面包含了大量的开源软件的jar包,只 ...
- [系统]no such partition
电脑系统是win8.1+ubuntu14.2,为了卸载ubuntu,安装CentOS,于是在win8.1下把ubuntu的分区给删除了,重启,出现no such partition grub resc ...