第十五节:SpringBoot使用JPA访问数据库
JPA是Java Persistence API的简写,是官方提出的一种ORM规范!
JPA规范,都在包路径:
javax.persistence.*
下,像一些常用的如:@Entity、@Id及@Transient都在此路径下。这些也是一些现在市面上常用的ORM一些约定俗成的注解了。
Spring Data JPA是Spring基于Hibernate开发的一个JPA框架。可以极大的简化JPA的写法,可以在几乎不用写具体代码的情况下,实现对资料的访问和操作。除了「CRUD」外,还包括如分页、排序等一些常用的功能。
pom.xml中添加依赖
org.springframework.bootspring-boot-starter-data-jpamysqlmysql-connector-java
application.properties 配置
spring.datasource.url=jdbc:mysql://localhost:3306/rumenz_springboot
spring.datasource.username=root
spring.datasource.password=root1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.jpa.hibernate.ddl-auto=update
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:/ddl/user-book.sql
spring.sql.init.data-locations=classpath:/ddl/user-book-data.sql
spring.jpa.hibernate.ddl-auto 是否根据实体类更新数据库,有四个属性值
属性值 | 作用 |
---|---|
create | 每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。 |
create-drop | 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 |
update | 最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。 |
validate | 每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 |
spring.sql.init.mode 是否使用sql文件初始化数据库,有3个值
属性值 | 作用 |
---|---|
ALWAYS | 始终初始化数据库。 |
EMBEDDED | 仅初始化嵌入式数据库。 |
NEVER | 永远不要初始化数据库。 |
- spring.sql.init.schema-locations 指定建表的sql文件
- spring.sql.init.data-locations指定数据sql文件
创建实体类
User.java
@Getter
@Setter
@Builder
@AllArgsConstructor
@Entity //jpa必填
@DynamicInsert //填充默认值
@DynamicUpdate //填充默认值
@Table(name = "user") //jpa必填
@NoArgsConstructor
public class User {@Id //jpa必填@GeneratedValue(strategy = GenerationType.IDENTITY) //jpa必填private Integer id;private String name;private String domain;@Column(name = "age",columnDefinition = "tinyint default 0")private Integer age;
}
@GeneratedValue(strategy = GenerationType.IDENTITY)
有以下几种类型
- TABLE:使用一个特定的数据库表格来保存主键。
- SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
- IDENTITY:主键由数据库自动生成(主要是自动增长型)
- AUTO:主键由程序控制。
创建repository
数据持久层,负责访问数据库,在这里声明的方法一般不用实现,只要按照Jpa的规范就可以自动生成SQL语句。
package com.rumenz.lession15.controller.repository;import com.rumenz.lession15.controller.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;import java.util.List;
import java.util.Optional;/*** @className: UserRepository* @description: TODO 类描述* @author: 入门小站 rumenz.com* @date: 2021/12/14**/@Repository
public interface UserRepository extends PagingAndSortingRepository {Optional findById(Integer id);List findDistinctUserByName(String name);Integer countUserByName(String name);List readDistinctByName(String name);Page findAllByName(String name, Pageable pageable);
}
Jpa
可以通过接口名生成对应的sql语句,如 find… By,read… By,query… By,count… By,和get… By 。这些方法可以包含其他表达式,例如在要创建的查询上设置 Distinct 标志。第一个 By 用作分隔符,表示条件的开始,后面定义实体属性的各种条件,并将它们用 And 和 Or 连接起来。例如:
interface RumenzRepository extends JpaRepository {List findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);// 为查询启用 distinct 标志List findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);List findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);// 为单个属性启用忽略大小写List findByLastnameIgnoreCase(String lastname);// 为所有属性启用忽略大小写List findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);// 为查询启用静态 Order byList findByLastnameOrderByFirstnameAsc(String lastname);List findByLastnameOrderByFirstnameDesc(String lastname);
}
举一些例子
关键字 | 方法示例 | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is, Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull, Null | findByAge(Is)Null | … where x.age is null |
IsNotNull, NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection ages) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
Repository有3种
JpaRepository继承PagingAndSortingRepository,PagingAndSortingRepository继承CrudRepository。
- CrudRepository提供CRUD的功能
- PagingAndSortingRepository提供分页和排序功能
- JpaRepository提供JPA相关的方法,如刷新持久化数据、批量删除等。
service
业务逻辑层,负责调用
Repository
处理数据完成业务。
package com.rumenz.lession15.controller.service;import com.rumenz.lession15.controller.entity.User;
import org.springframework.data.domain.Page;import java.util.List;/*** @className: UserService* @description: TODO 类描述* @author: 入门小站 rumenz.com* @date: 2021/12/14**/
public interface UserService {Integer save(User user);User get(Integer id);List listByName(String name);Integer countByName(String name);List readDistinctByName(String name);Page listByNamePage(String name, Integer page, Integer pageSize);
}//实现类package com.rumenz.lession15.controller.service.lmpl;import com.rumenz.lession15.controller.entity.User;import com.rumenz.lession15.controller.repository.UserRepository;
import com.rumenz.lession15.controller.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Optional;/*** @className: UserServiceImpl* @description: TODO 类描述* @author: 入门小站 rumenz.com* @date: 2021/12/14**/
@Service
public class UserServiceImpl implements UserService {@AutowiredUserRepository userRepository;@Overridepublic Integer save(User user) {User save = userRepository.save(user);return save.getId();}@Overridepublic User get(Integer id) {Optional opt = userRepository.findById(id);return opt.isPresent()?opt.get():null;}@Overridepublic List listByName(String name) {List res = userRepository.findDistinctUserByName(name);return res;}@Overridepublic Integer countByName(String name) {return userRepository.countUserByName(name);}@Overridepublic List readDistinctByName(String name) {return userRepository.readDistinctByName(name);}@Overridepublic Page listByNamePage(String name, Integer page, Integer pageSize) {Sort sort = Sort.by("id").descending();Pageable pageable= PageRequest.of(page-1, pageSize, sort);Page res = userRepository.findAllByName(name, pageable);return res;}
}
Controller
前端控制器,负责接收前端请求,调用
service
,返回数据。
package com.rumenz.lession15.controller;import com.rumenz.lession15.controller.entity.User;
import com.rumenz.lession15.controller.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @className: RumenzController* @description: TODO 类描述* @author: 入门小站 rumenz.com* @date: 2021/12/14**/
@RestController
@RequestMapping("/rumenz")
public class RumenzController {@AutowiredUserService userService;//保存数据//id=1的数据不存在就添加//id=1的数据存在就更新@RequestMapping("/save")public String save(){User user=User.builder().id(1).name("入门小站123").domain("https://rumenz.com").build();Integer save = userService.save(user);return save.toString();}//通过id查询数据@GetMapping("/get")public User get(@RequestParam("id") Integer id){return userService.get(id);}//带条件查询@GetMapping("/listByName")public List get(@RequestParam("name") String name){return userService.listByName(name);}//按条件查询符合条件的数量@GetMapping("/countByName")public Integer countByName(@RequestParam("name") String name){return userService.countByName(name);}//带条件查询@GetMapping("/readDistinctByName")public List readDistinctByName(@RequestParam("name") String name){return userService.readDistinctByName(name);}//分页查询//带条件查询@GetMapping("/listByNamePage")public Page listByNamePage(@RequestParam("name") String name, @RequestParam("page") Integer page, @RequestParam("pageSize") Integer pageSize){return userService.listByNamePage(name,page,pageSize);}}
本小结源码地址:
- GitHub:https://github.com/mifunc/springboot/tree/main/lession15
- Gitee:https://gitee.com/rumenz/springboot/tree/master/lession15
- https://rumenz.com/rumenbiji/springboot-jpa-base.html
介绍
- 我的博客 https://rumenz.com/ ,
- 我的工具箱 https://tooltt.com/
- 微信公众号:【入门小站】
- 关注【入门小站】回复【1001】获取 linux常用命令速查手册
- 关注【入门小站】回复【1003】获取 LeetCode题解【java语言实现】
- 关注【入门小站】回复【1004】获取 Java基础核心总结
- 关注【入门小站】回复【1009】获取 阿里巴巴Java开发手册
第十五节:SpringBoot使用JPA访问数据库相关推荐
- Springboot 系列(十)使用 Spring data jpa 访问数据库
前言 Springboot data jpa 和 Spring jdbc 同属于 Spring开源组织,在 Spring jdbc 之后又开发了持久层框架,很明显 Spring data jpa 相对 ...
- 第十六节 springboot 打包vue代码实现前后端统一部署
svbadmin学习日志 本学习日志是使用Springboot和Vue来搭建的后台管理系统: 演示地址:http://118.31.68.110:8081/index.html 账号:root 密码: ...
- Python编程基础:第三十五节 文件删除Delete a File
第三十五节 文件删除Delete a File 前言 实践 前言 我们这一节来介绍如何删除一个文件,这里需要用到函数os.remove(path)用于删除指定路径下的文件,os.rmdir(path) ...
- Python编程基础:第十五节 二维列表2D Lists
第十五节 二维列表2D Lists 前言 实践 前言 列表中的元素可以是任何形式,整型.浮点型.字符串型,甚至是一个列表.当列表的元素也是列表时,我们将其称为二维列表. 实践 我们先来创建多个一维列表 ...
- Spring Boot (十五): Spring Boot + Jpa + Thymeleaf 增删改查示例
<p>这篇文章介绍如何使用 Jpa 和 Thymeleaf 做一个增删改查的示例.</p> 先和大家聊聊我为什么喜欢写这种脚手架的项目,在我学习一门新技术的时候,总是想快速的搭 ...
- Python编程基础:第五十五节 map函数Map
第五十五节 map函数Map 前言 实践 前言 map函数的作用是将指定函数作用于一个可迭代对象内部的每一个元素,其表达方式为map(function, iterable),第一个位置指定作用函数,第 ...
- Python编程基础:第四十五节 方法链Method Chaining
第四十五节 方法链Method Chaining 前言 实践 前言 方法链是指一个对象一次调用其自身的多个方法,通常写作对象.方法1.方法2.由于这种调用方法看起来像一个链条,所以我们将其称作方法链. ...
- Python编程基础:第二十五节 args参数*args
第二十五节 args参数*args 前言 实践 前言 我们目前学习到的函数的参数个数都是固定的,那么我们是否可以指定任意多个参数呢?其实是可以的,这里就用到了args参数,它可以将用户指定的任意多个参 ...
- 第三百四十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—爬虫和反爬的对抗过程以及策略—scrapy架构源码分析图...
第三百四十五节,Python分布式爬虫打造搜索引擎Scrapy精讲-爬虫和反爬的对抗过程以及策略-scrapy架构源码分析图 1.基本概念 2.反爬虫的目的 3.爬虫和反爬的对抗过程以及策略 scra ...
最新文章
- bzero, memset ,setmem 区别
- 杭电2063--过山车(二分匹配)
- qt判断读入的字符串是否含有英文_459. 重复的子字符串
- USTC English Club Note20211108
- 解决IE6、IE7、Firefox兼容最简单的CSS Hack
- dll 重新加密打包的问题
- Eclipse Web开发出现莫名其妙错误
- iOS提交TestFlight测试显示缺少合规证明
- Notepad ++添加到每一行
- 基于物联网的温度采集系统(一):底层感知网络搭建
- ubuntu16.04安装搜狗拼音输入法
- Python 交通仿真建模(1)
- 适用于开发者的开源分布式即时通讯系统
- 国外的号码如何批量加入通讯录,Excel表格如何批量导入安卓苹果手机通讯录,如何快速的添加whatsApp,下面介绍具体的方法和软件
- unity 和安卓互相交互
- 通过Burp以及自定义的Sqlmap Tamper进行二次SQL注入
- python教程十一 元组
- Java教程:RabbitMq如何开启发布手动确认模式,采用及时或异步方式确定消息是否发送到队列
- JAVAMail 使用imap协议分析邮件
- 一阶低通滤波器方程_一阶低通滤波器c语言
热门文章
- 优美的函数式语言Haskell
- 深入继承之抽象类和接口综合分析及完整案列解说(一)
- ubuntu12.04循环登录,无法进桌面的问题。
- LeetCode344. Reverse String
- shell脚本一键安装nginx[最终版]
- zabbix分布式监控环境搭建
- View 5.1 重装上阵(3—用户体验篇)
- 《设计的品格 探索×呈现×进化的InDesign美学》—第1课1.3节文字游戏
- 从零开始学做微信小程序,看这些就够了!
- centos6.5 升级python2.6到python2.7