SpringBoot——JPA学习笔记

前言

使用过Hibernate的同学应该知道,Hibernate的作用就是面向对象写SQL,Hibernate要求我们尽量关注与对象之间的关系,封装底层的数据库,用对象之间的映射关系去建立表之间的联系。

而JPA与Hibernate十分相似,也是可以利用对象来直接操作数据库。它只需要极其简单的几个类就可以完成对一个对象的CURD操作。具体如何简单,且看接下来的步骤。

 

引入JPA依赖

构建好SpringBoot项目之后,引入JPA以及mysql-connector依赖。

<!-- JPA --> 
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-data-jpa</artifactId> 
</dependency> 
<!-- mysql-connector --> 
<dependency> 
    <groupId>mysql</groupId> 
    <artifactId>mysql-connector-java</artifactId> 
    <scope>runtime</scope> 
</dependency>

 

配置数据源及JPA

接下来就需要配置好数据库的连接以及JPA的各项配置

# 数据源配置 
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC 
spring.datasource.username=root 
spring.datasource.password=mysql 
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 
# JPA配置 
# 配置方言,即操作哪种数据库,支持MySql,Oracle等 
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect 
# 配置是否显示sql语句,调试时可以配置为true 
spring.jpa.show-sql=true 
# 配置执行模式,可选create、update 
spring.jpa.hibernate.ddl-auto=create

 

此处JPA像Hibernate配置一样,需要配置方言,也可以配置是否显示sql语句

 

创建实体类

创建一个我们常用的用户类,User

package com.demo.jpademo.entity;


import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author chenxiaotao
 * @version 1.0
 * @date 2019/3/25 15:52
 **/
@Entity
@Table(name = "USER")
public class User {

    @Id()
    private Long id;
    @Column(length = 32)
    private String name;
    @Column(length = 16)
    private String account;
    @Column(length = 32)
    private String pwd;

}

 

部分注解解释:

@Entity:注解该类为一个实体类

@Table:标识所对应的数据表名

@Id:标识该属性为主键

@Column:标识该属性为字段,并可以指明字段的长度

 

到这里,我们可以说已经创建好了一个表,你可以尝试运行一下SpringBoot,可以在控制台看到这样两条输出语句

Hibernate: drop table if exists user 
Hibernate: create table auth_user (id bigint not null, account varchar(16), name varchar(32), pwd varchar(32), primary key (id)) engine=InnoDB

此处的 drop table if exists user 语句,是因为我们之前的 spring.jpa.hibernate.ddl-auto 配置项配置为了 create

 

可以用navicat看到,JPA帮我们创建了一张user表,节省了我们先去创建表后创建实体类这样一个过程,接下来更加强大的是JPA的快速构建CURD功能

 

创建DAO

创建一个UserDAO接口并继承 JpaRepository<Entity, ID> 接口,这里两个泛型,第一个表示的是实体类,第二个表示的实体类的ID字段类型

package com.demo.jpademo.dao;

import com.demo.jpademo.entity.User;
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.Repository;

import java.util.List;
import java.util.Optional;

/**
 * @author chenxiaotao
 * @version 1.0
 * @date 2019/3/25 16:02
 **/
@Repository
public interface UserDao extends JpaRepository<User, Long> {

}

 

好了,到这里一个具有CURD的DAO类就已经创建好了。并没有在开玩笑,不信的话,我们来进行测试。

 

测试DAO

 

新建一个测试类 UserDOTest

package com.demo.jpademo;

