Spring Data 2021.1 (Q)升级说明

发布于:2024-04-14 ⋅ 阅读:(130) ⋅ 点赞:(0)

Spring Data 2021.1 (Q) Release Notes

Spring Data Commons—2.6版本

1、域模型现jMolecules增加了@Identity注解

2、QuerydslPredicateExecutor、QueryByExampleExecutor 及其响应式变体为 Spring Data 提供了强大的查询构建能力。它们允许你以更灵活和动态的方式定义查询,支持流式处理结果,并提供了与多种存储模块和响应式编程框架的集成。通过使用这些接口和特性,你可以构建出更高效、更易于维护的查询逻辑。

(1)QueryDslPredicateExecutor是Spring Data JPA提供的一个接口,用于在查询中使用动态条件。它允许开发人员根据不同的查询条件动态构建查询语句,而无需手动编写SQL语

       // 1. 添加依赖
       // pom.xml
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-jpa</artifactId>
       </dependency>
       <dependency>
           <groupId>com.querydsl</groupId>
           <artifactId>querydsl-jpa</artifactId>
       </dependency>

       // 2. 创建实体类
       @Entity
       @Table(name = "users")
       @QueryEntity
       public class User {
           @Id
           @GeneratedValue(strategy = GenerationType.IDENTITY)
           private Long id;

           private String username;
           private String email;
           // other fields, getters, and setters
       }

       // 3. 创建查询接口
       public interface UserRepository extends JpaRepository<User, Long>, QueryDslPredicateExecutor<User> {
       }

       // 4. 使用动态条件查询
       @Service
       public class UserService {
           @Autowired
           private UserRepository userRepository;

           public List<User> searchUsers(String username, String email) {
               QUser qUser = QUser.user;
               BooleanExpression predicate = qUser.username.eq(username)
                       .and(qUser.email.eq(email));

               return (List<User>) userRepository.findAll(predicate);
           }
       }

(2)QueryByExampleExecutor是一种查询技术,允许动态创建查询,并且不需要编写包含字段名称的查询

	public interface QueryByExampleExecutor<T> {
	    // 根据实例查找一个对象
	    <S extends T> Optional<S> findOne(Example<S> var1);
	    // 根据实例查找一批对象
	    <S extends T> Iterable<S> findAll(Example<S> var1);
	    // 根据实例查找一批对象,且排序
	    <S extends T> Iterable<S> findAll(Example<S> var1, Sort var2);
	    // 根据实例查找一批对象,且排序和分页
	    <S extends T> Page<S> findAll(Example<S> var1, Pageable var2);
	    // 根据实例查找,返回符合条件的对象个数
	    <S extends T> long count(Example<S> var1);
	    // 根据实例查找,返回符合条件的对象
	    <S extends T> boolean exists(Example<S> var1);
	}
@Test
public void testQBE() {
    SystemUser systemUser = new SystemUser();
    systemUser.setUname("li");

    ExampleMatcher matcher = ExampleMatcher.matching()
            .withMatcher("uname", ExampleMatcher.GenericPropertyMatchers.startsWith());
    Example<SystemUser> example = Example.of(systemUser, matcher);
    List<SystemUser> systemUserList = this.userRepository.findAll(example);
    System.out.println(systemUserList);
}

3、Spring Data JPA提供了@DomainEvents注解,用于在deleteInBatch 和 deleteAllInBatch发布事件。

4、Spring Data引入Uni和Multi类型作为存储库查询方法的返回类型,支持响应式编程模型,特别是在处理大量数据或需要非阻塞操作的情况下。Uni代表一个可能发出单个项的响应式序列,而Multi代表一个可能发出零个或多个项的响应式序列。不是所有的数据库和存储系统都支持响应式编程模型。因此,在选择使用响应式存储库时,你需要确保你的目标存储系统支持响应式操作。

5、Spring Data 3.0不再支持RxJava 2。RxJava 2在2021年2月28日就结束了,我们建议使用RxJava 3。(RxJava是一个Java VM实现的响应式扩展(Reactive Extensions)库)

Spring Data JPA - 2.6

1、JpaRepositoryFactory.getRepositoryFragments(RepositoryMetadata, EntityManager, EntityPathResolver, CrudMethodMetadata)允许自定义片段,提供更多的上下文信息,而不需要对字段进行反射访问。

Spring Data MongoDB - 3.3

1、当使用@DocumentReference注解时,Spring Data MongoDB会自动处理引用的解析。在存储时,它通常会将引用的实体ID值存储为对另一个文档的引用。在检索时,它会使用这个ID值去查找并加载相应的实体。使用@DocumentReference注解时,需要考虑到性能问题。如果频繁地进行跨文档查询或加载操作,可能会对性能产生一定的影响。因此,在设计数据模型时,需要权衡好灵活性和性能之间的关系

class Account {
  @Id String id;
}

class Person {

  @Id String id;

  @DocumentReference List<Account> accounts;
}

2、添加对创建时间序列集合的支持

MongoDB 5.0引入了时间序列集合,springDateMongoDB支持创建时间序列集合。

@TimeSeries(collection = "weather", timeField = "timestamp")
public class Measurement {
    String id;
    Instant timestamp;
    // ...
}

3、支持通配符索引(在MongoDB中,通配符索引(Wildcard Index)允许你使用通配符来索引文档中的任意字段,例:db.yourCollectionName.createIndex({“$**”: 1})
)

