repository及查询方法(2.1.0.RELEASE)

  • 空Repository作为一个标记接口

创建Repository

  • Typically, your repository interface extends Repository , CrudRepository , or PagingAndSortingRepository .Alternatively, if you do not want to extend Spring Data interfaces, you can also annotate your repository interface with @RepositoryDefinition . Extending CrudRepository exposes a complete set of methods to manipulate your entities. If you prefer to be selective about the methods being exposed, copy the methods you want to expose from CrudRepository into your domain repository.
  • 典型创建Repository继承Repository或CrudRepository或PagingAndSortingRepository,除此之外,我们还可以使用注解@RepositoryDefinition注解自己的Repository接口,

@NoRepositoryBean
interface MyBaseRepository extends Repository {
    Optional findById(ID id);
     S save(S entity);
}
interface UserRepository extends MyBaseRepository {
    User findByEmailAddress(EmailAddress emailAddress);
}
  • @NoRepositoryBean
  • Make sure you add that annotation to all repository interfaces for which Spring Data should not create instances at runtime.
  • 保证每个Repository都被@NoRepositoryBean注解,以保证运行时不创建接口的实例

@NonNullApi
/** Used on the package level to declare that the default behavior for parameters and return values is to not accept or produce null values.
 *  用在package level,使不接受parameter和return value为null
 */
@NonNull
/** Used on a parameter or return value that must not be null (not needed on a parameter and return value where @NonNullApi applies).
 *  使用在parameter和return value上
 */
@Nullable
/** Used on a parameter or return value that can be null.
 *  标记parameter和return value可为null
 */
  • Throws an EmptyResultDataAccessException when the query executed does not produce a result.
  • Throws an IllegalArgumentException when the emailAddress handed to the method is null .
  • 设置Non-null行为,返回null抛出EmptyResultDataAccessException,当parameter为null时抛出IllegalArgumentException。

Using Repositories with Multiple Spring Data Modules 使用多个Spring Data 模块

  • Sometimes, applications require using more than one Spring Data module. In such cases, a repository definition must distinguish between persistence technologies. When it detects multiple repository factories on the class path, Spring Data enters strict repository configuration mode. Strict configuration uses details on the repository or the domain class to decide about Spring Data module binding for a repository definition:
  • If the repository definition extends the module-specific repository, then it is a valid candidate for the particular Spring Data module.
  • If the domain class is annotated with the module-specific type annotation, then it is a valid candidate for the particular Spring Data module. Spring Data modules accept either third-party annotations (such as JPA’s @Entity ) or provide their own annotations (such as @Document for Spring Data MongoDB and Spring Data Elasticsearch).
  • By basePackages
  • 当Spring检测到多个Repository factories时,Spring Data将进入strict配置模式;将会根据Repository或Domain class(Entity)中的详细信息决定哪一个Spring Data modules;
  • 1:看看Repository是否extends特定的module-specific repository
  • 2:看看domain class是否annotated the module-specific type annotation,而且他还接受第三方的annotation(如JPA的@Entity)
  • 3:通过@EnableXXXRepository的basePackages属性
  • 例子
/** By extends specific_repository
 *  detect JpaRepository
 */
interface MyRepository extends JpaRepository { }
@NoRepositoryBean
interface MyBaseRepository extends JpaRepository {

}
interface UserRepository extends MyBaseRepository {

}
/** By domain class
 *  detect @Entity(JPA) @Document(MongoDB)
 */
interface PersonRepository extends Repository {

}
@Entity
class Person {

}
interface UserRepository extends Repository {

}
@Document
class User {

}
/** Bad sample
 *  
 */
interface JpaPersonRepository extends Repository {

}
interface MongoDBPersonRepository extends Repository {

}
@Entity
@Document
class Person {

}

Defining Query Methods(咋定义方法)

  • The repository proxy has two ways to derive a store-specific query from the method name:
  • By deriving the query from the method name directly(直接通过method名字)
  • By using a manually defined query(手动定义query)