import com.demo.jpademo.dao.UserDao;
import com.demo.jpademo.entity.User;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author chenxiaotao
 * @version 1.0
 * @date 2019/3/25 16:04
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserDOTest {

    @Autowired
    private UserDao userDao;

    @Before
    public void before() {
        User userDO = new User();
        userDO.setId(5L);
        userDO.setName("向问天");
        userDO.setAccount("wentian");
        userDO.setPwd("123456");
        userDao.save(userDO);
    }

    @Test
    public void testAdd() {
        User userDO = new User();
        userDO.setId(1L);
        userDO.setName("风清扬");
        userDO.setAccount("fengqy");
        userDO.setPwd("123456");
        userDao.save(userDO);
        userDO = new User();
        userDO.setId(3L);
        userDO.setName("东方不败");
        userDO.setAccount("bubai");
        userDO.setPwd("123456");
        userDao.save(userDO);
    }

    @Test
    public void testUpdate() {
        User userDO = new User();
        userDO.setId(5L);
        userDO.setName("小涛");
        userDO.setAccount("xiaotao");
        userDO.setPwd("123456");
        userDao.save(userDO);

    }

    @Test
    public void testDelete() {
        userDao.deleteById(5L);
    }

    @Test
    public void testFindAll() {
        userDao.findAll();
    }


}

 

  运行,就可以看到下列输出,证明一个CURD已经完成,是不是十分的神奇,实际上Spring是利用了AOP以及反射(当然不会直接用反射,会用其他方式如二进制加快读取对象信息)等工具来帮助我们快速实现这个DAO类,只能说屌得一批。

SpringBoot——JPA学习笔记

  此处还有一个问题,为什么我只是insert,却会输出一个select语句(delete也会),这里我们可以看源码,在SimpleJpaRepository类中,我们可以看到save、delete等方法的源码,可以看到它在执行save执行执行了一次isNew去判断这个对象在数据库中是否已经存在,如果存在,则会进行一次更新操作,所以它在每次insert前都会进行一次select操作。

  而delete方法中,一样有这样一段源码,不过方式有些不同,此处涉及一级缓存等概念,可自行查阅。

SpringBoot——JPA学习笔记

 

简单的一对多实现

关联关系是十分常见的一种情况,比如一个作者有多篇文章,一篇文章对应着一个作者,这种关联关系在数据库种以外键的形式存在。而在面向对象中,则可以用以下方式进行表示

 

Author(作者):

package com.demo.jpademo.entity;


import javax.persistence.*;
import java.util.List;

/**
 * @author chenxiaotao
 * @version 1.0
 * @date 2019/3/25 17:53
 **/
@Entity
@Table(name = "author")
public class Author {

    /**
     * 表格主键,strategy:id策略 (此处为自增)
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    /**
     * 姓名
     */
    @Column(nullable = false, length = 20)
    private String name;

    /**
     * mapperBy可以理解为主从关系
     * 可以简单理解为这些aricleList被author所拥有
     */
    @OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
    private List<Article> articleList;
}

Article(文章):

package com.demo.jpademo.entity;

import javax.persistence.*;

/**
 * @author chenxiaotao
 * @version 1.0
 * @date 2019/3/25 17:56
 **/
@Entity
@Table(name = "article")
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50)
    private String title;

    /**
     * \@Lob 注解为大对象,映射MySQL的LongText类型
     * \@Basic(fetch = FetchType.LAZY) 懒加载
     */
    @Lob
    @Basic(fetch = FetchType.LAZY)
    @Column(nullable = false)
    private String content;

    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH}, optional = false)
    @JoinColumn(name = "author_id")
    private Author author;
}

 

这里还涉及到 cascade(配置),可以自行深入了解一下。这样,就创建好了一个一对多个关系,利用navicat可看到数据库中对这两个对象的关系表示为:

 

SpringBoot——JPA学习笔记

SpringBoot——JPA学习笔记

总结

  SpringBoot-JPA可以加少我们许多的开发工作,可以让我们更加专注于对象与对象之间的关联关系,在快速开发一个应用上十分有效,但可能对需要SQL优化的大型应用不太友好,Mybatis可能对大型应用来说才是更好的选择,所以抛开业务谈技术都是耍流氓,还是得根据实际来,如果你只想做个课程设计,去深入了解下JPA更多的特性(比如:Cascade级联属性,自定义@Query查询),然后利用SpringBoot+JPA+Web就可以快速帮你搭建好一个后端服务了。