所有的注解都是定义在getter方法的类名上的。
最好不要把类名或者字段名定义为数据库中的关键字相同!!!!!
JPA的配置文件persistence.xml是在META-INF文件夹下的
EntityManager,在对数据库做查询操作的时候,不需要开始事务,也就是说:
EntityManagerFactory factory=Persistence.createEntityManagerFactory();
EntityManager em=factory.createEntityManager();
em.getTransaction.begin();//开始事务
Person person=em.find(Person.class,1);
System.out.println(person.getName());
em.getTransaction.commit();
em.close();
factory.close();
上面代码中的
em.getTransaction.begin();//开始事务
em.getTransaction.commit();
这两行代码是不需要的(在查询数据库的时候)
只有在修改的时候,需要事务。(增、删、改操作)
获取数据的em.find(Person.class,1);相当于hibernate中的get(Person.class,1);方法,如果没有数据,会返回null值。
JPA还有一个方法em.getReference(Person.class,1);
相当于hibernate中的load()方法,执行em.getReference(Person.class,1);的时候并不会去数据库中拿数据,
而是在person.getName();的时候才会去数据库中查询,name的值。如果没有相应数据,会报异常。
EntityNotFoundException
实体的三个状态:
new
:新创建的对象
managered 托管
(非脱管,以前老记为脱管)
事务之内,是托管态。在托管态的对象是和数据库关联的。
EntityManagerFactory factory=Persistence.createEntityManagerFactory();
EntityManager em=factory.createEntityManager();
em.getTransaction.begin();//开始事务
Person person=em.find(Person.class,1);//托管
System.out.println(person.getName());
em.getTransaction.commit();
em.close();
factory.close();
游离(脱管)状态
EntityManagerFactory factory=Persistence.createEntityManagerFactory();
EntityManager em=factory.createEntityManager();
em.getTransaction.begin();//开始事务
Person person=em.find(Person.class,1);
em.clear();//清空缓存
System.out.println(person.getName());//这时候的person是游离态。也就是没有和数据库联系,对它修改不会同步到数据库
em.getTransaction.commit();
em.close();
factory.close();
有一个方法可以把游离态的实体对象,和数据库关联起来(前提是必须是游离态的对象)
EntityManagerFactory factory=Persistence.createEntityManagerFactory();
EntityManager em=factory.createEntityManager();
em.getTransaction.begin();//开始事务
Person person=em.find(Person.class,1);
em.clear();//清空缓存,这个时候,person是游离态的。
person.setName("tom");
em.merge(person);
em.getTransaction.commit();
em.close();
factory.close();
这里的merge会把游离态的person联系到数据库,所做修改会先保存到session中。在commit之后
会保存到数据库中。merge的目的就是把游离态的数据和数据库联系起来。
删除状态
EntityManagerFactory factory=Persistence.createEntityManagerFactory();
EntityManager em=factory.createEntityManager();
em.getTransaction.begin();//开始事务
Person person=em.find(Person.class,1);
em.remove(person);
em.getTransaction.commit();
em.close();
factory.close();
多的一方为关系维护端,关系维护端负责外键记录的更新,关系被维护端是没有权利
oneToMany是在一端配置的
@oneToMany(cascade=(CascadeType.PERSIST,CascadeType.REFRESH,CascadeType.REMOVE))
级联的几种方式:ALL,MERGE,PERSIST,REFRESH,REMOVE
PERSIST:级联持久化(或者可以理解为级联保存??),one端数据持久化的时候,many端数据也会持久化
MERGE:级联更新(可以认识是修改数据的时候级联?也就是做update的时候?)
REFRESH:级联刷新:也就是如果其他用户修改了一条数据的话,我再用这个数据之前要重新获取一次,以防止要操作的数据是错误的。感觉像是防止脏读的。
REMOVE:就是级联删除啦,如果one端数据被删除,那么many端与与之对应的数据也会被删除。
EntityManagerFactory factory=Persistence.createEntityManagerFactory();
EntityManager em=factory.createEntityManager();
em.getTransaction.begin();//开始事务
Person person=em.find(Person.class,1);
em.refreash(person);//重新从数据库中获取一次数据。可能在你操作的过程中别人对它进行了修改操作。
em.getTransaction.commit();
em.close();
factory.close();
JPA延迟加载(相当于hibernate中的lazy=true,lazy=false)
@oneToMany(cascade=(CascadeType.REFREASH),fetch=FetchType.EAGER)
fetchType有两种:EAGER,LAZY
EAGER就是立即加载。LAZY是延迟加载
如果要使用LAZY的话,也就是延迟加载的话,那么再获取one端数据的时候,不会去查询many端的数据。
而且,要从one端对象获取many端数据的时候是再次从数据库中查询得到的。这个时候必须保证EntityManager是打开状态。
只要是级联获取many端数据的时候,默认是LAZY。也就是说@oneToMany,@ManyToMany默认都是延迟加载的。
关系维护的控制权(相当于hibernate中的inverse)
@oneToMany(fetch=FetchType.EAGER,mapperBy="order")//这里的order要看many端类里定义的属性名是什么,比如:
One端类为Order.java
many端为OrderItem.java,在OrderItem.java中定义了一个private Order order;
那在One端中的@oneToMany()中就要定义这样一个mapperBy="order",表示他们两个的外键关系由many端的order来维护。
好像是mapperBy只定义在关系被维护端。就是有外键的一端来维护外键关系。
@ManyToOne(),默认是立即加载。
optional
@ManyToOne(optional=true)
public Order getOrder()
{
return order;
}
@ManyToMany()中还有一个属性optional,它有两个值true,false
true代表many端的Order属性可以为Null,false表示不能为null.
@JoinColumn(name="order_id")
public Order getOrder()上还要定义一个外键关系字段是哪个。
@ManyToMany双向关联关系
例子:teachers,students,
老师做关系的被维护段,学生做关系的维护段。
那么在老师和学生的关系没解除的情况下,不可以直接通过EntityManager的remove方法删除teacher对象。
必须在学生端先解除关系,才可以对老师进行remove.
删除学生的时候
联合主键
例如:飞机的:startCity,endCity.这两个属性做为联合主键。
要求:
1. 必须实现Serializable接口
2. 必须有一个无参数的构造方法
3. 重写hashCode()和equals(),重写这两个方法必须要联合主键的属性endCity,startCity.
(直接右键,override就可以了。)
例子:
联合主键类:
@Embeddable //这个注解表明要使用AirLinePK中的两个字段做其他实体类的联合主键。
AirLinePK.java
两个属性,private String startCity,endCity,然后是setter/getter方法
实现Serializable接口,重写hashCode(),equals()方法。有一个无参的构造方法。
Airline.java
private AirLinePK id;
private String name;
//getter/setter方法
@EmbeddedId // 表明它是做为联合主键的
public AirLinePK getId()
{
return id;
}
<div