Query Lookup Strategies

  • The following strategies are available for the repository infrastructure to resolve the query. With XML configuration, you can configure the strategy at the namespace through the query-lookup-strategy attribute. For Java configuration, you can use the queryLookupStrategy attribute of the Enable${store}Repositories annotation. Some strategies may not be supported for particular datastores.
  • CREATE attempts to construct a store-specific query from the query method name. The general approach is to remove a given set of well known prefixes from the method name and parse the rest of the method. You can read more about query construction in “Query Creation”.
  • USE_DECLARED_QUERY tries to find a declared query and throws an exception if cannot find one. The query can be defined by an annotation somewhere or declared by other means. Consult the documentation of the specific store to find available options for that store. If the repository infrastructure does not find a declared query for the method at bootstrap time, it fails.
  • CREATE_IF_NOT_FOUND (default) combines CREATE and USE_DECLARED_QUERY . It looks up a declared query first, and, if no declared query is found, it creates a custom method name-based query. This is the default lookup strategy and, thus, is used if you do not configure anything explicitly. It allows quick query definition by method names but also custom-tuning of these queries by introducing declared queries as needed.
  • 看看下面的lookup strategies,使用XML配置时,在中通过query-lookup-strategy指定,使用Java Config时通过@EnableXXXRepository的queryLookupStrategy指定
  • CREATEstrategy表示通过约定的方法名,如约定的get,find前缀,ByXX字段名等一系列约束,具体约束可参照附录;
  • USE_DECLARED_QUERYstrategy,通过给出的query,找不到就报错,
  • CREATE_IF_NOT_FOUNDstrategy,上面两者的结合体,先找定义的query,找不到根据方法名
  • 例子
interface PersonRepository extends Repository {
    List findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
    // Enables the distinct flag for the query
    List findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
    List findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
    // Enabling ignoring case for an individual property
    List findByLastnameIgnoreCase(String lastname);
    // Enabling ignoring case for all suitable properties
    List findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
    // Enabling static ORDER BY for a query
    List findByLastnameOrderByFirstnameAsc(String lastname);
    List findByLastnameOrderByFirstnameDesc(String lastname);
}

Special parameter handling(处理特殊参数)

  • 使用Pageable和Sort(框架认识)
/** The first method lets you pass an org.springframework.data.domain.Pageable instance to the query method
 *  to dynamically add paging to your statically de�ned query. A Page knows about the total number of elements and
 *  pages available. It does so by the infrastructure triggering a count query to calculate the overall number. As this
 *  might be expensive (depending on the store used), you can instead return a Slice . A Slice only knows about
 *  whether a next Slice is available, which might be su~cient when walking through a larger result set
 */
Page findByLastname(String lastname, Pageable pageable);
Slice findByLastname(String lastname, Pageable pageable);

List findByLastname(String lastname, Sort sort);
List findByLastname(String lastname, Pageable pageable);

Pageable

public interface Pageable {

    /**
     * Returns a {@link Pageable} instance representing no pagination setup.
     *
     * @return
     */
    static Pageable unpaged() {
        return Unpaged.INSTANCE;
    }

    /**
     * Returns whether the current {@link Pageable} contains pagination information.
     *
     * @return
     */
    default boolean isPaged() {
        return true;
    }

    /**
     * Returns whether the current {@link Pageable} does not contain pagination information.
     *
     * @return
     */
    default boolean isUnpaged() {
        return !isPaged();
    }

    /**
     * Returns the page to be returned.
     *
     * @return the page to be returned.
     */
    int getPageNumber();

    /**
     * Returns the number of items to be returned.
     *
     * @return the number of items of that page
     */
    int getPageSize();

    /**
     * Returns the offset to be taken according to the underlying page and page size.
     *
     * @return the offset to be taken
     */
    long getOffset();

