Spring Data JPA

前言

Spring Data是一个非常大的伞形项目,由多个子项目组成,其中大多数子项目都关注对不同的数据库类型进行数据持久化。比较流行的几个Sprig Data项目包括:
Spring Data JPA:基于关系型数据库进行JPA持久化。

Spring Data MongoDB:持久化到Mongo文档数据库。

Spring Data Neo4j:持久化到Neo4j图数据库。

Spring Data Redis:持久化到Redis key-value存储。

Spring Data Cassandra:持久化到Cassandra数据库。

Spring Data 为所有项目提供了-项最有趣且最有用的特性,就是基于repository规范接口自动生成repository的功能。

我们就来了解一下Spring Data JPA :
JPA :Java Persistence API(Java 持久层 API):用于对象持久化的 API.

导入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Spring Boot应用可以通过JPA starter来添加Spring Data JPA。这个starter依赖不仅会引人Spring Data JPA,还会传递性地将Hibernate(开放源代码的对象关系映射框架)作为JPA的实现引入进来。

配置数据源信息

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/Text
    username: root
    password: ********
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    database-platform: org.hibernate.dialect.MySQL5Dialect

定义实体对象

package sia.tacocloud.DAO;

import com.sun.istack.NotNull;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.persistence.*;
import java.util.Arrays;
import java.util.Collection;

@Entity
@Table(name="boss")//表名
public class Boss {

    private String name;
    private String password;

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

 
}

@Entity注解为了声明为JPA实体,他的id使用@Id注解,同时还设置了自动增长。
Spring 接口继承结构
在这里插入图片描述

声明JPA repository(继承CrudRepository)
CrudRepository定义了很多用于CRUD (创建、读取、更新、删除)操作的方法。注意,它是参数化的,第一个参数是repository要持久化的实体类型,第二个参数是实体ID属性的类型。对于BossRepository来说,参数应该是Boss和Integer。我们可以非常简单地定义BossCrudRepository

package sia.tacocloud.DAO;
import org.springframework.data.repository.CrudRepository;

import java.util.List;


public interface BossCrudRepository extends CrudRepository<Boss,Integer> {
}

现在,我们有了repository。你可能会想,我们应该需要编写它们的实现类,包括每个实现类所需的十多个方法。但是,Spring Data JPA带来的好消息是,我们根本就不用编写实现类!当应用启动的时候,Spring Data JPA会在运行期自动生成实现类。这意味着,我们现在就可以使用这些repository 了。我们只需要像使用基于JDBC的实现那样将它们注人控制器中就可以了,如下我们来测试一下。
测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class CrudTest {
    @Autowired
    private BossCrudRepository bossCrudRepository;
	/**
	 * 添加单个用户
	 */
	@Test
	public void testAddBoss(){
		Boss boss = new Boss();
		boss.setName("王七");
	    boss.setPassword("123");
		bossCrudRepository.save(boss);
	}
	
	
	/**
	 * 批量添加用户
	 */
	@Test
	public void test2(){
		Boss boss = new Boss();
		boss.setName("张二");
		boss.setPassword("12333");
		
		Boss boss1 = new Boss();
		boss1.setName("申六");
		boss1.setPassword("12222");
		
		List<Boss> list= new ArrayList<>();
		list.add(boss);
		list.add(boss1);
		
		bossCrudRepository.save(list);
		
	}
	
	/**
	 * 根据ID查询单条数据
	 */
	@Test
	public void test3(){
		Boss boss = bossCrudRepository.findOne(13);
		System.out.println(boss);
	}
	
	/**
	 * 查询全部数据
	 */
	@Test
	public void test4(){
		List<Boss> list = (List<Boss>)bossCrudRepository.findAll();
	
			System.out.println(list.toString());
		
	}
	
	/**
	 * 删除数据
	 */
	@Test
	public void test5(){
		bossCrudRepository.delete(13);
	}
	
	/**
	 * 更新数据 方式一
	 */
	@Test
	public void test6(){
		Boss boss = bossCrudRepository.findOne(12);
		boss.setName("王五");
		bossCrudRepository.save(boss);
	}
	
	/**
	 * 更新数据 方式二
	 */
	@Test
	@Transactional//在测试类对于事务提交方式默认的是回滚。
	@Rollback(false)//取消自动回滚
	public void test7(){
		Boss boss = bossCrudRepository.findOne(12);//持久化状态的
		boss.setName("李四");
	}
	
}

声明JPA repository(继承 PagingAndSortingRepository)

package sia.tacocloud.DAO;

import org.springframework.data.repository.PagingAndSortingRepository;

public interface BossPageAndSortJPARepository extends PagingAndSortingRepository<Boss, Integer> {

}

测试类

package sia.tacocloud.Control;

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.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;
import sia.tacocloud.Configuration.ConfigurationProps;
import sia.tacocloud.DAO.Boss;
import sia.tacocloud.DAO.BossPageAndSortJPARepository;

import java.util.List;
import java.util.function.Consumer;

@RunWith(SpringRunner.class)
@SpringBootTest
public class BossPageText {

    @Autowired//自定义配置属性,用来获取每页多少数据
    private ConfigurationProps configurationProps;

    @Autowired
    private BossPageAndSortJPARepository bossPageAndSortJPARepository;

