Spring Boot 实例:整合 Spring Data JPA

  • 首先 JPA(Java Persistence API)和Spring Data是两个范畴的概念, JPA
    和Hibernate的关系就像JDBC
    域JDBC驱动的关系,即JPA制定了ORM规范,Hibernate是这些规范的实现,因此从功能上来讲JPA相当于Hibernate的一个子集
  • Spring Data是Spring 的一个子项目,致力于简化数据库的访问,通过规范的方法名来分析开发者的意图,本实例步骤如下:

step.1

创建数据库jpa:

CREATE DATABASE `jpa` CHARACTER SET 'utf8';

step.2

创建spring boot 项目,添加mysql 和spring data jpa 的倚赖:

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.9</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

step.3

数据库配置:

  • 在application.properties中配置数据库的基本信息以及jpa相关配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql:///jpa?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
  • 1~4行是数据库基本信息
  • 第5行表示是否在控制台打印jpa执行过程生成的sql
  • 第6行表示jpa对应的数据库是mysql
  • 第7行表示在项目启动时根据实体类更新数据库中的表

step.4

创建实体类Book:

@Entity(name = "t_book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "book_name",nullable = false)
    private String name;
    private String author;
    private Float price;
    @Transient
    private String description;
    //省略getter/setter

  • @Entity注解表示该类是一个实体类,项目启动时会自动创建一张表,表的名称就是后面name的值,如果没有定义name,那么表名将默认使用类名
  • @Id 表示主键,GeneratedValue表示主键自动生成,strategy 表示生成策略
  • @Column表示注解可以定制字段的属性
  • @Transient表示自动生成表时忽略改字段

step.5

创建BookDao接口,继承JpaRepository

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> getBooksByIdAndName(String name, Integer id);
}

解释如下:

  • 自定义BookDao 继承JpaRepository,其中JpaRepository中已经提供了一些基本的如增删改查的基本数据操作方法
  • 第二行定义的方法表示查询以某个字符开始的所有书
  • 第三行定义的方法表示查询单价大于某个值的所有书
  • 在Spring Data Jpa中只要方法的定义符合规范,就是一定的方法命名规则,支持的命名规则如下表所示:
KeyWords方法命名举例对应的SQL
AndfindByNameAndAgewhere name = ? and age = ?
OrfindByNameOrAgewhere name = ? or age = ?
IsfindByAgeIswhere age = ?
EqualsfindByIdEqualswhere id=?
BetweenfindByAgeBetweenwhere age between ? and ?
LessThanfindByAgeLessThanwhere age <?
GreaterThanfindByAgeGreaterThanwhere age >?
GreaterThanEqualsfindByAgeGreaterThanEqualswhere age >=?
LessThanEqualsfindByAgeLessThanEqualswhere age <=?
AfterfindByAgeAfterwhere age >?
BeforefindByAgeBeforewhere age <?
IsNullfindByNameIsNullwhere name is null
isNotNull,NotNUllfindByNameNotNullwhere name is not null
NotfindByGenderNotwhere gender <>?
NotInfindByAgeNotInwhere age not in (?)
NotLikefindByNameNotLikewhere name not like ?
LikefindByNameLikewhere name like ?
StartingWithfindByNameStartingWithwhere name like ‘?%’
EndingWithfindByNameEndingWithwhere name like ‘%?’
Containing,ContainsfindByNameContainingwhere name like ‘?%?’
OrderByfindByAgeGreaterThanOrderByIdDescwhere age >? order by id desc
TruefindByEnabledTruewhere enabled =true
FalsefindByEnabledFalsewhere enabled =false
IgnoreCasefindByNameIgnoreCasewhere UPPER(name)=UPPER(?)
  • 既定的方法名不一定能满足所有的开发需求,因此Spring Data JPA 也支持自定义JPQL (java persistence query language)或者原生sql,第4~6行表示查询id最大的书,nativeQuery = true表示使用原生的sql查询
  • 第7~9行表示根据id和author进行查询,这里使用默认的JPQL进行查询,通过类名和属性名进行访问,而不是通过表明和表的属性,使用:id,:name进行参数绑定,需要注意的是这里使用的列名是属性的名称而不是数据库中列的名称
  • 第10,11行也是自定义JPQL查询,不同的是传参方式使用?1,?这种方式
  • 如果BokDao中涉及修改操作,则需要添加@Modifying注解并添加事务。