    /**
     * Returns the sorting parameters.
     *
     * @return
     */
    Sort getSort();

    /**
     * Returns the current {@link Sort} or the given one if the current one is unsorted.
     *
     * @param sort must not be {@literal null}.
     * @return
     */
    default Sort getSortOr(Sort sort) {

        Assert.notNull(sort, "Fallback Sort must not be null!");

        return getSort().isSorted() ? getSort() : sort;
    }

    /**
     * Returns the {@link Pageable} requesting the next {@link Page}.
     *
     * @return
     */
    Pageable next();

    /**
     * Returns the previous {@link Pageable} or the first {@link Pageable} if the current one already is the first one.
     *
     * @return
     */
    Pageable previousOrFirst();

    /**
     * Returns the {@link Pageable} requesting the first page.
     *
     * @return
     */
    Pageable first();

    /**
     * Returns whether there's a previous {@link Pageable} we can access from the current one. Will return
     * {@literal false} in case the current {@link Pageable} already refers to the first page.
     *
     * @return
     */
    boolean hasPrevious();

    /**
     * Returns an {@link Optional} so that it can easily be mapped on.
     *
     * @return
     */
    default Optional toOptional() {
        return isUnpaged() ? Optional.empty() : Optional.of(this);
    }
}

Sort

public class Sort implements Streamable, Serializable {

    private static final long serialVersionUID = 5737186511678863905L;

    private static final Sort UNSORTED = Sort.by(new Order[0]);

    public static final Direction DEFAULT_DIRECTION = Direction.ASC;

    private final List orders;

    /**
     * Creates a new {@link Sort} instance using the given {@link Order}s.
     *
     * @param orders must not be {@literal null}.
     */
    @Deprecated
    public Sort(Order... orders) {
        this(Arrays.asList(orders));
    }

    /**
     * Creates a new {@link Sort} instance.
     *
     * @param orders must not be {@literal null} or contain {@literal null}.
     * @deprecated see {@link Sort#by(List)}
     */
    @Deprecated
    public Sort(List orders) {

        Assert.notNull(orders, "Orders must not be null!");

        this.orders = Collections.unmodifiableList(orders);
    }

    /**
     * Creates a new {@link Sort} instance. Order defaults to {@value Direction#ASC}.
     *
     * @param properties must not be {@literal null} or contain {@literal null} or empty strings
     * @deprecated use {@link Sort#by(String...)}
     */
    @Deprecated
    public Sort(String... properties) {
        this(DEFAULT_DIRECTION, properties);
    }

    /**
     * Creates a new {@link Sort} instance.
     *
     * @param direction defaults to {@link Sort#DEFAULT_DIRECTION} (for {@literal null} cases, too)
     * @param properties must not be {@literal null}, empty or contain {@literal null} or empty strings.
     */
    public Sort(Direction direction, String... properties) {
        this(direction, properties == null ? new ArrayList<>() : Arrays.asList(properties));
    }

    /**
     * Creates a new {@link Sort} instance.
     *
     * @param direction defaults to {@link Sort#DEFAULT_DIRECTION} (for {@literal null} cases, too)
     * @param properties must not be {@literal null} or contain {@literal null} or empty strings.
     */
    public Sort(Direction direction, List properties) {

        if (properties == null || properties.isEmpty()) {
            throw new IllegalArgumentException("You have to provide at least one property to sort by!");
        }

        this.orders = new ArrayList<>(properties.size());

        for (String property : properties) {
            this.orders.add(new Order(direction, property));
        }
    }

    /**
     * Creates a new {@link Sort} for the given properties.
     *
     * @param properties must not be {@literal null}.
     * @return
     */
    public static Sort by(String... properties) {

        Assert.notNull(properties, "Properties must not be null!");

        return properties.length == 0 ? Sort.unsorted() : new Sort(properties);
    }

