6.Spring Data JPA

本文是读《Spring Boot2精髓-从构件小系统到架构分布式大系统》的读书笔记。

访 问数据库的方式有两个流派 , 一派 以 SQL 为中 心,在 JDBC 上做了 一定程度的封装 , 比直接操作 JDBC 更加方便和便捷,流行 DAO 工具 MyBatis 也属于这个流派。
另外一个流派则是 以 Java Entity 为 中心, 将实体和实体关系对应到数据库 的表和表关系,这类工具通常就是 ORM ( Object Relational Mappi°;g)工具 。 对实体和实体关系的操作会映射到数据库操作。
本章将介绍 Spring Data JPA , 它在 JPA 提供的简单语义上做了 一定的封装,满足 CRUD 查询。同时,也会介绍 Spring Data,它为 Spring 框架对访问 SQL 和 NoSQL 数据库提供了一致的方式 。

6.1 集成Spring Data JPA

集成数据源
添加依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
//Hikari作为数据源提供者
       <dependency>
          <groupId>com.zaxxer</groupId>
          <artifactId>HikariCP</artifactId>
        </dependency>
        
         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.5</version>
        </dependency>

为了在 Spring Boot 应用中使用 Spring Data JPA,需要通过 Java 来配置数据源。我们使用
Hikari 作为数据源:

package com.bee.sample.ch6.conf;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import com.zaxxer.hikari.HikariDataSource;

@Configuration
public class DataSourceConfig {
	@Bean(name = "dataSource")
	public DataSource datasource(Environment env) {
		HikariDataSource ds = new HikariDataSource();
		ds.setJdbcUrl(env.getProperty("spring.datasource.url"));
		ds.setUsername(env.getProperty("spring.datasource.username"));
		ds.setPassword(env.getProperty("spring.datasource.password"));
		ds.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
		return ds;
	}
}

配置JPA支持
大多数项目都是在需求分析后建立物理模型 。 也就是先有数据库表设计,随后才是 Sp「ing Boot 应用,因此数据库的 DDL 语句早已经具备 。 从另一方面讲,项目数据库管理人员、需求分析人员,甚至是项目经理并不喜欢 Hibernate 创建的表结构,比如,它的外键命名就很随机,不符合命名规范 。 自动建表对于小型项目或者工具类项目(如工作流引擎)还是很方便的 。

创建Entity
User 表对应的实体表如下:

package com.bee.sample.ch6.entity;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class User  {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id ;

	//部门
	@Column
	private String name ;
	//创建时间
	@Column(name="create_time")
	private Date createTime ;
	
	@ManyToOne
	@JoinColumn(name="department_id")
	Department department;
	
	
	public User() {
	//JPA要求实体必须有一个空的构造函数
	}
	
	
	public Integer getId(){
		return  id;
	}
	public void setId(Integer id ){
		this.id = id;
	}
	
	
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	public String getName(){
		return  name;
	}
	public void setName(String name ){
		this.name = name;
	}
	
	public Date getCreateTime(){
		return  createTime;
	}
	public void setCreateTime(Date createTime ){
		this.createTime = createTime;
	}
}

Department 对象的定义如下:

package com.bee.sample.ch6.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
@Entity
public class Department {
	@Id
	//
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id ;
	@Column
	private String name ;
	@OneToMany(mappedBy="department")
	private Set<User> users = new HashSet<User>();
	
	
    public Set<User> getUsers() {
      return users;
    }

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setUsers(Set<User> users) {
		this.users = users;
	}
	
}

