Spring Boot+Spring Data JPA

Spring Boot+Spring Data JPA

1.JPA

JPA是什么?

  1. Java Persistence API:用于对象持久化的 API
  2. Java EE 5.0 平台标准的 ORM 规范,使得应用程序以统一的方式访问持久层
Spring Boot+Spring Data JPA_第1张图片
image

JPA和Hibernate的关系

  1. JPA 是 Hibernate 的一个抽象(就像JDBC和JDBC驱动的关系);
  2. JPA 是规范:JPA 本质上就是一种 ORM 规范,不是ORM 框架,这是因为 JPA 并未提供 ORM 实现,它只是制订了一些规范,提供了一些编程的 API 接口,但具体实现则由 ORM 厂商提供实现;
  3. Hibernate 是实现:Hibernate 除了作为 ORM 框架之外,它也是一种 JPA 实现
  4. 从功能上来说, JPA 是 Hibernate 功能的一个子集

JPA的优势

  1. 标准化: 提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。
  2. 简单易用,集成方便: JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样简单,只需要使用 javax.persistence.Entity 进行注解;JPA 的框架和接口也都非常简单。
  3. 可媲美JDBC的查询能力: JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
  4. 支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型

JPA包含的技术

  1. ORM 映射元数据:JPA 支持 XML 和 JDK 5.0 注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。
  2. JPA 的 API:用来操作实体对象,执行CRUD操作,框架在后台完成所有的事情,开发者从繁琐的 JDBC 和 SQL 代码中解脱出来。
  3. 查询语言(JPQL):这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序和具体的 SQL 紧密耦合

2.Spring Data

Spring Data 是 Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。Spring Data 具有如下特点:

1.SpringData 项目支持 NoSQL 存储:
MongoDB (文档数据库)
Neo4j(图形数据库)
Redis(键/值存储)
Hbase(列族数据库)

2.SpringData 项目所支持的关系数据存储技术:
JDBC
JPA

3.Spring Data Jpa 致力于减少数据访问层(DAO)的开发量。开发者唯一要做的,就是声明持久层的接口,其他都交给 Spring Data JPA 完成。比如:当有一个UserDao.findUserById()这样一个方法声明,大致应该能判断出这是根据给定条件的 ID 查询出满足条件的 User 对象。Spring Data JPA做的便是规范方法的名字,根据符合规范的名字来确定方法需要实现什么样的逻辑。

3.Spring Boot整合Spring Data JPA

添加依赖、配置datasource和JPA


    org.springframework.boot
    spring-boot-starter-jdbc
 
 
    mysql
    mysql-connector-java
    runtime
 
 
    com.alibaba
    druid-spring-boot-starter
    1.1.10
 

spring.datasource.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# 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

创建实体类

ORM(Object Relational Mapping)框架表示对象关系映射,使用ORM框架我们不必再去创建表,框架会自动根据当前项目中的实体类创建相应的数据表。因此,我这里首先创建一个User对象,如下:

@Data
@Entity(name = "t_book")
public class book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "name")
    private String name;
    private String author;
}

@Entity注解表示这是一个实体类,那么在项目启动时会自动针对该类生成一张表,默认的表名为类名,@Entity注解的name属性表示自定义生成的表名。@Id注解表示这个字段是一个id,@GeneratedValue注解表示主键的自增长策略,对于类中的其他属性,默认都会根据属性名在表中生成相应的字段,字段名和属性名相同,如果开发者想要对字段进行定制,可以使用@Column注解,去配置字段的名称,长度,是否为空等等。

之后,启动Spring Boot项目,数据库中就会自动创建一个名为t_user的表


Spring Boot+Spring Data JPA_第2张图片
image

针对该表的操作,则需要我们提供一个Repository,如下:

package com.example.jpa.dao;

import com.example.jpa.bean.Book;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BookDao extends JpaRepository {
}

这里,自定义UserDao接口继承自JpaRepository,JpaRepository提供了一些基本的数据操作方法,例如保存,更新,删除,分页查询等。

普通增删改查

    @Test
    void insert() {
        Book book = new Book();
        book.setName("百年孤独");
        book.setAuthor("马尔克斯");
        bookDao.save(book);
    }
    @Test
    public void update(){
        Book book = new Book();
        book.setAuthor("马尔克斯");
        book.setName("霍乱时期的爱情");
        book.setId(1);
        bookDao.saveAndFlush(book);
    }
    @Test
    public void delete(){
        bookDao.deleteById(1);
    }
    @Test
    void find(){
        Optional byId = bookDao.findById(2);
        System.out.println(byId.get());
        List all = bookDao.findAll();
        System.out.println(all);
    }

JPA实现分页查询:

Pageable pageable = PageRequest.of(0,2);
        Page page = bookDao.findAll(pageable);
        System.out.println("记录数"+page.getTotalElements());
        System.out.println("当前页记录数"+page.getNumberOfElements());
        System.out.println("每页记录数"+page.getSize());
        System.out.println("获取总页数"+page.getTotalPages());
        System.out.println("查询结果"+page.getContent());
        System.out.println("当前页(从零开始)"+page.getNumber());

查询结果如下:


Spring Boot+Spring Data JPA_第3张图片
image

开发者也可以在接口中自己声明相关的方法,只需要方法名称符合规范即可,在Spring Data中,只要按照既定的规范命名方法,Spring Data Jpa就知道你想干嘛,这样就不用写SQL了,那么规范参考下图:

Spring Boot+Spring Data JPA_第4张图片
image

如查询id大于等于3的记录

List findBookByIdGreaterThan(Integer id);

查询结果如下


image

