SpringDataJPA

介绍

SpringDataJPA是SpringData项目下的一个模块。提供了基于JPA标准操作数据库的简化方案,底层默认依赖的是HibernateJPA。其特点为:只需要定义接口并集成SpringDataJPA中提供的接口即可,无需编写接口的实现类。

关键接口

Repository

SpringDataJPA提供的所有接口的顶层接口。本身是一个标志接口,提供了基于方法名称命名规则和基于@Query 注解两种操作方式支持。

java 复制代码
/*
 * Copyright 2011-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository;

import org.springframework.stereotype.Indexed;

/**
 * Central repository marker interface. Captures the domain type to manage as well as the domain type's id type. General
 * purpose is to hold type information as well as being able to discover interfaces that extend this one during
 * classpath scanning for easy Spring bean creation.
 * <p>
 * Domain repositories extending this interface can selectively expose CRUD methods by simply declaring methods of the
 * same signature as those declared in {@link CrudRepository}.
 * 
 * @see CrudRepository
 * @param <T> the domain type the repository manages
 * @param <ID> the type of the id of the entity the repository manages
 * @author Oliver Gierke
 */
@Indexed
public interface Repository<T, ID> {

}

CrudRepository

继承自Repository接口并且扩展了CRUD的相关功能。

java 复制代码
/*
 * Copyright 2008-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository;

import java.util.Optional;

import org.springframework.dao.OptimisticLockingFailureException;

/**
 * Interface for generic CRUD operations on a repository for a specific type.
 *
 * @author Oliver Gierke
 * @author Eberhard Wolff
 * @author Jens Schauder
 */
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

	/**
	 * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
	 * entity instance completely.
	 *
	 * @param entity must not be {@literal null}.
	 * @return the saved entity; will never be {@literal null}.
	 * @throws IllegalArgumentException in case the given {@literal entity} is {@literal null}.
	 * @throws OptimisticLockingFailureException when the entity uses optimistic locking and has a version attribute with
	 *           a different value from that found in the persistence store. Also thrown if the entity is assumed to be
	 *           present but does not exist in the database.
	 */
	<S extends T> S save(S entity);

	/**
	 * Saves all given entities.
	 *
	 * @param entities must not be {@literal null} nor must it contain {@literal null}.
	 * @return the saved entities; will never be {@literal null}. The returned {@literal Iterable} will have the same size
	 *         as the {@literal Iterable} passed as an argument.
	 * @throws IllegalArgumentException in case the given {@link Iterable entities} or one of its entities is
	 *           {@literal null}.
	 * @throws OptimisticLockingFailureException when at least one entity uses optimistic locking and has a version
	 *           attribute with a different value from that found in the persistence store. Also thrown if at least one
	 *           entity is assumed to be present but does not exist in the database.
	 */
	<S extends T> Iterable<S> saveAll(Iterable<S> entities);

	/**
	 * Retrieves an entity by its id.
	 *
	 * @param id must not be {@literal null}.
	 * @return the entity with the given id or {@literal Optional#empty()} if none found.
	 * @throws IllegalArgumentException if {@literal id} is {@literal null}.
	 */
	Optional<T> findById(ID id);

	/**
	 * Returns whether an entity with the given id exists.
	 *
	 * @param id must not be {@literal null}.
	 * @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
	 * @throws IllegalArgumentException if {@literal id} is {@literal null}.
	 */
	boolean existsById(ID id);

	/**
	 * Returns all instances of the type.
	 *
	 * @return all entities
	 */
	Iterable<T> findAll();

	/**
	 * Returns all instances of the type {@code T} with the given IDs.
	 * <p>
	 * If some or all ids are not found, no entities are returned for these IDs.
	 * <p>
	 * Note that the order of elements in the result is not guaranteed.
	 *
	 * @param ids must not be {@literal null} nor contain any {@literal null} values.
	 * @return guaranteed to be not {@literal null}. The size can be equal or less than the number of given
	 *         {@literal ids}.
	 * @throws IllegalArgumentException in case the given {@link Iterable ids} or one of its items is {@literal null}.
	 */
	Iterable<T> findAllById(Iterable<ID> ids);

	/**
	 * Returns the number of entities available.
	 *
	 * @return the number of entities.
	 */
	long count();

	/**
	 * Deletes the entity with the given id.
	 * <p>
	 * If the entity is not found in the persistence store it is silently ignored.
	 *
	 * @param id must not be {@literal null}.
	 * @throws IllegalArgumentException in case the given {@literal id} is {@literal null}
	 */
	void deleteById(ID id);

	/**
	 * Deletes a given entity.
	 *
	 * @param entity must not be {@literal null}.
	 * @throws IllegalArgumentException in case the given entity is {@literal null}.
	 * @throws OptimisticLockingFailureException when the entity uses optimistic locking and has a version attribute with
	 *           a different value from that found in the persistence store. Also thrown if the entity is assumed to be
	 *           present but does not exist in the database.
	 */
	void delete(T entity);

	/**
	 * Deletes all instances of the type {@code T} with the given IDs.
	 * <p>
	 * Entities that aren't found in the persistence store are silently ignored.
	 *
	 * @param ids must not be {@literal null}. Must not contain {@literal null} elements.
	 * @throws IllegalArgumentException in case the given {@literal ids} or one of its elements is {@literal null}.
	 * @since 2.5
	 */
	void deleteAllById(Iterable<? extends ID> ids);

	/**
	 * Deletes the given entities.
	 *
	 * @param entities must not be {@literal null}. Must not contain {@literal null} elements.
	 * @throws IllegalArgumentException in case the given {@literal entities} or one of its entities is {@literal null}.
	 * @throws OptimisticLockingFailureException when at least one entity uses optimistic locking and has a version
	 *           attribute with a different value from that found in the persistence store. Also thrown if at least one
	 *           entity is assumed to be present but does not exist in the database.
	 */
	void deleteAll(Iterable<? extends T> entities);

	/**
	 * Deletes all entities managed by the repository.
	 */
	void deleteAll();
}

