JPA概述
JDBC
是一个类一个接口,定义了访问数据库的通用接口,可以用java规范的访问数据库,
持久层框架
数据的存储,也就是三层框架中的Dao层,
Hibernate:开源的轻量级的ORM
- ORM(Object Relation Mapping):对象(内存中的java对象)关系(表的数据)映射(Mapping映射)
- 由面向对象的开发方法而产生的,对象和关系数据库
- 对象和关系数据是业务实体的两种表现形式
- ORM实现内存中对象到关系数据库数据的映射,以对象管理表
- 将对象映射到数据库中存储的表,操作对象就是操作数据库中的表
Mybatis:半ORM
- sql语句需要手工编写
- 支持定制化sql,存储过程以及高级映射
- 两种方式进行持久化的处理:xml或注解来配置映射原生信息
总结:
- Hibernate自动化,Mybatis手工编写sql
- 对于复杂的程序推荐Mybatis,因为Mybatis灵活,可以特定的数据库的sql语句,但是Mybatis移植性不好,因为编写的sql语句只适应一个数据库,
- 相比之下Hibernate较好,在不修改代码的情况下就可以使用不同的数据库
如果项目需要适配不同的数据库,使用Hibernate
如果是互联网应用,用大量的sql语句,需要随时优化建议使用Mybatis
JPA是什么
sun公司定义的一个规范
JPA(Java Persistence API):java持久API(用来对象持久化的)也就是操作数据库的
用来在java对象和关系数据库之间保存数据,充当面向对象的领域模型和关系数据库系统之间的桥梁
JPA定义了一些通用的接口,通过接口可以可以访问不同的数据库。
JPA使用有两种方式,一种是JDK注解,一种是XML文件描述对象关系表的映射关系,并将运行期的实体对象持久化到数据库中
Sun引入JPA ORM规范原因
- 简化Java EE 和Java SE 应用开发工作
- Sun希望整合ORM技术,实现天下归一
总结:
JPA等同于JDBC的规范,通过JPA可以集成对数据库的统一访问
JPA的实现
规范就是一个文档就是一个说明,规范不能直接的使用,我们要使用JPA规范的实现
- Hibernate
- JPA的始作俑者就是Hibernate的作者
- Hibernate 从3.2开始兼容JPA
- OpenJPA
- OpenJPA是Apache 组织提供的开源项目
- EclipseLink
- EclipseLink的前身是Toplink,Oracle的企业级ORM.
JPA的优势
- 标准化
- 可以使用JPA访问不同的数据库,不同的ORM框架,只要少量的修改代码或者是不修改代码
- 简单易用,继承了不同的框架:
- JPA提供简单的统一编程模型,可以在Spring,SpringBoot框架中使用
- 可媲美JDBC的查询能力:
- JPA是面向对象的以对象的方式来访问表中的数据
- 定义了独特的JPQL语言
- 支持面向对象的高级特性
- 类之间的继承,多态,类和类之间的复杂关系
总结:标准化是最大的优势
JPA的三方面技术
ORM映射元数据:
- 支持XML和注解两种元数据形式,元数据描述对象和表之间的映射关系,框架将对象持久化到数据库表中
JPA和API
- 对java对象执行CRUD行为,框架会把你的方法转换成数据库能识别的sql语句
查询语言(JPQL)
- 数据能存进去还得能查出来,通过JPQL可以获取持久层中的数据,因为使用的是JPQL是面向对象的,不是面向数据库的,即使你更换了数据库软件,也不用修改程序
JPA和Hibernate
- jpa是Hibernate的抽象,jpa就相当于接口,Hibernate就相当于接口的实现
- Hibernate本身就是ORM框架,可以独立使用去访问数据库,而且还扩展了其他的功能
- JPA是Hibernate功能的一个子集
总结:JPA是规范,Hibernate是JPA的具体实现,Hibernate的实现超过了JPA,还实现了一些扩展功能
JPA和Mybatis
Mybatis是一个独立的框架不算真正的ORM,和JPA规范没有关系,
jpa是对象与表之间的映射
Mybatis是对象和结果集的映射
总结:JPA是面向对象的,Mybatis是面向SQL
总结
JPA:是一个规范,制定访问数据库的API(接口和类)
使用JPA以标准的方式访问数据库
JPA的实现:
- Hibernate
- OpenJPA
- EclipseLink
JavaApplication----调用JPA中的接口-----》实现Hibernate-----》访问数据库
JPA的应用
使用JPA的主要步骤:
- 新建persistence.xml,文件名称是固定的,放在类路径的META-INF目录(目录和文件名称都是固定的)
- 创建jpa的单元,一个单元指定一个数据库的相关信息
- 配置数据库的相关属性,连接到指定的数据库
- 指定JPA的实现提供者(Hibernate,openJPA):只有一个实现的话,默认是可以不写的。
- 指定实体类的信息。
- 创建实体类,使用注解或者xml配置文件,描述实体类和数据库表的关系(定义元数据信息)
- 在java的应用中使用JPA的API实现对数据的crud.
- 主要对象EntityManagerFactory, EntityManager,EntityTransaction
开发环境的准备:
- 使用mysql数据库
- 使用的ide: idea
- 使用springboot+jpa依赖
JPA项目的开发步骤
- 新建Spring boot maven项目
- 加入JPA的实现jar ,加入的HIibernate -5.3.2/ required/ *.jar,或者加入依赖
(2条消息) Hibernate release(distribution)包下载!_donghaixiaoni的博客-优快云博客
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--引入mysql的驱动: -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
- 在resources/application.properties
#配置数据库连接信息
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jpa
spring.datasource.username=root
spring.datasource.password=x5
#jpa的和相关配置;
#开发阶段可以没置为true,开启了逆向工程:在实际上线运行阶段,实体类和底层的数据库表都是已经存在的,应该是f
# 毅管库和java碰向工程正同王程:
# 逆同王程:存在数婚库的表,然后经韶库表可以生成支实体类;
# 正网工程:兹存在变体类,然后根帮实体类。生成底层的表。
spring.jpa.generate-ddl=true
#create :没置为create,每次运行程序都会将惊来的数貂表丽除,然后重新创述一个表
#create-drop :没次将创建一个数据衣,数姻表使用完毕之后,将数据表再次删除。
#none将动糖不生效
#update如果你没定的实体类发生了改变,数据表会更新﹔
#如果当前数据库当中有数据表,就使用原来的表。没有数据表,就会创建一个数据表。也是在开发当中经常使用的属性
#validate实体类和数瘩表进行校验,如果属性或者个数不一致,就会抛出异常。
spring.jpa.hibernate.ddl-auto=update
#操作实体对象的时候,会生成sqL语句:false不生成sqL语每:
spring.jpa.show-sql=true
#指定了数据库的版本
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
- 创建实体类,在类中使用JPA有关的注解,声明元数据的信息。指定实体类的属性和数据库表的列的关系。
package com.example.demo.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/***
* 宠物实体类
* @author Administrator
*/
//@Entity 描述实体了和表之间的关系,name表示表的名字
@Entity(name="t_pet")
public class Pet {
@Id //表示该属性对应数据库的逐渐列,而且自增
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column
private String color;
@Column
private String pname;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
@Override
public String toString() {
return "Pet{" +
"id=" + id +
", color='" + color + '\'' +
", pname='" + pname + '\'' +
'}';
}
}
- 创建测试类
package com.example.demo;
import com.example.demo.dao.PetDao;
import com.example.demo.domain.Pet;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import java.util.List;
import java.util.Optional;
@SpringBootTest(classes = DemoApplication.class)
class DemoApplicationTests {
@Test
void contextLoads() {
System.out.println("-----------初始化数据库-----------");
}
@Autowired
PetDao petDao;
@Test
void addPet(){
System.out.println("add");
Pet pet = new Pet();
//pet.setId();
pet.setPname("Tom");
pet.setColor("blue");
petDao.save(pet);
}
@Test
void addPet1(){
System.out.println("add");
Pet pet = new Pet();
//pet.setId();
pet.setPname("jierui");
pet.setColor("zong");
petDao.save(pet);
}
/***
* 更新宠物信息
* save(obj)
* 如果id是null,执行insert操作
* 如果id不是null,查询数据库
* id在数据库存在 执行update
* id在数据不存在 执行insert
*/
@Test
public void updatePet() {
//创建Pet对象
Pet pet=new Pet();
pet.setId(2);
pet.setPname("小黑");
pet.setColor("黄黑");
petDao.save(pet);
}
//根据id查询
/**
* 查询操作:findByid(); JpaRepository接口当中提供的L:不是我们自定义
* 查询的内容封装到了 optional对象:
* get();方法获得Pet对象。啊如果查询的对象存在,返回的是一个异常
* NosuchElementException
*/
@Test
void find(){
//获得一个Optional对象
Optional<Pet> optional = petDao.findById(1);
Pet pet = optional.get();
System.out.println(pet.getId()+" "+pet.getPname()+" "+pet.getColor());
}
/**
* 返回的一个列表集合
*/
@Test
void findAllPets(){
//获得一个Optional对象
List<Pet> list = petDao.findAll();
for (Pet pet: list) {
System.out.println(pet.getId()+" "+pet.getPname()+" "+pet.getColor());
}
}
/**
* 查询:返回的是列表集合
* findAll();没有指定任何的参数,查询的列老
* findAll();在使用时可以指定参数,Sort象,指定排序字段.
*/
@Test
void findAllPets1(){
//获得一个Optional对象
Sort sort = Sort.by(Sort.Direction.DESC,"pname");
List<Pet> pname = petDao.findAll(sort);
for (Pet pet : pname) {
System.out.println(pet.getPname());
}
}
/**
* 分页查询
* pageable :接口类型:
* pageRequest :接口的实现类对象:实现类不是直接new,构造器protect
* PageRequest:类当中提供了of方法,返回本类对象:
* of();方法,static静态方法:
* 参数一:
* page:查询第一页,用户指定; 0代表第一页
* size:当前页显示的记录数
* Direction.AsC指定升序排序: Direction.DESC指定的降序排序
* properties:指定具体的哪个属性进行排序
*/
@Test
void findAllPetsWithPage(){
//封装了一些分页的参数
PageRequest pageable = PageRequest.of(0, 2,Direction.DESC,"id");
Page<Pet> pe = petDao.findAll(pageable);
int totalPages = pe.getTotalPages();
long totalElements = pe.getTotalElements();
System.out.println("totalPages="+totalPages);
System.out.println("totalElements="+totalElements);
//获取分页查询到的数据集合
List<Pet> list = pe.getContent();
for(Pet pet:list) {
System.out.println(pet.getId()+"\t"+pet.getPname()+"\t"+pet.getColor());
}
}
/**
* 传递的是对象
*/
@Test
void delPet(){
Pet pet = new Pet();
pet.setId(2);
petDao.delete(pet);
}
@Test
public void delByName(){
List<Pet> list = petDao.findByPname("Tom");
System.out.println(list);
//根据color查询
List<Pet> list1 = petDao.findByColor("blue");
System.out.println(list1);
//联合查询: 根据pname和color联合查询:
List<Pet> list2
= petDao.findByPnameAndColor("小黑", "黄黑");
System.out.println(list2);
//根据id区间查询,并且排序:
List<Pet> list3 = petDao.findByIdBetweenOrderById(1, 5);
System.out.println(list3);
}
}
- 自定义查询
package com.example.demo.dao;
import com.example.demo.domain.Pet;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
/**
*创建PetDao接口,实现pet实体类的操作:
* JpaRepository <t, ID> jpa提供的一个接口:接口的当中定义了实体的基本操作
* T指定具体操作的实现类:Pet实体类
* ID指定主键字段的类型(实体类当中带有id注解的属性)Integer
*/
public interface PetDao extends JpaRepository<Pet,Integer> {
/**
* 方法定义注意事项:
* 方法的返回值是根据实际的业务需求定义:List pet
* 方法的名称必须满足规范:findByXxxfindBy固定开始xxx属性名称: findByPname
* 在测试类中直接编写
* @param pname
* @return
*/
List<Pet> findByPname(String pname);
List<Pet> findByColor(String color);
/*
根据pname查询并且根据color查
select * from t_pet pet0_ where pet0_.color=? and pet0_panme =?
*/
List<Pet> findByPnameAndColor(String pname,String color);
/**
* 根据id 查询 : 查询id在 1-5之间的pet对象:
*/
List<Pet> findByIdBetweenOrderById(Integer minId, Integer maxId);
}
- 运行结果:在控制台进行查看