如果饿了就吃,困了就睡,渴了就喝,人生就太无趣了
源码地址:https://github.com/keer123456789/springbootstudy/tree/master/jpa_demo
本人刚刚接触jpa,如有错误,欢迎大家指正!!
1.JPA介绍
JPA(Java Persistence API)Java持久化API,是 Java 持久化的标准规范,Hibernate是持久化规范的技术实现,而Spring Data JPA是在 Hibernate 基础上封装的一款框架。JPA作为标准,实际上并没有说局限于某个固定的数据源,事实上mysql,mongo, solr都是ok的。接下来我们将介绍下springboot结合jpa 来实现mysql的curd以及更加复杂一点的sql支持
2.环境配置
2.1 数据库配置
数据库选择mysql
数据库。并新建一个数据库jpademo1
。如图
2.2 SpringBoot pom 配置
mysql
依赖中的版本根据自己的mysql
版本配置。
<dependencies>
<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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
2.3 MySQL数据源配置
mysql的基本配置,不再过多解释。
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jpademo?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
2.4 jpa配置
每个属性的解释都在注释中,
spring.jpa.show-sql
建议开启,这个会在日志中打印sql语句,对之后的调试很有帮助。- ddl-auto:update 每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新
# JPA配置
spring.jpa.database=mysql
# 在控制台打印SQL
spring.jpa.show-sql=true
# 数据库平台
spring.jpa.database-platform=mysql
# 每次启动项目时,数据库初始化策略
spring.jpa.hibernate.ddl-auto=update
# 指定默认的存储引擎为InnoDB
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
3.Entity介绍
JPA提供了实体与库表的映射关系。只需要使用@Entity
注解即可。
@Entity
- 声明这个POJO是一个与数据库中叫做
user
的表关联的对象. - 参数name,用于指定表名,如果不主动指定时,默认用类名,即上面如果不指定那么,那么默认与表 user 绑定
- 声明这个POJO是一个与数据库中叫做
@Column
- 这个注解就是用来解决我们pojo成员名和数据库列名不一致的问题的
- name参数填写表名
- nullable参数是表示该列是否可以为空
- 主键注解
@Id
注解 表示这个列是主键,关系型数据中很重的。@GeneratedValue
设置初始值,谈到主键,我们一般会和”自增“这个一起说,所以你经常会看到的取值为strategy = GenerationType.IDENTITY
(由数据库自动生成)
这个注解提供了四种形式,关于这几种使用姿势,这里不详细展开了,有兴趣的可以可以看一下这博文: @GeneratedValue
取值 | 说明 |
---|---|
GenerationType.TABLE |
使用一个特定的数据库表格来保存主键 |
GenerationType.SEQUENCE |
根据底层数据库的序列来生成主键,条件是数据库支持序列 |
GenerationType.IDENTITY |
主键由数据库自动生成(主要是自动增长型) |
GenerationType.AUTO |
主键由程序控制 |
@Entity(name = "user")
public class User {
@Column(name = "name", nullable = false)
private String name;
@Column(name = "password", nullable = false)
private String password;
@Column(name = "address", nullable = false)
private String address;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
", address='" + address + '\'' +
", id=" + id +
'}';
}
}
4.增删改查
jpa只需要继承一个接口即可完成DB的操作。这次继承的CrudRepository类。这样就可以实现很多操作。
@Component
public interface UserDao extends CrudRepository<User, Integer> {
}
4.1 Select
由于继承了CrudRepository
接口,这个接口提供了三个查询方法,如图
- 查询表中所有
User
信息 - 根据主键查询相应的
User
- 根据一组主键查询相应的信息。
这单单是此接口实现的根据主键查询的方法,jpa具有强大的查询功能,实现了GroupBy,having
等等高级的sql查询功能,这些功能会在之后的博客中介绍……
这次简单的介绍findAll()
的功能。在Service层进行查询。查寻完成之后返回给controller
,即可,webResult
返回请求的自定义的值。具体的就不在介绍,可以自行去项目中查看。
public WebResult selectAllUsers(){
List<User> users= (List<User>) userDao.findAll();
WebResult webResult=new WebResult();
webResult.setStatus(WebResult.SUCCESS);
webResult.setMessage("查询成功");
webResult.setData(users);
logger.info("查询成功,数据:"+users.toString());
return webResult;
}
如图,可以看到查询语句
数据库中的数据和日志打印出来的数据:
4.2 Insert
1.插入单个数据
public WebResult addUser(User user) {
User res = userDao.save(user);
WebResult result = new WebResult();
if (res != null) {
result.setData(user);
result.setMessage("增加成功");
result.setStatus(WebResult.SUCCESS);
return result;
}
return null;
}
- 调用接口的
save()
方法。入参是需要增加的User信息
进行测试:
测试数据:
#增加用户信息
POST http://127.0.0.1:8080/jpa/addUser
Content-Type: application/json
{
"id": 4,
"name": "keer",
"password": "133333",
"address": "北京市平谷区"
}
测试结果:
- 先根据id进行查询(防止主键重复,这是一种可能,原因在update的时候在深入解释)。
- 然后在进行插入操作
2.批量插入
同样是调用接口已经有的方法,saveAll()
方法,入参是User的list数组
public WebResult addUsers(List list) {
WebResult webResult = new WebResult();
userDao.saveAll(list);
List<User> failUsers = new ArrayList<>();
for (Object o : list) {
User user = (User) o;
if (!userDao.existsById(user.getId())) {
failUsers.add(user);
}
}
if (failUsers.size() == 0) {
webResult.setStatus(WebResult.SUCCESS);
webResult.setMessage("插入成功");
} else {
webResult.setMessage("部分插入失败");
webResult.setData(failUsers);
webResult.setStatus(WebResult.ERROR);
}
return webResult;
}
进行测试:
测试数据:
#批量增加用户
POST http://127.0.0.1:8080/jpa/addUsers
Content-Type: application/json
[
{
"name": "可耳",
"password": "love",
"address": "北京市"
},
{
"name": "java",
"password": "hello world",
"address": "main()"
}
]
测试结果:
- 这次没有指明主键id,因为是自增主键,所以就自动生成了
- 日志中的select语句,是因为调用了
existsById()
方法进行查询是否存在。
4.3 Delete
删除操作直接调用接口中的delete()
方法,入参是user实例
public WebResult removeUser(User user) {
userDao.delete(user);
WebResult webResult = new WebResult();
if (!userDao.existsById(user.getId())) {
webResult.setStatus(WebResult.SUCCESS);
webResult.setMessage("删除用户信息成功!");
} else {
webResult.setStatus(WebResult.ERROR);
webResult.setMessage("删除用户信息失败!");
}
return webResult;
}
进行测试:
测试数据:
#删除用户
POST http://127.0.0.1:8080/jpa/deleteUser
Content-Type: application/json
{
"name": "java",
"password": "hello world",
"address": "main()",
"id": 6
}
测试结果:
- 日志中首先使用主键进行了查询
- 之后再进行删除
- 日志中的select语句,是因为调用了
existsById()
方法进行查询是否存在。
4.4 Updata
1.使用save()
方法,数据必须带有主键,而且需要user中带有全部数据,这样才能进行update。
public WebResult updateUser(User user) {
WebResult webResult = new WebResult();
User newUser = userDao.save(user);
logger.info("更新信息:" + newUser.toString());
webResult.setMessage("更新操作成功");
webResult.setData(newUser);
webResult.setStatus(WebResult.SUCCESS);
return webResult;
}
进行测试:
测试数据:
POST http://127.0.0.1:8080/jpa/updateUser
Content-Type: application/json
{
"id": 1,
"name": "keer",
"password": "133333",
"address": "北京市平谷区"
}
测试结果:
- 日志中首先使用主键进行了查询(回答上面的问题,查询这个id对应的记录是否存在,存在就是update,不存在就是insert)