ListCrudRepository

继承自CrudRepository接口并且扩展了List的相关功能。

java 复制代码
/*
 * Copyright 2022-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository;

import java.util.List;

import org.springframework.dao.OptimisticLockingFailureException;

/**
 * Interface for generic CRUD operations on a repository for a specific type. This an extension to
 * {@link CrudRepository} returning {@link List} instead of {@link Iterable} where applicable.
 *
 * @author Jens Schauder
 * @see CrudRepository
 * @since 3.0
 */
@NoRepositoryBean
public interface ListCrudRepository<T, ID> extends CrudRepository<T, ID> {

	/**
	 * Saves all given entities.
	 *
	 * @param entities must not be {@literal null} nor must it contain {@literal null}.
	 * @return the saved entities; will never be {@literal null}. The returned {@literal Iterable} will have the same size
	 *         as the {@literal Iterable} passed as an argument.
	 * @throws IllegalArgumentException in case the given {@link Iterable entities} or one of its entities is
	 *           {@literal null}.
	 * @throws OptimisticLockingFailureException when at least one entity uses optimistic locking and has a version
	 *           attribute with a different value from that found in the persistence store. Also thrown if at least one
	 *           entity is assumed to be present but does not exist in the database.
	 */
	<S extends T> List<S> saveAll(Iterable<S> entities);

	/**
	 * Returns all instances of the type.
	 *
	 * @return all entities
	 */
	List<T> findAll();

	/**
	 * Returns all instances of the type {@code T} with the given IDs.
	 * <p>
	 * If some or all ids are not found, no entities are returned for these IDs.
	 * <p>
	 * Note that the order of elements in the result is not guaranteed.
	 *
	 * @param ids must not be {@literal null} nor contain any {@literal null} values.
	 * @return guaranteed to be not {@literal null}. The size can be equal or less than the number of given
	 *         {@literal ids}.
	 * @throws IllegalArgumentException in case the given {@link Iterable ids} or one of its items is {@literal null}.
	 */
	List<T> findAllById(Iterable<ID> ids);

}

PagingAndSortingRepository

继承自Repository接口并且扩展了分页和排序的相关功能。

java 复制代码
/*
 * Copyright 2008-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

/**
 * Repository fragment to provide methods to retrieve entities using the pagination and sorting abstraction. In many
 * cases this will be combined with {@link CrudRepository} or similar or with manually added methods to provide CRUD
 * functionality.
 *
 * @author Oliver Gierke
 * @author Jens Schauder
 * @see Sort
 * @see Pageable
 * @see Page
 * @see CrudRepository
 */
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends Repository<T, ID> {

	/**
	 * Returns all entities sorted by the given options.
	 *
	 * @param sort the {@link Sort} specification to sort the results by, can be {@link Sort#unsorted()}, must not be
	 *          {@literal null}.
	 * @return all entities sorted by the given options
	 */
	Iterable<T> findAll(Sort sort);

	/**
	 * Returns a {@link Page} of entities meeting the paging restriction provided in the {@link Pageable} object.
	 *
	 * @param pageable the pageable to request a paged result, can be {@link Pageable#unpaged()}, must not be
	 *          {@literal null}.
	 * @return a page of entities
	 */
	Page<T> findAll(Pageable pageable);
}

