SpringBoot数据访问3系列
3.1 SpringBoot整合MyBatis
3.2 SpringBoot整合JPA
3.3 SpringBoot整合Redis
SpringBoot整合JPA
概括
① JPA(Java持久化API),是Sun公司官方提出的Java持久化规范,它为Java开发人员提供了一种对象/关系映射工具 管理Java中的关系型数据库,其主要目的是简化现有的持久化开发工作和整合ORM(对象关系映射),spring boot在JPA规范的基础上,利用其优点,提出了Spring Data JPA模块对其具有ORM关系的数据进行持久化操作
② Spring Data JPA是Spring在ORM框架、JPA规范的基础上封装的一套JPA应用框架,提供增删改查等常用功能,使开发者能用较少的代码实现数据操作,同时还易于扩展。
本文主要介绍SpringBoot中如何使用JPA框架对ORM关系的数据
- JPA以及Spring Data JPA的介绍
- springboot项目中如何使用JPA对关系型数据库中的数据(ORM对象关系映射)进行操作
① 添加spring-boot-starter-data-jpa依赖
② 实体类(POJO类=>普通java类)=>@Entity注解标识
③ DAO层(自定义Repositroy接口)
④ 测试类(简单使用了Pageable分页查询)
一、步骤截图
1. 创建项目,添加mysql和jpa依赖,配置数据库连接
创建项目,添加两个依赖
在全局配置文件中,对数据库进行连接
# MySQl数据库springbootdata连接配置
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=123456
如果在3.1 SpringBoot整合MyBatis的基础上修改,则需要在pom.xml中添加
spring-boot-starter-data-jpa
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2. 编写ORM实体类
@Entity
:标注要与数据库做映射的实体类,默认情况下,数据表的名称是首字母小写的类名,可以用name属性指定映射的表名
(设置ORM实体类,并指定映射的表名)
@Entity(name = "t_comment")
@Id
:标注在类属性或getter()方法上,标识该类属性对应表中的主键(表明映射对应的主键)@GeneratedValue
:与@Id注解标注在同一位置,用于表示属性对应主键的生成策略
(设置主键自增长策略)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
:标注在属性上,当类属性和表字段名不同时,用name属性表示该类属性对应的表字段名
(指定映射的表字段名)
@Column(name = "a_id")
创建com.wpz.domain包,创建Comment实体类
2.1 报错解决:idea中@Column的name属性值报错:Cannot resolve column ‘a_id’
按照图片步骤解决:
然后就ok啦
3. 编写Repository接口
- 使用Spring Boot JPA自定义Repository接口,必须继承XXRepository接口<T,D>,T:要操作的实体类,D:实体类中主键数据类型
① JpaRepository接口继承关系
- 在自定义接口中对数据进行操作 的主要方式:
① 自定义接口继承了JpaRepository接口,则默认包含了一些常用的CRUD
② 可以直接使用方法名关键字进行查询操作(注意是查询!)=>findBy+表字段名(列名)+[关键字:NotNull等]
③ 可以使用 @Query注解配合SQL语句进行数据查,改,删操作
④ 针对变更操作(改、删),无论是否使用了@Query,都必须在方法上添加@Transaction注解进行事务管理,否则会报InvalidDataAccessApiUsageException(无效数据访问api使用异常)。如果调用Repository接口方法的业务层Service类上添加了@Transaction注解,那Repository接口中就不用标了
⑤ 使用@Query执行变更操作(改、删)时,除了使用@Query还必须使用@Modifying注解表示数据变更
创建com.wpz.repository包,创建一个用于对数据库表t_comment进行操作的Repository接口CommentRepository
4. 编写单元测试
在Chapter03jpaApplicationTests测试类当前位置创建一个JpaTests测试类,用于编写Jpa相关的单元测试
这里是步骤截图,整体代码在后面整体罗列
4.1 解决报错:java.lang.IllegalStateException: Failed to load ApplicationContext
报错解释内容是这样
我这里的原因是全局配置文件中没有连接mysql数据库
# MySQl数据库springbootdata连接配置
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=123456
二、测试结果
运行JpaTests测试类
三、整体代码
目录结构
1. 全局配置文件(数据库连接)
# MySQl数据库springbootdata连接配置
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=123456
2. 实体类(@Entity标注的)
package com.wpz.domain;
import javax.persistence.*;
/**
* @author 王胖子
* @version 1.0
* ORM实体类
*/
//设置ORM实体类,并指定映射的表名
//@Entity:标注要与数据库做映射的实体类,默认情况下,数据表的名称是首字母小写的类名,可以用name属性指定映射的表名
@Entity(name = "t_comment")
public class Comment {
//表明映射对应的主键
//@Id:标注在类属性或getter()方法上,标识某一个属性对应表中的主键
@Id
//设置主键自增长策略
//@GeneratedValue:与@Id注解标注在同一位置,用于表示属性对应主键的生成策略
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;//主键id
private String content;//评论的内容
private String author;//发表评论的人
//指定映射的表字段名
//@Column:标注在属性上,当类属性和表字段名不同时,用name属性表示该类属性对应的表字段名
@Column(name = "a_id")
private Integer aId;//关联t_article的主键(作为t_comment的外键)
//下面是get、set、toString方法
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Integer getaId() {
return aId;
}
public void setaId(Integer aId) {
this.aId = aId;
}
@Override
public String toString() {
return "Comment{" +
"id=" + id +
", content='" + content + '\'' +
", author='" + author + '\'' +
", aId=" + aId +
'}';
}
}
3. DAO层接口(使用JPA框架对ORM关系的数据进行操作)
package com.wpz.repository;
import com.wpz.domain.Comment;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author 王胖子
* @version 1.0
* Repository接口文件,用于对数据库表进行操作
*/
public interface CommentRepository extends JpaRepository<Comment, Integer> {
//1. 查询author非空的Comment集合=>不需要标注解,因为这是JPA支持的方法名关键子查询方式
List<Comment> findByAuthorNotNull();
//2. 根据文章id(实体类中设置的表字段名对应的类属性名aid),分页查询Comment评论集合
@Query("SELECT c FROM t_comment c WHERE c.aId=?1")
List<Comment> getCommentPaged(Integer aid, Pageable pageable);
//3. 使用原生SQL语句(使用表字段名a_id),根据文章id分页查询Comment评论集合
@Query(value = "SELECT * FROM t_comment WHERE a_Id=?1", nativeQuery = true)
List<Comment> getCommentPaged2(Integer aid, Pageable pageable);
//4. 根据评论id修改评论作者author
@Transactional
@Modifying
@Query("UPDATE t_comment c SET c.author=?2 where c.id=?1")
int updateComment(Integer id, String author);
//5. 根据评论id删除评论
@Transactional
@Modifying
@Query("DELETE FROM t_comment c where c.id=?1")
int deleteComment(Integer id);
}
5. 测试类(简单使用了Pageable分页查询)
package com.wpz;
import com.wpz.domain.Comment;
import com.wpz.repository.CommentRepository;
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.Pageable;
import java.util.List;
import java.util.Optional;
/**
* @author 王胖子
* @version 1.0
* JpaTests:用于编写Jpa相关的单元测试
*/
@SpringBootTest
public class JpaTests {
@Autowired
private CommentRepository repository;
//1. 使用JpaRepository内部方法进行操作
// findById(1)=>接口文件自己提供的查询方法,可以直接使用
@Test
public void selectComment() {
Optional<Comment> optional = repository.findById(1);
if (optional.isPresent()) {//查回来内容不为空
System.out.println("内部方法findById(1)查询\n" + optional.get());//输出查出的内容
}
System.out.println();
}
//2. 使用方法名关键字findByAuthorNotNull()进行数据操作
@Test
public void selectCommentByKeys() {
List<Comment> list = repository.findByAuthorNotNull();
System.out.println("方法名关键字查询:作者非空时的评论\n" + list);
}
//3. 使用@Query注解进行操作=>根据文章id查询评论,并根据指定分页来显示查询结果
@Test
public void selectCommentPaged() {
/*
pageable封装了分页的参数,当前页page(开始页是0),和每页最多显示的条数3
- aid=1时,查询的结果有4条,每页最多显示3条,所以共有2页(0页[3条]和1页[1条])
- 这里我设置了当前页为1,表示我想要得到第1页的内容
- 结果会出现第1页的一条内容
*/
Pageable pageable = PageRequest.of(1, 3);
List<Comment> currentPagedComment = repository.getCommentPaged(1, pageable);
System.out.println("@Query注解查询:aid=1时第一页的评论\n" + currentPagedComment);
}
}