AI智能
改变未来

Spring Data开发手册|Java持久化API(JPA)需要了解到什么程度呢?

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是什么

JPA实际上是sun公司出的一套规范、这套规范的作用是为了解决市场上ORM框架一家独大的问题

JPA是一套规范,只要我们的ORM框架实现了这套规范,那么在使用这个ORM框架的时候,就不需要面对于某一种ORM产品的API来进行编程,而是统一的面向于JPA来进行编程,这个时候即使你的ORM产品改变了,那么你的DAO层面向于JPA编程的代码是不用变的

JPA解决了什么问题

JPA统一了ORM框架访问数据库的API

JPA解决了ORM框架一家独大的问题

JPA的第一个HelloWorld程序

导包

编写配置文件

<?xml version=\"1.0\" encoding=\"UTF-8\"?><persistence 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\" version=\"2.1\"> <persistence-unit name=\"hibernateJPA\" transaction-type=\"RESOURCE_LOCAL\">  <properties>   <property name=\"hibernate.hbm2ddl.auto\" value=\"update\"></property>   <property name=\"hibernate.show_sql\" value=\"true\"></property>   <property name=\"hibernate.format_sql\" value=\"true\"></property>   <property name=\"hibernate.dialect\" value=\"org.hibernate.dialect.MySQL5Dialect\"></property>   <property name=\"hibernate.connection.url\" value=\"jdbc:mysql:///qianyu\"></property>   <property name=\"hibernate.connection.driver_class\" value=\"com.mysql.jdbc.Driver\"></property>   <property name=\"hibernate.connection.username\" value=\"root\"></property>   <property name=\"hibernate.connection.password\" value=\"root\"></property>  </properties> </persistence-unit> </persistence>

编写Java实体和注解

@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(); }

详解配置文件

<?xml version=\"1.0\" encoding=\"UTF-8\"?><persistence 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\" version=\"2.1\">    <!--         persistence-unit:这个叫做持久化的单元   这个的作用就是配置 访问数据库的信息         name:逻辑意义上可以随便写  但是一般情况下见名之意  这个一般情况下写JPA的实现产品的名字         transaction-type:事务的类型            RESOURCE_LOCAL:局部事务                                事务的分类                            全局事务                               举例:张三给李四转账(建设银行----中国银行)                                                            局部事务                               举例:所有的操作在同一个库里头执行                                                            粗粒度事务                              举例:能够对整个类或者方法体进行事务的管理                                                细粒度事务                                  举例:就是能够对某几行代码进行事务的管理                                      --> <persistence-unit name=\"hibernateJPA\" transaction-type=\"RESOURCE_LOCAL\">  <properties>   <property name=\"hibernate.hbm2ddl.auto\" value=\"update\"></property>   <property name=\"hibernate.show_sql\" value=\"true\"></property>   <property name=\"hibernate.format_sql\" value=\"true\"></property>   <property name=\"hibernate.dialect\" value=\"org.hibernate.dialect.MySQL5Dialect\"></property>   <property name=\"hibernate.connection.url\" value=\"jdbc:mysql:///qianyu\"></property>   <property name=\"hibernate.connection.driver_class\" value=\"com.mysql.jdbc.Driver\"></property>   <property name=\"hibernate.connection.username\" value=\"root\"></property>   <property name=\"hibernate.connection.password\" value=\"root\"></property>  </properties> </persistence-unit> </persistence>

常用的注解线程池技术

@Table:表示的是当前的实体对应的数据库中的表名字@Entity:表示的是当前的实体是一个持久化的实体@Id:这个表示当前的属性是一个主键@GeneratedValue:主键的生成策略strategy=GenerationType.IDENTITY:这个表示的是主键自增长strategy=GenerationType.AUTO:使用表来生成目标表的主键strategy=GenerationType.SEQUENCE:使用序列来生成主键@Column:jAVA的属性对应的数据库表的列的名字Name:名字Length:表示的是字段的长度nullable=false:这个表示的是不能为nullunique=true:是否是唯一的@Transient :当前字段在数据库中不对应列@Enumerated:表示的是枚举在数据库中的映射使用下标还是字符串EnumType.STRING:表示的是以字符串的形式显示EnumType.ORDINAL:表示枚举在数据中以下标的形式显示@Lob:修饰String类型的时候 表示的大文本       修饰byte[]的时候表示存储的是二进制

一对一的问题

需求:一个人对应了一个身份证、一个身份证也唯一对应了一个人

  • 身份证—–>人

  • 一对一的关系

代码演示:

声明IdCard类

@Entity@Tablepublic 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@Tablepublic 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@Tablepublic 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<Employee> emps;}

声明员工对象

@Entity@Tablepublic 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@Tablepublic 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<Student> students;}

编写学生实体

@Entity @Tablepublic class Student {  @Id private int stuNum;  private String stuName;  private int age;  @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy=\"students\") private Set<Teacher> teachers;}

测试

@Test public void testMany2Many() throws Exception {     EntityManager em=JPAUtils.getEntityManager();    Teacher teacher=new Teacher();  teacher.settName(\"小羽\");  teacher.settNum(\"007\");    Set<Student> students=new HashSet<Student>();    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(); }

JPA中常见的方法

代码演示:

常见方法

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(); }

JPA中对象的状态

对象的状态:

  • 新建状态

    : User user = new User();和数据库以及内存没有任何关联,对象仅仅是被new出来之后的这种状态

  • 托管状态

    : 对象调用了find persist refresh merge或者查询之后的这个对象状态就叫做托管状态,托管状态的数据是被entityManager管理的,并且内存和数据库的数据是对应了,这个时候如果你改变了内存的这个数据的话,并且进行提交的话,那么这个数据会和数据库进行同步

  • 游离状态

    : 当前的对象调用了clear方法之后在close方法之前的这段时间,这个对象处于游离状态。clear:表示的是清楚内存和数据库数据的对应的关系

  • 删除状态

    : 当前对象close之后的对象的这种状态,就称为删除状态

 

注意事项

表名不写默认就是类作为表名

column不写,表的列名就是类的属性名

@GeneratedValue后面值不写默认是auto

结语

JPA是我们开发中离不开的经常用到的技术,其涉及的技术和知识面其实远不止上面列出的这些。

后续浅羽会继续更新关于JPA的开发知识,只希望能对大家有所帮助,谢谢大家的支持!

点点点,一键三连都在这儿!

 

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Spring Data开发手册|Java持久化API(JPA)需要了解到什么程度呢?