ListPagingAndSortingRepository

继承自PagingAndSortingRepository接口并且扩展了List的相关功能。

java 复制代码
/*
 * Copyright 2008-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

/**
 * Repository fragment to provide methods to retrieve entities using the pagination and sorting abstraction. This an
 * extension to {@link PagingAndSortingRepository} returning {@link List} instead of {@link Iterable} where applicable.
 *
 * @author Oliver Gierke
 * @author Jens Schauder
 * @see Sort
 * @see Pageable
 * @see Page
 * @see CrudRepository
 */
@NoRepositoryBean
public interface ListPagingAndSortingRepository<T, ID> extends PagingAndSortingRepository<T, ID> {

	/**
	 * Returns all entities sorted by the given options.
	 *
	 * @param sort the {@link Sort} specification to sort the results by, can be {@link Sort#unsorted()}, must not be
	 *          {@literal null}.
	 * @return all entities sorted by the given options
	 */
	List<T> findAll(Sort sort);

}

JpaRepository

继承了ListCrudRepository、ListPagingAndSortingRepository和QueryByExampleExecutor三个接口,是日常开发使用最多的接口。可以帮助我们将其他接口方法的返回值做适配处理,使我们在开发的过程中更加方便的使用这些方法。

java 复制代码
/*
 * Copyright 2008-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.jpa.repository;

import java.util.List;

import jakarta.persistence.EntityManager;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.ListCrudRepository;
import org.springframework.data.repository.ListPagingAndSortingRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.query.QueryByExampleExecutor;

/**
 * JPA specific extension of {@link org.springframework.data.repository.Repository}.
 *
 * @author Oliver Gierke
 * @author Christoph Strobl
 * @author Mark Paluch
 * @author Sander Krabbenborg
 * @author Jesse Wouters
 * @author Greg Turnquist
 * @author Jens Schauder
 */
@NoRepositoryBean
public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

	/**
	 * Flushes all pending changes to the database.
	 */
	void flush();

	/**
	 * Saves an entity and flushes changes instantly.
	 *
	 * @param entity entity to be saved. Must not be {@literal null}.
	 * @return the saved entity
	 */
	<S extends T> S saveAndFlush(S entity);

	/**
	 * Saves all entities and flushes changes instantly.
	 *
	 * @param entities entities to be saved. Must not be {@literal null}.
	 * @return the saved entities
	 * @since 2.5
	 */
	<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);

	/**
	 * Deletes the given entities in a batch which means it will create a single query. This kind of operation leaves JPAs
	 * first level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this
	 * method.
	 *
	 * @param entities entities to be deleted. Must not be {@literal null}.
	 * @deprecated Use {@link #deleteAllInBatch(Iterable)} instead.
	 */
	@Deprecated
	default void deleteInBatch(Iterable<T> entities) {
		deleteAllInBatch(entities);
	}

	/**
	 * Deletes the given entities in a batch which means it will create a single query. This kind of operation leaves JPAs
	 * first level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this
	 * method.
	 * <p>
	 * It will also NOT honor cascade semantics of JPA, nor will it emit JPA  lifecycle events.
	 *</p>
	 * @param entities entities to be deleted. Must not be {@literal null}.
	 * @since 2.5
	 */
	void deleteAllInBatch(Iterable<T> entities);

	/**
	 * Deletes the entities identified by the given ids using a single query. This kind of operation leaves JPAs first
	 * level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this method.
	 *
	 * @param ids the ids of the entities to be deleted. Must not be {@literal null}.
	 * @since 2.5
	 */
	void deleteAllByIdInBatch(Iterable<ID> ids);

	/**
	 * Deletes all entities in a batch call.
	 */
	void deleteAllInBatch();

	/**
	 * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
	 * implemented this is very likely to always return an instance and throw an
	 * {@link jakarta.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
	 * immediately.
	 *
	 * @param id must not be {@literal null}.
	 * @return a reference to the entity with the given identifier.
	 * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
	 * @deprecated use {@link JpaRepository#getReferenceById(ID)} instead.
	 */
	@Deprecated
	T getOne(ID id);

	/**
	 * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
	 * implemented this is very likely to always return an instance and throw an
	 * {@link jakarta.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
	 * immediately.
	 *
	 * @param id must not be {@literal null}.
	 * @return a reference to the entity with the given identifier.
	 * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
	 * @deprecated use {@link JpaRepository#getReferenceById(ID)} instead.
	 * @since 2.5
	 */
	@Deprecated
	T getById(ID id);

	/**
	 * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
	 * implemented this is very likely to always return an instance and throw an
	 * {@link jakarta.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
	 * immediately.
	 *
	 * @param id must not be {@literal null}.
	 * @return a reference to the entity with the given identifier.
	 * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
	 * @since 2.7
	 */
	T getReferenceById(ID id);

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
	 */
	@Override
	<S extends T> List<S> findAll(Example<S> example);

	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

