使用Spring Data键值存储库组织数据搜索

交互式系统使用许多不同的目录,数据字典,它们是不同的状态,代码,名称等,通常,它们有很多,但每个都不大。 在结构中,它们通常具有共同的属性:代码,ID,名称等。在应用程序代码中,有许多不同的搜索,按代码,按引用ID进行比较。 可以扩展搜索,例如:按ID,按代码搜索,按条件,排序等获得列表。因此,目录被缓存,减少了对数据库的频繁访问。 在这里,我想展示一个示例,说明如何使用Spring Data键值存储库来实现这些目的。 主要思想是:在键值存储库中进行高级搜索,并且在没有对象的情况下,对数据库中的Spring数据存储库进行搜索,然后将其放置在键值存储库中。

图片

因此在Spring中有KeyValueOperations,它类似于Spring Data存储库,但是它基于Key-Value的概念进行操作,并将数据放置在HashMap结构中(我在此处写过 有关Spring Data存储库的文章 )。 对象可以是任何类型,主要是指定了键。

public class Status { @org.springframework.data.annotation.Id private long statusId; private String code; private String name; .... 

这里的键是statusId,并特别指出了注释的完整路径,以后我将使用JPA Entity,那里也有一个ID,但已经与数据库有关。
KeyValueOperations具有与Spring Data存储库中类似的方法

 interface KeyValueOperations { <T> T insert(T objectToInsert); void update(Object objectToUpdate); void delete(Class<?> type); <T> T findById(Object id, Class<T> type); <T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type); .... . 

因此,您可以为Spring bean指定java KeyValueOperations配置。

 @SpringBootApplication public class DemoSpringDataApplication { @Bean public KeyValueOperations keyValueTemplate() { return new KeyValueTemplate(keyValueAdapter()); } @Bean public KeyValueAdapter keyValueAdapter() { return new MapKeyValueAdapter(ConcurrentHashMap.class); } 

字典存储类在此处列出-ConcurrentHashMap

并且由于我将使用“ JPA实体”字典,因此将其中两个与该项目相关联。

这是“状态”和“卡片”的词典

 @Entity public class Status { @org.springframework.data.annotation.Id private long statusId; private String code; private String name; @Id @Column(name = "STATUS_ID") public long getStatusId() { return statusId; } .... @Entity public class Card { @org.springframework.data.annotation.Id private long cardId; private String code; private String name; @Id @Column(name = "CARD_ID") public long getCardId() { return cardId; } ... 

这些是与数据库表相对应的标准实体,我提请注意每个实体的两个Id注释,一个用于JPA,另一个用于KeyValueOperations

字典的结构类似,其中一个例子

 create table STATUS ( status_id NUMBER not null, code VARCHAR2(20) not null, name VARCHAR2(50) not null ); -- Create/Recreate primary, unique and foreign key constraints alter table STATUS add constraint STATUS_PK primary key (STATUS_ID) 

适用于他们的Spring Data存储库:

 @Repository public interface CardCrudRepository extends CrudRepository<Card, Long> { } @Repository public interface StatusCrudRepository extends CrudRepository<Status, Long> { } 

这是DictionaryProvider示例本身,我们在其中连接Spring数据存储库和KeyValueOperations

 @Service public class DictionaryProvider { private static Logger logger = LoggerFactory.getLogger(DictionaryProvider.class); private Map<Class, CrudRepository> repositoryMap = new HashMap<>(); @Autowired private KeyValueOperations keyValueTemplate; @Autowired private StatusCrudRepository statusRepository; @Autowired private CardCrudRepository cardRepository; @PostConstruct public void post() { repositoryMap.put(Status.class, statusRepository); repositoryMap.put(Card.class, cardRepository); } public <T> Optional<T> dictionaryById(Class<T> clazz, long id) { Optional<T> optDictionary = keyValueTemplate.findById(id, clazz); if (optDictionary.isPresent()) { logger.info("Dictionary {} found in keyValueTemplate", optDictionary.get()); return optDictionary; } CrudRepository crudRepository = repositoryMap.get(clazz); optDictionary = crudRepository.findById(id); keyValueTemplate.insert(optDictionary.get()); logger.info("Dictionary {} insert in keyValueTemplate", optDictionary.get()); return optDictionary; } .... 

在其中为存储库和KeyValueOperations安装了自动注入,然后进行简单的逻辑(此处不检查null等),我们在keyValueTemplate字典中查找,如果存在,则返回,否则通过crudRepository从数据库中提取并放置在keyValueTemplate中,并给出出来。

但是,如果所有这些都仅限于键搜索,那么可能没有什么特别的。 因此,KeyValueOperations具有广泛的CRUD操作和请求。 这是在相同的keyValueTemplate中进行搜索的示例,但是已经通过Code使用KeyValueQuery查询进行了搜索。

  public <T> Optional<T> dictionaryByCode(Class<T> clazz, String code) { KeyValueQuery<String> query = new KeyValueQuery<>(String.format("code == '%s'", code)); Iterable<T> iterable = keyValueTemplate.find(query, clazz); Iterator<T> iterator = iterable.iterator(); if (iterator.hasNext()) { return Optional.of(iterator.next()); } return Optional.empty(); } 

这是可以理解的,如果我之前通过ID搜索并将对象放入keyValueTemplate,然后通过同一对象的代码搜索将已经从keyValueTemplate返回了该对象,则将无法访问数据库。 Spring表达式语言用于描述请求。

测试例:
ID搜索

  private void find() { Optional<Status> status = dictionaryProvider.dictionaryById(Status.class, 1L); Assert.assertTrue(status.isPresent()); Optional<Card> card = dictionaryProvider.dictionaryById(Card.class, 100L); Assert.assertTrue(card.isPresent()); } 

按代码搜索

  private void findByCode() { Optional<Card> card = dictionaryProvider.dictionaryByCode(Card.class, "VISA"); Assert.assertTrue(card.isPresent()); } 

您可以通过以下方式获取数据列表

 <T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type); 

您可以在请求中指定排序

 query.setSort(Sort.by(DESC, "name")); 

材料:

弹簧数据键值

Github项目

Source: https://habr.com/ru/post/zh-CN445060/


All Articles