这种方法命名主要是针对查询,但是一些特殊需求,可能并不能通过这种方式解决,例如想要查询id最大的用户,这时就需要开发者自定义查询SQL了,如上代码所示,自定义查询SQL,使用@Query注解,在注解中写自己的SQL,默认使用的查询语言不是SQL,而是JPQL,这是一种数据库平台无关的面向对象的查询语言,有点定位类似于Hibernate中的HQL,在@Query注解中设置nativeQuery属性为true则表示使用原生查询,即大伙所熟悉的SQL。上面代码中的只是一个很简单的例子,还有其他一些点,例如如果这个方法中的SQL涉及到数据操作,则需要使用@Modifying和@Transactional注解。

如查询id最大的记录

    @Query(value = "select * from t_book where id=(select max(id) from t_book)",nativeQuery = true)
    Book getMaxIdBook();
    
    @Query(value = "insert into t_book(name,author) value (:name,:author)",nativeQuery = true)
    @Modifying
    @Transactional
    Integer addBook(@Param("name") String name,@Param("author") String author);

查询结果如下


image

4.多数据源查询

创建项目

创建项目时选择Spring Web、Spring Data JPA以及MySQL Driver

手动添加druid-spring-boot依赖

 
    com.alibaba
    druid-spring-boot-starter
    1.1.10
 

多数据源配置

接下来配置多数据源,这里基本上还是和JdbcTemplate多数据源的配置方式一致,首先在application.properties中配置数据库基本信息,然后提供两个DataSource,再加上jpa的配置即可。与单数据源配置不同,多数据源的jpa配置中要加上.properties,表示这些属性最终都要放在properties中。

application.properties中的配置如下:

spring.datasource.one.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8&useSSL=false
spring.datasource.one.username=root
spring.datasource.one.password=admin
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource

spring.datasource.url=jdbc:mysql://localhost:3306/demo2?serverTimezone=GMT%2B8&useSSL=false
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

spring.jpa.properties.hibernate.ddl-auto=update
spring.jpa.properties.database-platform=mysql
spring.jpa.properties.database=mysql
spring.jpa.properties.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

创建实体类和配置类

@Data
@Entity(name = "t_book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String author;
}

配置DataSource
这里的配置和Mybatis以及jdbc的多数据源配置基本一致,但是多了一个在Spring中使用较少的注解@Primary,@Primary表示当某一个类存在多个实例时,优先使用哪个实例。这个注解一定不能少,否则在项目启动时会出错,

@Configuration
public class DataSourceConfig {
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.one")
    DataSource dsOne(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.two")
    DataSource dsTwo(){
        return DruidDataSourceBuilder.create().build();
    }
}

配置JPA

@Configuration
@EnableJpaRepositories(basePackages = "com.example.jpa2.dao1",
        entityManagerFactoryRef = "localContainerEntityManagerFactoryBean1",
        transactionManagerRef = "platformTransactionManager1")
public class JpaConfig1 {
    @Autowired
    @Qualifier("dsOne")
    DataSource dsOne;

    @Autowired
    JpaProperties jpaProperties;
    
    @Bean
    @Primary
    LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean1(EntityManagerFactoryBuilder builder){
        return builder.dataSource(dsOne)
                .properties(jpaProperties.getProperties())
                .persistenceUnit("pu1")
                .packages("com.example.jpa2.bean")
                .build();
    }
    
    //事务管理器
    @Bean
    PlatformTransactionManager platformTransactionManager(EntityManagerFactoryBuilder builder){
        return new JpaTransactionManager(localContainerEntityManagerFactoryBean1(builder).getObject());
    }
}

首先这里注入dsOne,再注入JpaProperties,JpaProperties是系统提供的一个实例,里边的数据就是我们在application.properties中配置的jpa相关的配置。然后我们提供两个Bean,分别是LocalContainerEntityManagerFactoryBean和PlatformTransactionManager事务管理器,不同于MyBatis和JdbcTemplate,在Jpa中,事务一定要配置。在提供LocalContainerEntityManagerFactoryBean的时候,需要指定packages,这里的packages指定的包就是这个数据源对应的实体类所在的位置,另外在这里配置类上通过@EnableJpaRepositories注解指定dao所在的位置,以及LocalContainerEntityManagerFactoryBean和PlatformTransactionManager分别对应的引用的名字。这样第一个就配置好了,第二个基本和这个类似,主要有几个不同点:

  • dao的位置不同
  • persistenceUnit不同
  • 相关bean的名称不同
  • 实体类可以共用。

代码如下:

@Configuration
@EnableJpaRepositories(basePackages = "com.example.jpa2.dao2",
        entityManagerFactoryRef = "localContainerEntityManagerFactoryBean2",
        transactionManagerRef = "platformTransactionManager2")
public class JpaConfig2 {
    @Autowired
    @Qualifier("dsTwo")
    DataSource dsTwo;

    @Autowired
    JpaProperties jpaProperties;

    @Bean
    LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean2(EntityManagerFactoryBuilder builder){
        return builder.dataSource(dsTwo)
                .properties(jpaProperties.getProperties())
                .persistenceUnit("pu2")
                .packages("com.example.jpa2.bean")
                .build();
    }
    //事务管理器
    @Bean
    PlatformTransactionManager platformTransactionManager2(EntityManagerFactoryBuilder builder){
        return new JpaTransactionManager(localContainerEntityManagerFactoryBean2(builder).getObject());
    }
}

接下来,在对应位置分别提供相关的实体类和dao即可。

数据源一的dao如下:

public interface BookDao extends JpaRepository {}

数据源二的dao如下:

public interface BookDao2 extends JpaRepository {}

到此,所有的配置就算完成了,接下来就可以在Service中注入不同的UserDao,不同的UserDao操作不同的数据源。

你可能感兴趣的:(Spring Boot+Spring Data JPA)