JpaSpecificationExecutor

提供了条件查询、分页和排序功能,无法单独使用,需要和其他的接口一块使用。

java 复制代码
/*
 * Copyright 2008-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.jpa.repository;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;

import java.util.List;
import java.util.Optional;
import java.util.function.Function;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.repository.query.FluentQuery;

/**
 * Interface to allow execution of {@link Specification}s based on the JPA criteria API.
 *
 * @author Oliver Gierke
 * @author Christoph Strobl
 * @author Diego Krupitza
 * @author Mark Paluch
 */
public interface JpaSpecificationExecutor<T> {

	/**
	 * Returns a single entity matching the given {@link Specification} or {@link Optional#empty()} if none found.
	 *
	 * @param spec must not be {@literal null}.
	 * @return never {@literal null}.
	 * @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
	 */
	Optional<T> findOne(Specification<T> spec);

	/**
	 * Returns all entities matching the given {@link Specification}.
	 *
	 * @param spec must not be {@literal null}.
	 * @return never {@literal null}.
	 */
	List<T> findAll(Specification<T> spec);

	/**
	 * Returns a {@link Page} of entities matching the given {@link Specification}.
	 *
	 * @param spec must not be {@literal null}.
	 * @param pageable must not be {@literal null}.
	 * @return never {@literal null}.
	 */
	Page<T> findAll(Specification<T> spec, Pageable pageable);

	/**
	 * Returns all entities matching the given {@link Specification} and {@link Sort}.
	 *
	 * @param spec must not be {@literal null}.
	 * @param sort must not be {@literal null}.
	 * @return never {@literal null}.
	 */
	List<T> findAll(Specification<T> spec, Sort sort);

	/**
	 * Returns the number of instances that the given {@link Specification} will return.
	 *
	 * @param spec the {@link Specification} to count instances for, must not be {@literal null}.
	 * @return the number of instances.
	 */
	long count(Specification<T> spec);

	/**
	 * Checks whether the data store contains elements that match the given {@link Specification}.
	 *
	 * @param spec the {@link Specification} to use for the existence check, ust not be {@literal null}.
	 * @return {@code true} if the data store contains elements that match the given {@link Specification} otherwise
	 *         {@code false}.
	 */
	boolean exists(Specification<T> spec);

	/**
	 * Deletes by the {@link Specification} and returns the number of rows deleted.
	 * <p>
	 * This method uses {@link jakarta.persistence.criteria.CriteriaDelete Criteria API bulk delete} that maps directly to
	 * database delete operations. The persistence context is not synchronized with the result of the bulk delete.
	 * <p>
	 * Please note that {@link jakarta.persistence.criteria.CriteriaQuery} in,
	 * {@link Specification#toPredicate(Root, CriteriaQuery, CriteriaBuilder)} will be {@literal null} because
	 * {@link jakarta.persistence.criteria.CriteriaBuilder#createCriteriaDelete(Class)} does not implement
	 * {@code CriteriaQuery}.
	 *
	 * @param spec the {@link Specification} to use for the existence check, must not be {@literal null}.
	 * @return the number of entities deleted.
	 * @since 3.0
	 */
	long delete(Specification<T> spec);

	/**
	 * Returns entities matching the given {@link Specification} applying the {@code queryFunction} that defines the query
	 * and its result type.
	 *
	 * @param spec must not be null.
	 * @param queryFunction the query function defining projection, sorting, and the result type
	 * @return all entities matching the given Example.
	 * @since 3.0
	 */
	<S extends T, R> R findBy(Specification<T> spec, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);

}

命名规则