    /**
     * 分页
     */
    @Test
    public void testPage(){
        int page = 2; //page:当前页的索引。注意索引都是从0开始的。
       //PageSize显示每页多少条数据,这里使用自定义配置属性,属性源是应用配置文件
        //数据库页数从0开始
        //获取PageRequest的新方法,新版本
        Pageable pageable= PageRequest.of(page-1,configurationProps.getPageSize());
        Page<Boss> p = this.bossPageAndSortJPARepository.findAll(pageable);
        System.out.println("数据的总条数:"+p.getTotalElements());
        System.out.println("总页数:"+p.getTotalPages());
        //获取当前页的数据
        List<Boss> list = p.getContent();
        for (Boss boss : list) {
            System.out.println(boss.getId()+" "+boss.getPassword());
        }
    }

    @Test
    public void textPageAndSort(){
        //获取Sort的新方法,新版本,对password先排序,在进行分页,如果不分页就直接传入sort就行,依情况而定
        Sort password = Sort.by(Sort.Direction.DESC, "password");
        Pageable  of = PageRequest.of(0, 3, password);
        Iterable<Boss> all = bossPageAndSortJPARepository.findAll(of);
        all.forEach(boss -> System.out.println(boss.getId()+" "+boss.getPassword()));
    }
}

上述Repository所提供的方法对于实体的通用持久化是非常有用的。但是,如果我们的需求并不局限于基本持久化,那又该怎么办呢?接下来,我们看一下如何自定义repositry来执行特定领域的查询。

自定义 JPA repository

Spring Data JPA 中为我们提供了两种查询方式的支持
1)基于方法名称命名规则查询
2)基于@Query 注解查询

方法名称命名规则查询
规则:
findBy(关键字)+属性名称(属性名称的首字母大写)+查询条件(首字母大写)
复制

关键字方法命名sql where 字句
AndfindByNameAndPwdwhere name= ? and pwd =?
OrfindByNameOrSexwhere name= ? or sex=?
BetweenfindByIdBetweenwhere id between ? and ?
LessThanfindByIdLessThanwhere id < ?
LessThanEqualfindByIdLessThanEqualswhere id <= ?
GreaterThanfindByIdGreaterThanwhere id > ?
GreaterThanEqualfindByIdGreaterThanEqualswhere id > = ?
AfterfindByIdAfterwhere id > ?
BeforefindByIdBeforewhere id < ?
IsNullfindByNameIsNullwhere name is null
isNotNull,Not NullfindByNameNotNullwhere name is not
LikefindByNameLikewhere name like ?
NotLikefindByNameNotLikewhere name not like ?
StartingWithfindByNameStartingWithwhere name like ‘?%’
EndingWithfindByNameEndingWithwhere name like ‘%?’
ContainingfindByNameContainingwhere name like ‘%?%’
OrderByfindByIdOrderByXDescwhere id=? order by x desc
NotfindByNameNotwhere name <> ?
InfindByIdIn(Collection<?> c)where id in (?)
NotInfindByIdNotIn(Collection<?> c)where id not in (?)
TruefindByAaaTuewhere aaa = true
FalsefindByAaaFalsewhere aaa = false
IgnoreCasefindByNameIgnoreCasewhere UPPER(name)=UPPER(?)

创建接口


public interface BossRepository extends Repository<Boss, Integer> {
	//方法名称命名规则
	List<Users> findByNameLike(String name);
	List<Users> findByNameAndIdGreaterThanEqual(String name,Integer id);
}

测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class RepositoryTest {

	@Autowired
	private BossRepository bossRepository;
	
	/**
	 * 需求:根据用户姓名做Like处理
	 */
	@Test
	public void test1(){
		List<Boss> list = bossRepository.findByNameLike("%申%");
			System.out.println(list.toString());

	}
	
	
	/**
	 * 需求:查询名称为王五,并且他的年龄大于等于17岁
	 */
	@Test
	public void test2(){
		List<Boss> list = this.usersDao.findByNameAndIdGreaterThanEqual("王五", 17);
	
			System.out.println(list.toString());
	
	}
}

尽管方法名称约定对于相对简单的查询非常有用,但是,不难想象,对于更为复杂的查询,方法名可能会面临失控的风险。在这种情况下,可以将方法定义为任何你想要的名称,并为其添加@Query注解从而明确指明方法调用时要执行的查询,如下面的样例所示:

2)基于@Query 注解查询

创建接口

public interface BossQueryRepository extends Repository<Boss,Integer> {

    //启用SQL查询
    @Query(value ="select * from boss where name like ? or ID > ? ",nativeQuery=true)
    List<Boss> byNameOrIdUseSQL(String name,int id);

    @Query(value="select * from boss where name like ? and Id = 9",nativeQuery=true)
    List<Boss> byLikeNameAndIdUseSQL(String name,int id);

测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class RepositoryTest {

	@Autowired
	private BossQueryRepository bossQueryRepository;
	
	/**
	 * 需求:根据用户姓名like申%或者Id>21
	 */
	@Test
	public void test1(){
		 List<Boss> sc = bossQueryRepository.byNameOrIdUseSQL("申%",21);
			System.out.println(list.toString());

	}
	
	
	/**
	 * 需求:查询名称like%王%,并且他的ID等于17
	 */
	@Test
	public void test2(){
		List<Boss> list = bossQueryRepository.byLikeNameAndIdUseSQL("%王%", 17);
			System.out.println(list.toString());
	
	}
}

来源:Spring实战5
https://www.cnblogs.com/chenglc/p/11226693.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值