    /**
     * Creates a new {@link Sort} for the given {@link Order}s.
     *
     * @param orders must not be {@literal null}.
     * @return
     */
    public static Sort by(List orders) {

        Assert.notNull(orders, "Orders must not be null!");

        return orders.isEmpty() ? Sort.unsorted() : new Sort(orders);
    }

    /**
     * Creates a new {@link Sort} for the given {@link Order}s.
     *
     * @param orders must not be {@literal null}.
     * @return
     */
    public static Sort by(Order... orders) {

        Assert.notNull(orders, "Orders must not be null!");

        return new Sort(orders);
    }

    /**
     * Creates a new {@link Sort} for the given {@link Order}s.
     *
     * @param direction must not be {@literal null}.
     * @param properties must not be {@literal null}.
     * @return
     */
    public static Sort by(Direction direction, String... properties) {

        Assert.notNull(direction, "Direction must not be null!");
        Assert.notNull(properties, "Properties must not be null!");
        Assert.isTrue(properties.length > 0, "At least one property must be given!");

        return Sort.by(Arrays.stream(properties)//
                .map(it -> new Order(direction, it))//
                .collect(Collectors.toList()));
    }

    /**
     * Returns a {@link Sort} instances representing no sorting setup at all.
     *
     * @return
     */
    public static Sort unsorted() {
        return UNSORTED;
    }

    /**
     * Returns a new {@link Sort} with the current setup but descending order direction.
     *
     * @return
     */
    public Sort descending() {
        return withDirection(Direction.DESC);
    }

    /**
     * Returns a new {@link Sort} with the current setup but ascending order direction.
     *
     * @return
     */
    public Sort ascending() {
        return withDirection(Direction.ASC);
    }

    public boolean isSorted() {
        return !orders.isEmpty();
    }

    public boolean isUnsorted() {
        return !isSorted();
    }

    /**
     * Returns a new {@link Sort} consisting of the {@link Order}s of the current {@link Sort} combined with the given
     * ones.
     *
     * @param sort must not be {@literal null}.
     * @return
     */
    public Sort and(Sort sort) {

        Assert.notNull(sort, "Sort must not be null!");

        ArrayList these = new ArrayList<>(this.orders);

        for (Order order : sort) {
            these.add(order);
        }

        return Sort.by(these);
    }