由于篇幅问题,下列表格中只梳理了一部分常用的内容。如无法满足开发要求可查看官方文档或自行推断命名。

关键字 示例 效果
And findByNameAndPassword(String name, String password) WHERE name = ? AND password = ?
Or findByNameOrPhone(String name, String phone) WHERE name = ? OR phone = ?
Equal findByNameEqual(String name) WHERE name = ?
Between findByIdBetween(Long start, Long end) WHERE id BETWEEN ? AND ?
LessThan findByIdLessThan(Long num) WHERE id < ?
LessThanEqual findByIdNameLessThanEqual(Long num) WHERE id <= ?
GreaterThan findByIdGreaterThan(Long num) WHERE id > ?
GreaterThanEqual findByIdGreaterThanEqual(Long num) WHERE id >= ?
After findByIdAfter(Long num) WHERE id > ?
Before findByIdBefore(Long num) WHERE id < ?
IsNull findByNameIsNull(String name) WHERE name IS NULL
IsNotNull findByNameIsNotNull(String name) WHERE name IS NOT NULL
Like findByNameLike(String name) WHERE name LIKE ?
NotLike findByNameNotLike(String name) WHERE name NOT LIKE ?
StartingWith findByNameStartingWith(String name) WHERE name LIKE '?%'
EndingWith findByNameEndingWith(String name) WHERE name LIKE '%?'
Containing findByNameContaining(String name) WHERE name LIKE '%?%'
OrderBy findByAgeOrderByNameDesc(Integer age) WHERE age = ? ORDER BY name DESC
Not findByNameNot(String name) WHERE name <> ?
In findByNameIn(Collection names) WHERE name IN(?)
NotIn findByNameNotIn(Collection names) WHERE name NOT IN(?)
True findByDeletedTrue() WHERE deleted = true
False findByDeletedFalse() WHERE deleted = false
IgnoreCase findByNameIgnoreCase(String name) WHERE UPPER(name) = UPPER(?)

代码示例

整体结构

pom

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.5</version>
	</parent>

	<groupId>com.sumlv</groupId>
	<artifactId>spring-boot-data-jpa-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<java.version>21</java.version>
	</properties>

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

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.33</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-3-starter</artifactId>
			<version>1.2.24</version>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.30</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

properties

bash 复制代码
# 应用设置
spring.application.name=spring-boot-data-jpa-demo

# 数据源配置
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sumlv?characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# jpa配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

entity

java 复制代码
package com.sumlv.demo.entity;

import lombok.Data;

import jakarta.persistence.*;

/**
 * 用户表
 *
 * @Auther: yuzhuo.song
 * @Date: 2026-08-27
 */
@Data
@Entity
@Table(name = "users")
public class Users {

    /**
     * ID
     */
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /**
     * 用户名
     */
    @Column(name = "user_name")
    private String userName;

    /**
     * 密码
     */
    @Column(name = "password")
    private String password;

    /**
     * 手机号
     */
    @Column(name = "phone")
    private String phone;

}

dao

java 复制代码
package com.sumlv.demo.dao;


import com.sumlv.demo.entity.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

/**
 * 用户表持久层
 *
 * @Auther: yuzhuo.song
 * @Date: 2026-08-27
 */
public interface UsersDao extends JpaRepository<Users, Long>, JpaSpecificationExecutor<Users> {

    /**
     * 自定义查询,无需实现但命名需要符合规则
     */
    List<Users> findByUserName(String userName);

    /**
     * 使用JPQL的方式查询
     */
    @Query("FROM Users WHERE id = :id")
    Users queryById(@Param("id") Long id);

    /**
     * 使用常规SQL的方式查询
     */
    @Query(value = "SELECT id, user_name, password, phone FROM users WHERE user_name LIKE :userName", nativeQuery = true)
    List<Users> queryUsersLikeUserName(@Param("userName") String userName);

    /**
     * 使用JPQL的方式修改
     */
    @Modifying(clearAutomatically = true)
    @Query("UPDATE Users SET userName = :userName WHERE id = :id")
    void updateById(@Param("id") Long id, @Param("userName") String userName);

    /**
     * 使用SQL的方式修改
     */
    @Modifying(clearAutomatically = true)
    @Query(value = "UPDATE users SET user_name = :userName, password = :password WHERE id = :id", nativeQuery = true)
    void updateById(@Param("id") Long id, @Param("userName") String userName, @Param("password") String password);

}

test

java 复制代码
package com.sumlv.demo;

