Springboot集成jpa框架
JPA概述
PA是一个持久层的ORM框架,对jdbc的封装,使用jpa可以实现操作实体对象就能够实现对数据库表的CRUD。
ORM关系映射:
关系型数据库---java
数据表---对应java当中的实体类
记录数---对应java当中的对象
Field----对应java当中的属性
Java程序员面向对象的角度操作对象,由于我们的表以及表中的属性已经和关系型数据库当中表和字段进行了一一映射。我们操作了对象就能够操作表当中的记录。
Jpql查询
Java Pesistence Query Language:java的持久化查询语言,类似sql语句
本质:
Sql:操作的关系型数据库当中的记录
Jpql:操作的是java当中的实体类对象
Sql语句:
Select field1,field2 from tableName (field1—关系型数据库中字段的名称,tableName---表的名称)
Jpql语句:
Select attributeName1,attributeName2 from entityName(attributeName1---实体类属性的名称,entityName---实体类的名称)
Jpql编写时候注意的细节:
1.里面不能出现表名,列名,只能出现java的类名,属性名,区分大小写
2.出现的sql关键字是一样的意思,关键字不区分大小写
3.不能写select * 要写select 别名
一个小例子
dao—PetDao
/**
* 类名
* generated by hik-ga-archetype-webapp
* <p>
* 创建PetDao接口,实现Pet实体类的操作
* JpaRepository<T,ID> jpa提供的接口,接口当中定义了实体的基本操作
* T 指定具体操作的实体类:Pet实体类
* ID 指定主键字段的类型(实体类当中带有id注解的属性):Integer
*
* @date 2021/3/15 9:59
* @since
*/
public interface PetDao extends JpaRepository<Pet, Integer> {
/**
* 自定义查询:
* (1)什么时候进行自定义查询
* JpaRepository接口当中提供的方法不能正常满足实际业务需求,此时我们需要进行自定义查询:
* PetDao接口当中自定义方法:
*
* (2)方法定义注意事项:
* 方法的返回值是根据实际的业务需求定义: List pet
* 方法的名称必须满足规范:findByXxx findBy固定开始Xxx属性名称:findByPname
* 参数列表:根据实际的业务需求定义
*
* 注意:方法的名称必须满足响应的规范
*/
List<Pet> findByPname(String pname);
List<Pet> findByColor(String color);
/**
* 根据pname查询并且根据color查
* select pet0_.id as id1_0_, pet0_.color as color2_0_, pet0_.pname as pname3_0_ from t_pet pet0_ where pet0_.pname=?
* select * from t_pet pet0_ where pet0_.pname=? and pet0_.color=?
*/
List<Pet> findByPnameAndAndColor(String pname,String color);
/**
* 根据id查询:查询id在1-5之间的pet对象
*/
List<Pet> findByIdBetweenOrderById(Integer minId,Integer maxId);
/**
* jpql查询
* 语法: select attName... from entityName
*
*/
//需求查询pet列表
/**
*
* sql:select * from t_pet
* jpql:from com.example.jpa.entity.Pet
* select 别名 from xxx
* select pet from com.example.jpa.entity.Pet pet
*/
// @Query(value="from com.example.jpa.entity.Pet")
@Query(value="select pet from com.example.jpa.entity.Pet pet")
List<Pet> loadPetsList();
/**
* 查询t_pet表中的id pname color
* sql: select id,pname,color from t_pet
* jpql: select id,pname,color from com.example.jpa.entity.Pet
*
* 注意:
* 查询的结果集并没有直接封装到pet对象当中,所以用pet接收,就会出现异常ConversionFailedException
*
* 原因:查询的数据封装到了Obejct[] 不是直接封装到pet当中
*/
@Query(value="select id,pname,color from com.example.jpa.entity.Pet")
List<Object[]> loadPetsList2();
/**
*
* 查询的实体类直接封装到了对象当中
*/
@Query("select new com.example.jpa.entity.Pet(id,pname,color) from com.example.jpa.entity.Pet")
List<Pet> loadPetsList3();
}
entity—Pet 类
/**
* 类名
* generated by hik-ga-archetype-webapp
* Pet实体类,对应底层数据库表。mysql数据库当中没有t_pet表,可以使用jpa提供的逆向工程
* 实体类--->关系表
* @Entity 注解,表明当前是实体类,当前的实体类和底层的t_pet关系表进行映射
*
* @date 2021/3/12 17:35
* @since
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity(name = "t_pet")
public class Pet {
@Id//id唯一
//指定当前主键的一个生成策略,自增
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column//注解,标识pname是一个普通的列,注解当中可以指定很多属性,我们可以都使用默认值
private String pname;
@Column
private String color;
}
测试PetDao中的接口
@SpringBootTest(classes = JpaApplication.class)
class JpaApplicationTests {
@Test
void contextLoads() {
System.out.println("table 创建成功了......");
}
//对jpa提供的接口方法进行测试
@Autowired
PetDao petDao;//springboot在启动的时候,底层使用了动态代理的方式获得了一个接口的实现类,完成了注入
@Test
void addPet(){
System.out.println("pet add");
Pet pet = new Pet();
//pet.setId(); id字段是自增,不需要手动设置值
pet.setPname("小花狗");
pet.setColor("黄色");
//完成添加操作
petDao.save(pet);
}
/**
* save方法:
* 如果没有指定id,直接进行一个insert操作;
* 如果指定了id字段:
* 根据指定的id先去查询
* 如果查询id对应的记录存在的话,进行一个更新操作;
* 如果查询id对应的记录不存在的话,进行一个添加操作;
*
*/
@Test
void addPet1(){
System.out.println("pet add");
Pet pet = new Pet();
pet.setId(5); //id字段是自增,不需要手动设置值
pet.setPname("hot dog");
pet.setColor("hot");
//完成添加操作
petDao.save(pet);
}
//查询操作
/**
* 查询操作
* 根据id查询 findById();jpaRepository接口当中提供的,不是我们自定义的
* 查询的内容封装到了Optinal对象
* get();//获取Pet对象,如果查询的对象不存在,返回的一个异常是java.util.NoSuchElementException: No value present
*/
@Test
void findPet(){
//获得一个Option对象
Optional<Pet> optional = petDao.findById(4);
Pet pet = optional.get();
System.out.println(pet.getId()+" ,"+pet.getPname()+" ,"+pet.getColor());
}
/**
* 列表查询:返回的是列表集合
* findAll();没有指定任何参数,查询的列表
* findAll();在使用的时候可以指定参数。Sort 对象,指定排序字段,升序或降序
*/
@Test
void findAllPets(){
// //获得一个Option对象
// List<Pet> pets = petDao.findAll();
// for(Pet pet:pets){
// System.out.println(pet.getId()+" ,"+pet.getPname()+" ,"+pet.getColor());
// }
List<Pet> pnames = petDao.findAll(Sort.by("pname"));
for (Pet pet:pnames){
System.out.println(pet.getPname());
}
}
/**
* 分页查询
*/
@Test
void findAllPetWithPage(){
/**
* Pageable:接口类型
* PageRequest:接口的实现类对象;实现类不是直接new,构造器protect
* PageRequest:类中of方法,返回本类对象
* of():方法,static 静态方法
* 参数一:
* page:查询第一页,用户指定,page:0-----代表第一页
* size:当前页显示的记录数
* Direction.DESC:指定按降序进行排序
* properties:指定具体的哪个属性进行排序
* Pageable对象封装了一些分页相关的参数
*/
Pageable pageable = PageRequest.of(0, 3, Sort.Direction.DESC,"id");
Page<Pet> allPets = petDao.findAll(pageable);
for (Pet pet:allPets) {
System.out.println(pet.getId()+" ,"+pet.getPname()+" ,"+pet.getColor());
}
//获得分页相关信息
// long totalElements = allPets.getTotalElements();//获得元素的个数
// int totalPages = allPets.getTotalPages();//获得页码个数
}
/**
* 删除操作
* delete(pet);传递一个pet对象,删除传递对象
* 删除的具体步骤:
* 1.先根据id进行一个查询
* 2.执行delete操作
*/
@Test
void deletePet(){
// Pet pet = new Pet();
// pet.setId(5);
// petDao.delete(pet);
petDao.deleteById(3);
}
@Test
public void test3(){
//按照pname查询
List<Pet> pname = petDao.findByPname("black dog");
System.out.println(pname);
//按照color查询
List<Pet> color = petDao.findByColor("black");
System.out.println(color);
/* for(Pet pet:pname){
System.out.println(pet.getId()+" ,"+pet.getPname()+" ,"+pet.getColor());
}*/
//按照pname和color联合查询
List<Pet> list = petDao.findByPnameAndAndColor("black dog", "black");
System.out.println(list);
//根据id区间查询并且排序
List<Pet> list1 = petDao.findByIdBetweenOrderById(1,5);
System.out.println(list1);
}
//测试jpql
@Test
public void test4(){
List<Pet> list2 = petDao.loadPetsList();
System.out.println(list2);
}
@Test
public void test5(){
List<Object[]> list3 = petDao.loadPetsList2();
for(Object[] pet:list3) {
System.out.println(Arrays.toString(pet));
}
}
@Test
public void test6(){
List<Pet> list4 = petDao.loadPetsList3();
System.out.println(list4);
}
}
application.properties
# 连接数据库的四大参数
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/jpa
spring.datasource.username=postgres
spring.datasource.password=123456
# jpa相关配置
# 开发阶段可以 设置为true,开启逆向工程,在实际上线运行阶段,实体类和底层的数据库表都是已经存在,应该设置成false
# 数据库和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.PostgreSQL10Dialect
# 上线运行时只有spring.jpa.database-platform是真实有效的
pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--postgresql-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>