    /**
     * Returns the order registered for the given property.
     *
     * @param property
     * @return
     */
    @Nullable
    public Order getOrderFor(String property) {

        for (Order order : this) {
            if (order.getProperty().equals(property)) {
                return order;
            }
        }

        return null;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Iterable#iterator()
     */
    public Iterator iterator() {
        return this.orders.iterator();
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(@Nullable Object obj) {

        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Sort)) {
            return false;
        }

        Sort that = (Sort) obj;

        return this.orders.equals(that.orders);
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {

        int result = 17;
        result = 31 * result + orders.hashCode();
        return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return orders.isEmpty() ? "UNSORTED" : StringUtils.collectionToCommaDelimitedString(orders);
    }

    /**
     * Creates a new {@link Sort} with the current setup but the given order direction.
     *
     * @param direction
     * @return
     */
    private Sort withDirection(Direction direction) {

        return Sort.by(orders.stream().map(it -> new Order(direction, it.getProperty())).collect(Collectors.toList()));
    }

    /**
     * Enumeration for sort directions.
     *
     * @author Oliver Gierke
     */
    public static enum Direction {

        ASC, DESC;

        /**
         * Returns whether the direction is ascending.
         *
         * @return
         * @since 1.13
         */
        public boolean isAscending() {
            return this.equals(ASC);
        }

        /**
         * Returns whether the direction is descending.
         *
         * @return
         * @since 1.13
         */
        public boolean isDescending() {
            return this.equals(DESC);
        }

        /**
         * Returns the {@link Direction} enum for the given {@link String} value.
         *
         * @param value
         * @throws IllegalArgumentException in case the given value cannot be parsed into an enum value.
         * @return
         */
        public static Direction fromString(String value) {

            try {
                return Direction.valueOf(value.toUpperCase(Locale.US));
            } catch (Exception e) {
                throw new IllegalArgumentException(String.format(
                        "Invalid value '%s' for orders given! Has to be either 'desc' or 'asc' (case insensitive).", value), e);
            }
        }

        /**
         * Returns the {@link Direction} enum for the given {@link String} or null if it cannot be parsed into an enum
         * value.
         *
         * @param value
         * @return
         */
        public static Optional fromOptionalString(String value) {

            try {
                return Optional.of(fromString(value));
            } catch (IllegalArgumentException e) {
                return Optional.empty();
            }
        }
    }

    /**
     * Enumeration for null handling hints that can be used in {@link Order} expressions.
     *
     * @author Thomas Darimont
     * @since 1.8
     */
    public static enum NullHandling {

        /**
         * Lets the data store decide what to do with nulls.
         */
        NATIVE,

        /**
         * A hint to the used data store to order entries with null values before non null entries.
         */
        NULLS_FIRST,

        /**
         * A hint to the used data store to order entries with null values after non null entries.
         */
        NULLS_LAST;
    }

    /**
     * PropertyPath implements the pairing of an {@link Direction} and a property. It is used to provide input for
     * {@link Sort}
     *
     * @author Oliver Gierke
     * @author Kevin Raymond
     */
    public static class Order implements Serializable {

        private static final long serialVersionUID = 1522511010900108987L;
        private static final boolean DEFAULT_IGNORE_CASE = false;
        private static final NullHandling DEFAULT_NULL_HANDLING = NullHandling.NATIVE;

        private final Direction direction;
        private final String property;
        private final boolean ignoreCase;
        private final NullHandling nullHandling;

        /**
         * Creates a new {@link Order} instance. if order is {@literal null} then order defaults to
         * {@link Sort#DEFAULT_DIRECTION}
         *
         * @param direction can be {@literal null}, will default to {@link Sort#DEFAULT_DIRECTION}
         * @param property must not be {@literal null} or empty.
         */
        public Order(@Nullable Direction direction, String property) {
            this(direction, property, DEFAULT_IGNORE_CASE, DEFAULT_NULL_HANDLING);
        }

        /**
         * Creates a new {@link Order} instance. if order is {@literal null} then order defaults to
         * {@link Sort#DEFAULT_DIRECTION}
         *
         * @param direction can be {@literal null}, will default to {@link Sort#DEFAULT_DIRECTION}
         * @param property must not be {@literal null} or empty.
         * @param nullHandling must not be {@literal null}.
         */
        public Order(@Nullable Direction direction, String property, NullHandling nullHandlingHint) {
            this(direction, property, DEFAULT_IGNORE_CASE, nullHandlingHint);
        }

        /**
         * Creates a new {@link Order} instance. Takes a single property. Direction defaults to
         * {@link Sort#DEFAULT_DIRECTION}.
         *
         * @param property must not be {@literal null} or empty.
         * @deprecated since 2.0, use {@link Order#by(String)}.
         */
        @Deprecated
        public Order(String property) {
            this(DEFAULT_DIRECTION, property);
        }

        /**
         * Creates a new {@link Order} instance. Takes a single property. Direction defaults to
         * {@link Sort#DEFAULT_DIRECTION}.
         *
         * @param property must not be {@literal null} or empty.
         * @since 2.0
         */
        public static Order by(String property) {
            return new Order(DEFAULT_DIRECTION, property);
        }

        /**
         * Creates a new {@link Order} instance. Takes a single property. Direction is {@link Direction#ASC} and
         * NullHandling {@link NullHandling#NATIVE}.
         *
         * @param property must not be {@literal null} or empty.
         * @since 2.0
         */
        public static Order asc(String property) {
            return new Order(Direction.ASC, property, DEFAULT_NULL_HANDLING);
        }

        /**
         * Creates a new {@link Order} instance. Takes a single property. Direction is {@link Direction#ASC} and
         * NullHandling {@link NullHandling#NATIVE}.
         *
         * @param property must not be {@literal null} or empty.
         * @since 2.0
         */
        public static Order desc(String property) {
            return new Order(Direction.DESC, property, DEFAULT_NULL_HANDLING);
        }

        /**
         * Creates a new {@link Order} instance. if order is {@literal null} then order defaults to
         * {@link Sort#DEFAULT_DIRECTION}
         *
         * @param direction can be {@literal null}, will default to {@link Sort#DEFAULT_DIRECTION}
         * @param property must not be {@literal null} or empty.
         * @param ignoreCase true if sorting should be case insensitive. false if sorting should be case sensitive.
         * @param nullHandling must not be {@literal null}.
         * @since 1.7
         */
        private Order(@Nullable Direction direction, String property, boolean ignoreCase, NullHandling nullHandling) {

            if (!StringUtils.hasText(property)) {
                throw new IllegalArgumentException("Property must not null or empty!");
            }

            this.direction = direction == null ? DEFAULT_DIRECTION : direction;
            this.property = property;
            this.ignoreCase = ignoreCase;
            this.nullHandling = nullHandling;
        }

        /**
         * Returns the order the property shall be sorted for.
         *
         * @return
         */
        public Direction getDirection() {
            return direction;
        }

        /**
         * Returns the property to order for.
         *
         * @return
         */
        public String getProperty() {
            return property;
        }

        /**
         * Returns whether sorting for this property shall be ascending.
         *
         * @return
         */
        public boolean isAscending() {
            return this.direction.isAscending();
        }

        /**
         * Returns whether sorting for this property shall be descending.
         *
         * @return
         * @since 1.13
         */
        public boolean isDescending() {
            return this.direction.isDescending();
        }

        /**
         * Returns whether or not the sort will be case sensitive.
         *
         * @return
         */
        public boolean isIgnoreCase() {
            return ignoreCase;
        }

        /**
         * Returns a new {@link Order} with the given {@link Direction}.
         *
         * @param direction
         * @return
         */
        public Order with(Direction direction) {
            return new Order(direction, this.property, this.ignoreCase, this.nullHandling);
        }

        /**
         * Returns a new {@link Order}
         *
         * @param property must not be {@literal null} or empty.
         * @return
         * @since 1.13
         */
        public Order withProperty(String property) {
            return new Order(this.direction, property, this.ignoreCase, this.nullHandling);
        }

        /**
         * Returns a new {@link Sort} instance for the given properties.
         *
         * @param properties
         * @return
         */
        public Sort withProperties(String... properties) {
            return Sort.by(this.direction, properties);
        }

        /**
         * Returns a new {@link Order} with case insensitive sorting enabled.
         *
         * @return
         */
        public Order ignoreCase() {
            return new Order(direction, property, true, nullHandling);
        }

        /**
         * Returns a {@link Order} with the given {@link NullHandling}.
         *
         * @param nullHandling can be {@literal null}.
         * @return
         * @since 1.8
         */
        public Order with(NullHandling nullHandling) {
            return new Order(direction, this.property, ignoreCase, nullHandling);
        }

        /**
         * Returns a {@link Order} with {@link NullHandling#NULLS_FIRST} as null handling hint.
         *
         * @return
         * @since 1.8
         */
        public Order nullsFirst() {
            return with(NullHandling.NULLS_FIRST);
        }

        /**
         * Returns a {@link Order} with {@link NullHandling#NULLS_LAST} as null handling hint.
         *
         * @return
         * @since 1.7
         */
        public Order nullsLast() {
            return with(NullHandling.NULLS_LAST);
        }

        /**
         * Returns a {@link Order} with {@link NullHandling#NATIVE} as null handling hint.
         *
         * @return
         * @since 1.7
         */
        public Order nullsNative() {
            return with(NullHandling.NATIVE);
        }

        /**
         * Returns the used {@link NullHandling} hint, which can but may not be respected by the used datastore.
         *
         * @return
         * @since 1.7
         */
        public NullHandling getNullHandling() {
            return nullHandling;
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {

            int result = 17;

            result = 31 * result + direction.hashCode();
            result = 31 * result + property.hashCode();
            result = 31 * result + (ignoreCase ? 1 : 0);
            result = 31 * result + nullHandling.hashCode();

            return result;
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(@Nullable Object obj) {

            if (this == obj) {
                return true;
            }

            if (!(obj instanceof Order)) {
                return false;
            }

            Order that = (Order) obj;

            return this.direction.equals(that.direction) && this.property.equals(that.property)
                    && this.ignoreCase == that.ignoreCase && this.nullHandling.equals(that.nullHandling);
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {

            String result = String.format("%s: %s", property, direction);

            if (!NullHandling.NATIVE.equals(nullHandling)) {
                result += ", " + nullHandling;
            }

            if (ignoreCase) {
                result += ", ignoring case";
            }

            return result;
        }
    }
}

Limiting Query Results(限制查询结果)

  • The results of query methods can be limited by using the first or topkeywords, which can be used interchangeably. An optional numeric value can be appended to top or first to specify the maximum result size to be returned. If the number is left out, a result size of 1 is assumed. The following example shows how to limit the query size:
  • The limiting expressions also support the Distinct keyword. Also, for the queries limiting the result set to one instance, wrapping the result into with the Optional keyword is supported.
  • 可通过top first来限制查询的结果数量,操作如下
  • 还可以使用DistinctOptional(将结果wrap进Optional,可用与处理null)
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page queryFirst10ByLastname(String lastname, Pageable pageable);
Slice findTop3ByLastname(String lastname, Pageable pageable);
List findFirst10ByLastname(String lastname, Sort sort);
List findTop10ByLastname(String lastname, Pageable pageable);

Streaming query results(Stream query结果)

  • The results of query methods can be processed incrementally by using a Java 8 Stream as return type. Instead of wrapping the query results in a Stream data store-specific methods are used to perform the streaming, as shown in the following example:
  • 我么可以返回Java8 Stream,见如下样例
@Query("select u from User u")
Stream findAllByCustomQueryAndStream();
Stream readAllByFirstnameNotNull();
@Query("select u from User u")
Stream streamAllPaged(Pageable pageable);
  • A Stream potentially wraps underlying data store-specific resources and must, therefore, be closed after usage,You can either manually close
    the Stream by using close() method or by using a Java 7 try-with-resources blocks,as shown in the following example:
try (Stream stream = repository.findAllByCustomQueryAndStream()) {
    stream.forEach(…);
}

Not all Spring Data modules currently support Stream as a return type


Async query results(异步查询)

  • Repository queries can be run asynchronously by using Spring’s asynchronous method execution capability. This means the method returns immediately upon invocation while the actual query execution occurs in a task that has been submitted to a Spring TaskExecutor . Asynchronous query execution is difierent from reactive query
    execution and should not be mixed. Refer to store-specific documentation for more details on reactive support. The following example shows a number of asynchronous queries:
  • 异步查询和reactive查询不同,不应该混合使用
/**
 *  Use java.util.concurrent.Future as the return type.
 */
@Async
Future findByFirstname(String firstname);
/**
 *  Use a Java 8 java.util.concurrent.CompletableFuture as the return type
 */
@Async
CompletableFuture findOneByFirstname(String firstname);
/**
 *  Use a org.springframework.util.concurrent.ListenableFuture as the return type
 */
@Async
ListenableFuture findOneByLastname(String lastname);

你可能感兴趣的:(repository及查询方法(2.1.0.RELEASE))