Spring Data JPA:
JPA(Java Persistence API)即java持久化API,它的出现主要是为了简化持久层开发以及整合ORM技术,结束Hibernate、TopLink、JDO等ORM框架各自为营的局面。JPA是在吸收现有ORM框架的基础上发展而来,易于使用,伸缩性强。总的来说,JPA包括以下三方面的技术:
ORM映射元数据:支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系
API:操作实体对象来执行CRUD操作
查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合
Sping Data JPA官方解释:
Spring Data JPA是Spring Data家族的一部分,可以轻松实现基于JPA的存储库。此模块处理对基于JPA的数据访问层的增强支持。它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。
在相当长的一段时间内,实现应用程序的数据访问层一直很麻烦。必须编写太多样板代码来执行简单查询以及执行分页和审计。Spring Data JPA旨在减少实际需要的工作量来显著改善数据访问层的实现。
SpringBoot 整合Spring Data JPA:
导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
数据库配置:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/chapter05?characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
#表示Jpa对应的数据库是mysql
spring.jpa.show-sql=true
#项目启动时根据实体类更新数据库中的表
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.ddl-auto:
create:每次运行程序时,都会重新创建表,故而数据会丢失
create-drop:每次运行程序时会先创建表结构,然后程序结束时清空表
update:每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新(推荐使用)
validate:运行程序会校验数据于数据库的字段类型是否相同,字段不同会报错
none:禁用DDL处理
Spring Data JPA的使用:
创建实体类:
import lombok.Data;
import javax.persistence.*;
@Data
@Entity(name = "t_book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "book_name")
private String name;
@Column(name = "book_author")
private String author;
private Float price;
@Transient
private String description;
}
代码解释:
@Entity注解表示该类是一个实体类,在项目启动时会根据该类自动生成一张表,表的名称即@Entity注解中name的值,如果不配置name,默认表名为类名
所有的实体类都要有主键,@Id注解表示该属性是一个主键,@GneeratedValue注解表示主键自动生成,strategy则表示主键的生成策略
默认情况下,生成的表中字段的名称时实体类中属性的名称,通过@Column注解可以定制生成的字段的属性,name表示该属性对应的数据表中字段的名称,nullable表示该字段非空
@Transient注解表示在生成数据库的表时,该属性被忽略,即不生成对应的字段
JPA自带的几种主键生成策略:
TABLE:使用一个特定的数据库表格来保存主键
SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。这个值要于generator一起使用,generator指定生成主键的生成器
IDENTITY:主键由数据库自动生成(主要支持自动增长的数据库,如mysql)
AUTO:主键由程序控制,也是GenerationType的默认值
Dao层:
创建BookDao接口,继承JpaRepository,代码如下:
import com.example.demo.domain.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public interface BookDao extends JpaRepository<Book,Integer> {
//查询以某个字符开始的所有书
List<Book> getBooksByAuthorStartingWith(String author);
//查询单价大于某个值的所有书
List<Book> getBooksByPriceGreaterThan(Float price);
@Query(value = "select * from t_book where id=(select max(id) from t_book)",nativeQuery = true)
Book getMaxIdBook();
@Query("select b from t_book b where b.id>:id and b.author=:author")
List<Book> getBookByIdAndAuthor(@Param("author") String author,@Param("id") Integer id);
@Query("select b from t_book b where b.id<?2 and b.name like %?1%")
List<Book> getBookByIdAndName(String name,Integer id);
}
代码解释:
自定义BookDao继承自JpaRepositiory。JpaRepositiory中提供了一些基本的数据操作方法,有基本的增删改查、分页查询、排序查询等
在Spring Data JPA中,只要方法的定义符合既定规范,Spring Data就能分析出开发者意图,从而避免开发者定义SQL
Service层:
import com.example.demo.dao.BookDao;
import com.example.demo.domain.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
@Autowired
BookDao bookDao;
//save方法由JpaRepository接口提供
public void addBook(Book book){
bookDao.save(book);
}
//分页查询
public Page<Book> getBookByPage(Pageable pageable){
return bookDao.findAll(pageable);
}
public List<Book> getBooksByAuthorStartingWith(String author){
return bookDao.getBooksByAuthorStartingWith(author);
}
public List<Book> getBooksByPriceGreaterThan(Float price){
return bookDao.getBooksByPriceGreaterThan(price);
}
public Book getMaxIdBook(){
return bookDao.getMaxIdBook();
}
public List<Book> getBookByIdAndName(String name,Integer id){
return bookDao.getBookByIdAndName(name,id);
}
public List<Book> getBookByIdAndAuthor(String author,Integer id){
return bookDao.getBookByIdAndAuthor(author,id);
}
}
Controller层:
创建BookContrller,实现对数据的测试,代码如下:
import com.example.demo.domain.Book;
import com.example.demo.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class BookController {
@Autowired
BookService bookService;
@GetMapping(value = "/findAll")
public void findAll(){
PageRequest pageRequest = PageRequest.of(2,3);
Page<Book> page = bookService.getBookByPage(pageRequest);
System.out.println("总页数:"+page.getTotalPages());
System.out.println("总记录数:"+page.getTotalElements());
System.out.println("查询结果:"+page.getContent());
//从0开始记,所以加上1
System.out.println("当前页数:"+(page.getNumber()+1));
System.out.println("当前记录数:"+page.getNumberOfElements());
System.out.println("每页记录数:"+page.getSize());
}
@GetMapping(value = "search")
public void search(){
List<Book> bs1 = bookService.getBookByIdAndAuthor("鲁迅",7);
List<Book> bs2 = bookService.getBooksByAuthorStartingWith("吴");
List<Book> bs3 = bookService.getBookByIdAndName("西",8);
List<Book> bs4 = bookService.getBooksByPriceGreaterThan(30F);
Book b = bookService.getMaxIdBook();
System.out.println("bs1:"+bs1);
System.out.println("bs2:"+bs2);
System.out.println("bs3:"+bs3);
System.out.println("bs4:"+bs4);
System.out.println("b:"+b);
}
@GetMapping(value = "/save")
public void save(){
Book book = new Book();
book.setAuthor("鲁迅");
book.setName("呐喊");
book.setPrice(23F);
bookService.addBook(book);
}
}
代码解释:
在findAll接口中,首先通过调用PageRequest中的of方法构造PageRequest对象。of方法接收两个参数:第一个参数是页数,从0开始计数,第二个参数是每页显示的条数
分页
@Override
public List<Person> findAllPerson(String name, Integer currentPage, Integer pagesize) {
Pageable page = PageRequest.of(currentPage - 1, pagesize);
if(name==null || "".equals(name))
return personRepository.findAll(page).getContent();
return personRepository.findAllByName(name,page);
}
@Repository
public interface PersonRepository extends JpaRepository<Person,Integer> {
@Query(value = "select * from persion where name like %?1%",nativeQuery = true)
List<Person> findAllByName(String name, Pageable page);
@Query(value = "select * from persion where id = ?1",nativeQuery = true)
Person findByyid(Integer id);
@Modifying
@Transactional
@Query(value = "delete from persion where id in (?1)",nativeQuery = true)
void delall(String[] isd);
}