import com.sumlv.demo.dao.UsersDao;
import com.sumlv.demo.entity.Users;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.junit.jupiter.api.Test;
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.data.jpa.domain.Specification;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * JPA测试
 *
 * @Auther: yuzhuo.song
 * @Date: 2026-08-27
 */
@SpringBootTest
class SpringBootDataJpaDemoApplicationTests {

	/**
	 * 持久层注入
	 */
	@Autowired
	private UsersDao dao;

	/**
	 * 测试保存
	 */
	@Test
	public void testSave() {
		Users users = new Users();
		users.setUserName("test3");
		users.setPassword("333333");
		users.setPhone("15666666666");

		dao.save(users);
	}

	/**
	 * 测试列表查询
	 */
	@Test
	public void testQuery() {
		List<Users> list = dao.findByUserName("lisi");
		System.out.println(list);
	}

	/**
	 * 测试单条查询
	 */
	@Test
	public void testQueryById() {
		Users users = dao.queryById(9L);
		System.out.println(users);
	}

	/**
	 * 测试模糊查询
	 */
	@Test
	public void testQueryUsersLikeUserName() {
		List<Users> list = dao.queryUsersLikeUserName("%es%");
		System.out.println(list);
	}

	/**
	 * 测试JPQL方式修改
	 * 修改操作如果不添加事务会报错,实际开发应该在顶层设计中控制事务
	 * 因为在测试包中,所以必须手动设置不回滚
	 */
	@Test
	@Rollback(false)
	@Transactional(rollbackFor = Exception.class)
	public void testUpdateByJPQL() {
		Long id = 8L;

		Users users = dao.queryById(id);
		System.out.println(users);

		dao.updateById(id, "test");

		users = dao.queryById(id);
		System.out.println(users);
	}

	/**
	 * 测试SQL方式修改
	 * 修改操作如果不添加事务会报错,实际开发应该在顶层设计中控制事务
	 * 因为在测试包中,所以必须手动设置不回滚
	 */
	@Test
	@Rollback(false)
	@Transactional(rollbackFor = Exception.class)
	public void testUpdateBySQL() {
		Long id = 8L;

		Users users = dao.queryById(id);
		System.out.println(users);

		dao.updateById(id, "test1", "123456");

		users = dao.queryById(id);
		System.out.println(users);
	}

	/**
	 * 测试Specification,支持条件查询、分页和排序功能
	 */
	@Test
	public void test1(){
		Specification<Users> specification = new Specification<>() {
            /**
             * 构建查询条件
             *
             * @param root 根对象,封装查询条件
             * @param criteriaQuery 基本查询
             * @param criteriaBuilder 基本查询构造器
             * @return 构件结果
             */
            @Override
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
				List<Predicate> list = new ArrayList<>();
				list.add(criteriaBuilder.like(root.get("userName"), "%st%"));
				list.add(criteriaBuilder.le(root.get("id"), 10));

				return criteriaBuilder.and(list.toArray(new Predicate[0]));
            }
        };

		Sort sort = Sort.by(Sort.Direction.DESC, "id");
		Pageable pageable = PageRequest.of(0, 3, sort);

		Page<Users> page = dao.findAll(specification, pageable);
		System.out.println(page.getTotalElements());
		System.out.println(page.getTotalPages());

		List<Users> content = page.getContent();
		System.out.println(content);
	}

}
相关推荐
某不知名網友1 小时前
C++ 深浅拷贝:从默认拷贝到 Rule of Five
java·开发语言
青山木1 小时前
Hot 100 --- 划分字母区间
java·数据结构·算法·leetcode·贪心算法
Zzzzmo_1 小时前
SpringBoot 配置文件
java·spring boot
君顾11 小时前
外卖CPS小程序开发实战指南:从零到上线的完整流程
java·开发语言·外卖
無a伟1 小时前
RabbitMq高级特性:消息确认,持久化,重试机制
java·分布式·rabbitmq
流烟默1 小时前
xxl-job 接入 Spring 的两种方式:手动装配与自动装配(含 initMethod 双启动踩坑实录)
java·spring·xxl-job
鹅城剑仙1 小时前
Spring Boot 3 全局异常处理与统一响应封装进阶实战
java·spring boot·后端
橘子汽水1682 小时前
Leetcode 208,207实现Trie前缀树,课程表
java·数据结构·算法·leetcode
tryxr2 小时前
Chat2Excel 文件服务模块剩余功能开发
java·服务器·windows·java项目·文件服务