@Document
@WildcardIndexed
public class Product {
	// …
}
Document
@WildcardIndexed(wildcardProjection = "{ 'userMetadata.age' : 0 }")
public class User {
    private @Id String id;
    private UserMetadata userMetadata;
}
@Document
public class User {
    private @Id String id;

    @WildcardIndexed
    private UserMetadata userMetadata;
}

4、写入时包含/排除 null 属性

从实体写入 Document 时,跳过值为 null 的属性。 @Field(write=…) 可以用来控制是否跳过(默认)此类属性,或者是否强制将 null 属性写入 Document

5、加密属性的模式派生

可以使用@Encrypted对字段进行加密

@Document
@Encrypted(keyId = "xKVup8B1Q+CkHaVRx+qa+g==", algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random") 
static class Patient {

    @Id String id;
    String name;

    @Encrypted 
    String bloodType;

    @Encrypted(algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic") 
    Integer ssn;
}

Spring Data Couchbase - 4.3

1、优化IN查询绑定标记计算

当结合使用IN关系和绑定标记进行查询时,每一个IN列表中的元素都会生成一个独立的绑定标记。这意味着,如果IN列表很长,查询准备阶段会创建大量的绑定标记,这不仅增加了内存使用量,而且可能导致性能下降,特别是在缓存准备好的语句时。

这一版本对此进行了优化。现在,当使用IN关系和绑定标记时,Spring Data Couchbase会使用单个参数绑定标记来代替多个绑定标记。这意味着,不论IN列表中有多少个元素,都只会创建一个绑定标记。这样做的好处是显著减少了内存使用,并提高了查询准备的效率。

Spring Data Redis - 2.6

1、从这个版本开始,您可以使用Redis 6.2命令,例如 LMOVE / BLMOVE , ZMSCORE , ZRANDMEMBER , HRANDFIELD ,以及更多。有关引入的命令的完整列表,请参阅2.6.0-M1发行说明。

2、RedisURI-based configuration of LettuceConnectionFactory
可以使用 RedisURI 来简化 Lettuce 连接工厂的配置。RedisURI 类提供了一种方便的方式来表示 Redis 服务器的 URI,并包含所有必要的连接参数,如主机名、端口、密码等

import io.lettuce.core.RedisURI;  
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
  
@Configuration  
public class RedisConfig {  
  
    @Bean  
    public LettuceConnectionFactory redisConnectionFactory() {  
        RedisURI redisUri = RedisURI.create("redis://user:password@localhost:6379/0");  
        return new LettuceConnectionFactory(redisUri);  
    }  
  
    @Bean  
    public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {  
        RedisTemplate<Object, Object> template = new RedisTemplate<>();  
        template.setConnectionFactory(redisConnectionFactory);  
        return template;  
    }  
}

3、为 RedisCache 配置批处理策略

RedisCacheManagerBuilder.fromCacheWriter(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, BatchStrategies.scan(42)));

4、MessageListener 可以监听已订阅或未订阅的事件

当使用 MessageListener 进行订阅确认回调时,此版本包括对 SubscriptionListener 的支持,当订阅成功或失败时,它可以提供回调方法,以便开发者能够执行相应的操作

ReactiveRedisMessageListenerContainer和ReactiveRedisOperations提供的receiveLater(…)和listenToLater(…)方法则是用于异步处理Redis订阅的。这些方法允许你将接收到的消息或订阅事件延迟处理,以便在稍后的时间点或不同的线程中处理它们。这对于需要高并发或低延迟的应用程序来说是非常有用的,因为它可以帮助避免阻塞主线程并提高系统的响应性。

使用receiveLater(…)和listenToLater(…)方法时,你可以将它们与Spring的反应式编程模型(如Flux和Mono)结合使用,以实现更复杂的异步处理逻辑。例如,你可以将接收到的消息发布到一个反应式流中,并在流的下游进行进一步的处理、转换或聚合。

Spring Data JDBC - 2.3

1、对大型结果集进行流式处理

JDBC存储库查询方法现在可以直接从 ResultSet 返回 Stream ,而不是将结果收集到一个List 中。这种改变减少了内存压力和延迟,直到第一个结果出现。

interface PersonRepository extends CrudRepository<Person, Long> {

	@Query("SELECT * FROM person WHERE name  < :upper and name > :lower")
	Stream<Person> findAsStream(String lower, String upper);
}

2、现在可以通过使用接口或DTO投影(包括动态投影)来返回投影。注意,当指定自定义 RowMapper 时,不能使用投影。

(1)接口投影

interface NamesOnly {

  String getFirstname();
  String getLastname();
}

interface PersonRepository extends Repository<Person, UUID> {

  Collection<NamesOnly> findByLastname(String lastname);
}

(2)DTO投影

import lombok.Value;
/**
 *使用DTO的方式返回用户名,需要构造函数,我们使用lombok的@Value方法来简化代码
 */
@Value
public class UsernameDTO{
    private String userName;
}

(3)动态投影

interface PersonRepository extends Repository<Person, UUID> {

  <T> Collection<T> findByLastname(String lastname, Class<T> type);
}

void someMethod(PersonRepository people) {

  Collection<Person> aggregates =
    people.findByLastname("Matthews", Person.class);

  Collection<NamesOnly> aggregates =
    people.findByLastname("Matthews", NamesOnly.class);
}