不同于 BeetlSQL 对 Entity 的“松散”要求, JPA 既然以 Entity 为中心, 实体类就必须使用
@Entity 来注解, JPA 也提供了大量的注解来表明实体属性和关系。
@Id , 声明了 一 个属性将映射到数据库主键宇段。主键生成策略由注解@GeneratedValue 来指定。本例中, id 为自增主键,是一种简单的数据库主键生成策略,因此使用 GenerationType .IDENTITY 作为主键生成的策略 。
@Column,此注解表明属性对应到数据库的一个字段,且列名为 name 指定的名称 。
@ManyToOne, Many 指的是定义此属性的实体,即 User 实体,而 One 指的就是此注
解所注解的属性, ManyToOne 说明对象 User 和 Department 的关系是多对一关系,多
个用户属于一个部门 。
@JoinColumn ,与 ManyToOne 搭配使用,说明外键字段是 department一id 。
Department 对象的定义如下:

简化Entity
去掉 了关系映射的相关配置,去掉了数据库外键设置,一个表对应了一个简单的对象

6.2 Repository

Repository 是 Spring Data 的核心概念,抽象了对数据库和 NoSQL 的操作,提供了如下接口供开发者使用:

  • CrudRepository ,提供了基本的增删改查,批量操作接口。
  • PagingAndSortingRepository , 集成 CrudRepository ,提供了附加的分页 查询功能。
  • JpaRepository , 专门用于 JPA ,提供了 更多丰富 的数据库访问接口,比如根据 Example来查询,类似 BeetlSQL 的根据模板查询。

NoSQL :Redis、MongoDB、Elasticsearch
CrudRepository
Spring Data 提供 了 CrudRepository 接口来实现 Entity 的简单增删改查功能。
PagingAndSortingRepository
PagingAndSortingRepository 增加了翻页查找和排序相关的操作:
**JpaRepository **:
JpaRepository 提供了更多的实用功能,以及通过 Example 对象进行查询 。

持久化Entity
Sort
Pageable和Page
基于方法名字查询
Spring Data 通过查询的方法名和参数名来自动构造一个 JPA OQL 查询,我们可以在
UserRepository 中添加一个查询方法:

public interface UserRepository extends JpaRepository<User,Integer>{
	public User findByName(String name);
}

方法名和参数名需要遵守一定的规则, Spring Data JPA 才能自动转化为 JPQL:
JPOL片段可以自己看看
@Query查询

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.bee.sample.ch6.entity.User;

public interface UserRepository extends JpaRepository<User, Integer> {
	public User findByName(String name);
//注解 Query 允许在方法上使用 JPQL 。	
	@Query("select u from User u where u.name=?1 and u.department.id=?2")
	public User findUserByDepartment(String name,Integer departmentId);
//如果你更喜欢 SQL 而不是 JPQL,可以使用@Query 的 nativeQuery 属性 , 设置为 true:	
	@Query(value="select * from user where name=?1 and department_id=?2",nativeQuery=true)
	public User nativeQuery(String name,Integer departmentId);
//无论是 JPQL , 还是 SQL 语句,都支持 “命名参数” :	
	@Query(value="select * from user where name=:name and department_id=:departmentId",nativeQuery=true)
	public User nativeQuery2(@Param("name")  String name,@Param("departmentId")  Integer departmentId);
//如果 SQL 或者 JPQL 查询结果集并非 Entity , 可以用 Object[]数组代替 ,比如分组统计每个部 门的用户数 :
	@Query(value="select department_id,count(1) total from user group by department_id",nativeQuery=true)
	public List<Object[]> queryUserCount();
	
	@Query(value="select id from user where department_id=?1",nativeQuery=true)
	public List<Integer> queryUserIds(Integer departmentId);
//查询时可以使用 Pageable 和 Sort 来对协助“ JPQL ” 完成翻页和排序。
	@Query(value="select u from User u where u.department.id=?1")
	public Page<User> queryUsers(Integer departmentId,Pageable page);

//@Query 还允许 SQL 更新、删除语句,此时必须搭配@Modifying 使用,比如:
	@Modifying
	@Query("update User u set u.name=?1 where u.id=?2")
	int updateName(String name,Integer id);
}

使用JPA Query
Example查询

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值