Step. 6

创建BookService:

@Service
public class BookService {
    @Autowired
    BookDao bookDao;
    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> getBookByIdAndAuthor(String author, Integer id){
        return bookDao.getBookByIdAndAuthor(author, id);
    }
    public List<Book> getBooksByIdAndName(String name, Integer id){
        return bookDao.getBooksByIdAndName(name, id);
    }
}
  • 其中第六行的save方法建对象数据保存到数据库save方法是由JpaRepository接口提供的
  • 第九行是一个分页查询,fandAll方法的返回值是Page< Book>

step.7

创建BookController:

@RestController
public class BookController {
    @Autowired
    BookService bookService;
    @GetMapping("/findAll")
    public void findAll() {
        PageRequest pageable = PageRequest.of(2, 3);
        Page<Book> page = bookService.getBookByPage(pageable);
        System.out.println("总页数:"+page.getTotalPages());
        System.out.println("总记录数:"+page.getTotalElements());
        System.out.println("查询结果:"+page.getContent());
        System.out.println("当前页数:"+(page.getNumber()+1));
        System.out.println("当前页记录数:"+page.getNumberOfElements());
        System.out.println("每页记录数:"+page.getSize());
    }
    @GetMapping("/search")
    public void search() {
        List<Book> bs1 = bookService.getBookByIdAndAuthor("鲁迅", 7);
        List<Book> bs2 = bookService.getBooksByAuthorStartingWith("吴");
        List<Book> bs3 = bookService.getBooksByIdAndName("西", 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("/save")
    public void save() {
        Book book = new Book();
        book.setAuthor("鲁迅");
        book.setName("呐喊");
        book.setPrice(23F);
        bookService.addBook(book);
    }
}

  • 在findAll中首先需要调用PageRequest 中的of方法构造PageRequest
    对象,of方法接受两个参数,第一个是页数,从0开始,第二个是每页显示的条数
  • 在save接口中构造一个Book对象,直接调用save方法进行保存

step.8

测试:
加入数据
在这里插入图片描述

  1. 输入http://localhost:8080/findAll,结果如下
总页数:2
总记录数:4
查询结果:[Book{id=1, name='三国演义', author='罗贯中', price=99.0, description='null'}, Book{id=2, name='西游记', author='六小龄童', price=999.0, description='null'}, Book{id=3, name='鸡你太美', author='cxk', price=9999.0, description='null'}]
当前页数:1
当前页记录数:3
每页记录数:3

  1. 接下来调用http://localhost:8080/save接口,调用后数据更新如图:
    在这里插入图片描述
  2. 接下来调用http://localhost:8080/search 接口,查询结果如下:
bs1:[Book{id=3, name='鸡你太美', author='cxk', price=9999.0, description='null'}]
bs2:[Book{id=6, name='呐喊', author='鲁迅', price=23.0, description='null'}]
bs3:[Book{id=2, name='西游记', author='六小龄童', price=999.0, description='null'}]
bs4:[Book{id=1, name='三国演义', author='罗贯中', price=99.0, description='null'}, Book{id=2, name='西游记', author='六小龄童', price=999.0, description='null'}, Book{id=3, name='鸡你太美', author='cxk', price=9999.0, description='null'}, Book{id=6, name='呐喊', author='鲁迅', price=23.0, description='null'}]
b:Book{id=6, name='呐喊', author='鲁迅', price=23.0, description='null'}

注意:其中数据源的不同可能会导致查询不到结果等问题,可在BookDao中自行改动数据库语句

实例结构

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值