JPA,Java Persistence API是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合ORM技术
ORM:通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。本质就是将数据从一种形式转换到另外一种形式。
同时也结束了Hibernate、TopLink等ORM框架各自为营的局面。JPA充分吸收了Hibernate、TopLink等ORM框架的基础上发展起来的,使用方便,伸缩性强
注意: JPA不是一种新的ORM框架,它的出现只是用于规范现有的ORM技术,它不能取代现有的Hibernate等ORM框架,相反,采用JPA开发时,我们仍将使用这些ORM框架,只是此时开发出来的应用不在依赖于某个持久化提供商。应用可以在不修改代码的情况下载任何JPA环境下运行,真正做到低耦合,可扩展的程序设计。类似于JDBC,在JDBC出现以前,我们的程序针对特性的数据库API进行编程,但是现在我们只需要针对JDBC API编程,这样能够在不改变代码的情况下就能换成其他的数据库。
JPA是一套规范,不是一套产品。Hibernate是一套产品,如果这些产品实现了JPA规范,那么我们可以叫它们为JPA的实现产品。使用JPA,就可以把我们的应用从Hibernate中解脱出来,那么现在问题来了::如何使用JPA来开发呢?
准备好了吗,进入正题,起飞!
首先,先带大家看一下本篇文章的大致介绍。
没目录怎么知道这篇到底有多少干货呢?
以前的开发模式
JPA是什么
JPA解决了什么问题
JPA的第一个HelloWord程序
详解配置文件
常用的注解
一对一的问题
一对多的问题
多对多的问题
JPA中常见的方法
JPA中对象的状态
注意事项
是不是很清晰呢,什么?还不进入正文,来了,安排上,一个一个来:
以前开发的时候我们的DAO层,要么使用Hibernate、要么使用iBatis、dbutils、toplink
需求:假设现在的产品的1.0版本的DAO的实现使用的是Hibernate、现在老板要求将DAO层换成TopLink
按照现在的解决方案整个DAO层都是需要重写的,很耗费人力和物力,增加了成本
有没有一种方案?这种方案就是如果我们需要换ORM框架,我们的整个DAO层都不需要改变只是需要改变配置文件就可以了呢?
JPA技术技术因此而生
JPA实际上是sun公司出的一套规范、这套规范的作用是为了解决市场上ORM框架一家独大的问题
JPA是一套规范,只要我们的ORM框架实现了这套规范,那么在使用这个ORM框架的时候,就不需要面对于某一种ORM产品的API来进行编程,而是统一的面向于JPA来进行编程,这个时候即使你的ORM产品改变了,那么你的DAO层面向于JPA编程的代码是不用变的
JPA统一了ORM框架访问数据库的API
JPA解决了ORM框架一家独大的问题
@Table(name="t_user") //设置当前的类的对象对应的表名字
@Entity //表示当前的这个类是一个持久化的实体
public class User {
@Id //这个表示的是当前的字段是主键
@GeneratedValue(strategy=GenerationType.IDENTITY) //这个表示的是主键的生成策略(自增长)
@Column(name="uId")
private int uId;
@Column(name="userName") //列的名字
private String userName;
@Column(name="password")
private String password;
}
@Test
public void testHelloWorld() throws Exception {
//第一步:创建实体管理的工厂
EntityManagerFactory ef=Persistence.createEntityManagerFactory("hibernateJPA");
//通过工厂创建实体的管理器
EntityManager em=ef.createEntityManager();
//第三步:开启事务
em.getTransaction().begin();
//操作业务逻辑
User user=new User();
user.setUserName("浅羽");
user.setPassword("123");
//保存用户实体到数据库
em.persist(user);
//提交事务
em.getTransaction().commit();
//关闭管理器
em.close();
ef.close();
}
@Table:表示的是当前的实体对应的数据库中的表名字
@Entity:表示的是当前的实体是一个持久化的实体
@Id:这个表示当前的属性是一个主键
@GeneratedValue:主键的生成策略
strategy=GenerationType.IDENTITY:这个表示的是主键自增长
strategy=GenerationType.AUTO:使用表来生成目标表的主键
strategy=GenerationType.SEQUENCE:使用序列来生成主键
@Column:jAVA的属性对应的数据库表的列的名字
Name:名字
Length:表示的是字段的长度
nullable=false:这个表示的是不能为null
unique=true:是否是唯一的
@Transient :当前字段在数据库中不对应列
@Enumerated:表示的是枚举在数据库中的映射使用下标还是字符串
EnumType.STRING:表示的是以字符串的形式显示
EnumType.ORDINAL:表示枚举在数据中以下标的形式显示
@Lob:修饰String类型的时候 表示的大文本
修饰byte[]的时候表示存储的是二进制
需求:一个人对应了一个身份证、一个身份证也唯一对应了一个人
身份证----->人
一对一的关系
声明IdCard类
:
@Entity
@Table
public class IdCard {
@Id
private String cardNum;
private Date startTime;
private Date endTime;
//一个身份证唯一的对应了一个人
@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinColumn(name="pId") //这个表示的是添加一个列 这个列映射下面对象中的这个Id
private People people;
}
声明People类
:
@Entity
@Table
public class People {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int pId;
private String pName;
private String pTel;
//一个人对应了一个身份证
//在关联关系中 配置了mappedBy的哪一方没有权限维护另外一方
//mappedBy的值就是当前的类在下面对象中声明的这个名字
@OneToOne(mappedBy="people",cascade=CascadeType.ALL)
private IdCard idCard;
}
测试
:
@Test
public void testHelloWorld() throws Exception {
EntityManager entityManager=JPAUtils.getEntityManager();
IdCard idCard=new IdCard();
idCard.setCardNum("510...x");
idCard.setStartTime(new Date());
idCard.setEndTime(new Date());
People people=new People();
people.setpName("小羽");
people.setpTel("1234566");
idCard.setPeople(people);
entityManager.persist(idCard);
JPAUtils.close();
}
需求:部门和员工的对应
部门----->员工
一对多的关联关系
声明部门对象
:
@Entity
@Table
public class Dept {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int dId;
private String dName;
private String dDes;
//一个部门有多个员工
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="dept")
private Set emps;
}
声明员工对象
:
@Entity
@Table
public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int empId;
private String empName;
@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinColumn(name="dId")
private Dept dept;
}
测试
:
@Test
public void testOne2Many() throws Exception {
EntityManager entityManager=JPAUtils.getEntityManager();
Employee emp=new Employee();
emp.setEmpName("小娜");
Dept dept=new Dept();
dept.setdName("研发部");
dept.setdDes("专门搞开发的");
emp.setDept(dept);
entityManager.persist(emp);
JPAUtils.close();
}
需求:一个学生可以被多个老师教,一个老师也可以教多个学生
学生----->老师 一对多
老师----->学生 一对多
老师和学生的最终关系 多对多的关联关系
编写老师实体
:
@Entity
@Table
public class Teacher {
@Id
private String tNum;
private String tName;
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinTable(name="t_teacher_student",
joinColumns=@JoinColumn(name="tNum"), //映射的是当前这个类的主键
inverseJoinColumns={@JoinColumn(name="stuNum")}) //映射的是对方表的主键
private Set students;
}
编写学生实体
:
@Entity
@Table
public class Student {
@Id
private int stuNum;
private String stuName;
private int age;
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="students")
private Set teachers;
}
测试
:
@Test
public void testMany2Many() throws Exception {
EntityManager em=JPAUtils.getEntityManager();
Teacher teacher=new Teacher();
teacher.settName("小羽");
teacher.settNum("007");
Set students=new HashSet();
Student student=new Student();
student.setAge(18);
student.setStuName("小白");
student.setStuNum(100);
Student student1=new Student();
student1.setAge(19);
student1.setStuName("小娜");
student1.setStuNum(1000);
Student student2=new Student();
student2.setAge(20);
student2.setStuName("小黑");
student2.setStuNum(10000);
students.add(student);
students.add(student1);
students.add(student2);
teacher.setStudents(students);
em.persist(teacher);
JPAUtils.close();
}
常见方法
:
public void testMethod() throws Exception {
EntityManager entityManager=JPAUtils.getEntityManager();
User user= new User();
user.setUserName("小灰");
user.setuId(1);
//添加数据的方法
// entityManager.persist(user);
//查询数据
//User user2=entityManager.find(User.class,1);
//这个写的是HQL语句
// Query query=entityManager.createQuery("from User");
// List list=query.getResultList();
//下面这个方法有主键值 那么就修改 没有主键值 就插入
//entityManager.merge(user);
/*创建的是本地SQL的查询
Query query=entityManager.createNativeQuery("select * from user");
List list=query.getResultList();*/
//一般用在查询中 获取最新的这个数据
// entityManager.refresh(user);
User user2=entityManager.find(User.class,1);
entityManager.remove(user2);
//System.out.println(list);
JPAUtils.close();
}
对象的状态:
新建状态
: User user = new User();和数据库以及内存没有任何关联,对象仅仅是被new出来之后的这种状态
托管状态
: 对象调用了find persist refresh merge或者查询之后的这个对象状态就叫做托管状态,托管状态的数据是被entityManager管理的,并且内存和数据库的数据是对应了,这个时候如果你改变了内存的这个数据的话,并且进行提交的话,那么这个数据会和数据库进行同步
游离状态
: 当前的对象调用了clear方法之后在close方法之前的这段时间,这个对象处于游离状态。clear:表示的是清楚内存和数据库数据的对应的关系
删除状态
: 当前对象close之后的对象的这种状态,就称为删除状态
表名不写默认就是类作为表名
column不写,表的列名就是类的属性名
@GeneratedValue后面值不写默认是auto
JPA是我们开发中离不开的经常用到的技术,其涉及的技术和知识面其实远不止上面列出的这些。
后续浅羽会继续更新关于JPA的开发知识,只希望能对大家有所帮助,谢谢大家的支持!
写作秉持初心,致力于让每一位互联网人共同进步。
往期推荐
动态资源技术JSP|Java与Html的美好相遇
「万字图文」史上最姨母级Java继承详解
尚能饭否|技术越来越新,我对老朋友jQuery还是一如既往热爱
告别祈祷式编程|单元测试在项目里的正确落地姿势
小记 | 一周上线百万级高并发系统
组件必知必会|那些年我们使用过的轮子—Filter和Proxy
【简历加分】hexo框架搭建个人博客站点,手把手教学。
ES开发指南|如何快速上手ElasticSearch
如果你觉得浅羽的文章对你有帮助的话,请在微信搜索并关注「 浅羽的IT小屋 」微信公众号,我会在这里分享一下计算机信息知识、理论技术、工具资源、软件介绍、后端开发、面试、工作感想以及一些生活随想等一系列文章。所见所领,皆是生活。慢慢来,努力一点,你我共同成长...
点点点,一键三连都在这儿!