* MongoOperations는 MongoDB를 사용하기 위한, 여러 유용한 메소드를 제공한다. 아래는 그러한 메소드들의 예시이다.
// 컬렉션을 가지고, 해당 컬렉션의 수를 세는 count()
long orderCount = mongo.getCollection("order").count();
// 새 객체를 저장하는 save()
Order order = new Order();
order.set~~~ // 객체 값 설정
~~~
mongo.save(order, "order");
// ID에 따라 검색을 하는 findById()
String orderId = test;
Order order = mongo.findById(orderId, Order.class);
// Query로 고급 검색을 가능할게 하는 find()
List<Order> chucksOrders = mongo.find(Query.query(
Criteria.where("client").is("Chuck Wagon")), Order.class);
// 클라이언트필드가 "Chuck Wagon"인 모든 케이스
List<Order> chucksWebOrders = mongo.find(Query.query(
Criteria.where("customer").is("Chuck Wagon")
.and("type").is("WEB")), Order.class);
// Crieteria는 한 개의 필드를 체크하는 쿼리를 생성하기 위해 사용. WEB을 통해 Chuck의 모든 Order를 얻음
// 도큐먼트를 삭제하는 remove()
mongo.remove(order);
MongoDB 저장소 작성
* 일반적으로, 만든 저장소 클래스에 MongoOperations를 주입하고 메소드를 구현한다. 그러나 저장소를 작성하는데 애를 쓰고 싶지 않다면, 런타임 시에 자동으로 저장소를 구현하게 한다.
OrderRepository 인터페이스로, Order 도큐먼트를 위한 기본 CRUD 동작을 제공하기 위해 MongoRepository를 확장한다.
public interface OrderOperations {
List<Order> findOrdersByType(String t);
}
// 중간 버전의 인터페이스 정의
Impl 사용
public class OrderRepositoryImpl implements OrderOperations {
@Autowired
private MongoOperations mongo; // MongoOperation 주입
public List<Order> findOrdersByType(String t) {
String type = t.equals("NET") ? "WEB" : t;
Criteria where = Criteria.where("type").is(t);
Query query = Query.query(where); // 쿼리 생성
return mongo.find(query, Order.class); // 쿼리 수행
}
}
마지막으로 중간버전의 인터페이스 확장을 위한, 저장소 인터페이스 변경
public interface OrderRepository
extends MongoRepository<Order, String>, OrderOperations { ~~~ }
Neo4j로 그래프 데이터 사용하기
Neo4j : 그래프 데이터베이스 - 관계를 저장하고 탐색하도록 특별히 구축되었습니다. 노드를 사용하여 데이터 엔터티를 저장하고 엣지로는 엔터티 간의 관계를 저장합니다. 엣지는 항상 시작 노드, 끝 노드, 유형과 방향을 가지며, 상-하위 관계, 동작, 소유자 등을 문서화 합니다. 하나의 노드가 가질 수 있는 관계의 수와 종류에는 제한이 없음.
* MongoDB와 JPA와 동일한 기능을 제공한다
스프링으로 Neo4j 설정하기
@EnableNeo4jRepositories : Neo4j 자동저장소 활성화 애너테이션
@Configuration
@EnableNeo4jRepositories(basePackages="orders.db") // 자동 저장소 활성화, marker Repository 확장 후, 인터페이스용 db 패키지를 스캔
public class Neo4jConfig extends Neo4jConfiguration {
public Neo4jConfig() { // 생성자, orders패키지의, 모델 클래스를 찾는다
setBasePackage("orders"); // 모델 베이스 패키지 세팅
}
@Bean(destroyMethod="shutdown")
public GraphDatabaseService graphDatabaseService() { // 참조하는 그래프데이터베이스
return new GraphDatabaseFactory()
.newEmbeddedDatabase("/tmp/graphdb"); // 임베디드 데이터베이스 패키지 설정(인메모리 아님), 애플리케이션의 일부로 JVM 내에서 동작
}
/*
@Bean(destroyMethod="shutdown")
public GraphDatabaseService graphDatabaseService() {
return new SpringRestGraphDatabase(
"http://grephdb:7575/db/data/", env.getProperty("db.username"), env.getProperty("db.password")
);
// 원격서버 + 보안 요소가 있는 경우
}
*/
}
그래프 엔티티 애너테이션
Neo4j에서는, 아래의 애너테이션을 사용하여, 노드와 관계 등을 애너테이션 한다.
노드 엔티티는, @NodeEntity.. 관계 엔티티는 @RelationshipEntity로 애너테이션 한다. 단순한 노드끼리의 관계는 @RelationTo 애너테이션으로 정의 가능
@NodeEntity // Order는 노드엔티티
public class Order {
@GraphId // 그래프 아이디
private Long id;
private String customer;
private String type;
// items 프로퍼티는, Order와 Item의 Set에 관계됨
@RelatedTo(type="HAS_ITEMS")
private Set<Item> items = new LinkedHashSet<Item>();
~~~
}
@NodeEntity // 아이템 노드
public class Item {
@GraphId // 그래프의 아이디
private Long id;
private String product;
private double price;
private int quantity;
~~~
}
==>조금 더 복잡한 경우
* @RelationShipEntity 사용 !!
@RelationshipEntity(type="HAS_LINE_ITEM_FOR") // 관계엔티티, 타입 정의
public class LineItem {
@GraphId // 그래프 아이디
private Long id;
@StartNode // 시작 노드
private Order order;
@EndNode // 끝나는 노드
private Product product;
// 관계엔티티의 자체 프로퍼티
private int quantity;
~~~
}
* LineItem 관계 생성 시, 데이터베이스 내에 유지되는 quanity 프로퍼티를 가진다.
Neo4jTemplate 사용하기
* MongoDB의 경우처럼, Neo4jConfiguration을 확장한다면, Neoj4Template빈이 자동으로 생성됨
// 마찬가지로, Neo4jOpreations로 직접 오토와이어링
@Autowired
private Neo4Operations neo4j;
* Neo4Operations도 마찬가지로 Neo4j를 사용하기 위한, 여러 유용한 메소드를 제공한다. 아래는 그러한 메소드들의 예시이다.
// save() 메소드
Order order = ...;
Order savedOrder = neo4j.save(order);
// findOne() 메소드 - id기반 // 존재하지 않으면 NotFoundException
Order order = neo4j.findOne(42, Order.class);
// 객체 전부 검색 findAll()
EndResult<Order> allOrders = neo4j.findAll(Order.class);
// count()
long orderCount = count(Order.class);
// delete()
neo4j.delete(order);
// 가장 특이한 메소드중 하나 createRelastionshipBetween() 메소드 -- 두 노드간의 관계를 만든다
Order order = ...;
Product prod = ...;
LineItem lineItem = neo4j.createRelationshipBetween(order, prod, LineItem.class, "HAS_LINE_ITEM_FOR", false); // order와 prod간의 LineItem 관계를 생성(type - HAS_LINE_ITEM_FOR)
lineItem.setQuantity(5);
neo4j.save(lineItem);
자동 저장소 만들기
MongoDB와 동일.. 겹치는 내용이 많아서 코드와 간단한 설명정도만 남김.
* GraphRepsitory 인터페이스 확장
public interface OrderRepository extends GraphRepository<Order> {}
* 확장으로 얻는 메소드
* Order saveOrder = orderRepository.save(order) 등, 간단하게 사용 가능
맞춤형 쿼리 메소드
=> MongoDB나 JPA와 명명규칙은 같지만, 앞의 둘과는 달리 OrderRepository에 쿼리 메소드를 따로 지정해주어야함
public interface OrderRepository extends GraphRepository<Order> {
List<Order> findByCustomer(String customer);
List<Order> findByCustomerAndType(String customer, String type); // 다른 메소드와 유사하며, 주어진 타입의 type 프로퍼티를 가진다.
}
@Bean
public RedisConnectionFactory redisCF() {
JedisConnectionFactory cf = new JedisConnectionFactory();
cf.setHostName("redis-server"); // 호스트 서버 설정
cf.setPort(7379); // 포트 설정
cf.setPassword("foobared"); // 비밀번호 설정
return cf;
}
하지만, 실제로 byte배열보다는, 상위 레벨의 데이터 액세스가 필요하다. 스프링데이터 Redis 이럴 때 사용할 수 있는 2가지의 Template을 제공한다.
** RedisTemplate ** StringRedisTemplate(키, 밸류가 모두 String일 경우 권장)
RedisConnectionFactory cf = ~~;
RedisTemplate<String, Product> redis = new RedisTemplate<String, Product>();
redis.setConnectionFactory(cf); // 일반 RedisTemplate의 경우엔 지정을 해주어야함
=====
/// 자주 사용할 경우 빈 설정
@Bean
public RedisTemplate<String, Product> redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Product> redis = new RedisTemplate<String, Product>();
redis.setConnectionFactory(cf);
return redis;
}
RedisConnectionFactory cf = ...;
StringRedisTemplate redis = new StringRedisTemplate(cf); // RedisConnectionFactory를 바로 허용
====
//자주 사용할 경우 빈 설정
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory cf) {
return new StringRedisTemplate(cf);
}
* RedisTemplate가 지원하는 다양한 메소드
예시..
///// 단순 Value 메소드
// sku 프로퍼티에 값을 가져오고 싶을 때 설정
redis.opsForValue().set(product.getSku(), product);
// sku가 123456일 때,
Product product = redis.opsForValue().get("123456");
//// 리스트 메소드 left(시작점) right(종단)
// 리스트의 종단(오른쪽)에 값 추가
redis.opsForList().rightPush("cart", product);
// 종단 pop 메소드
Product last = redis.opsForList().rightPop("cart");
// 단순 값 추출
List<Product> products = redis.opsForList().range("cart", 2, 12);
//// 세트 메소드
// 세트에 아이템 추가
redis.opsForSet().add("cart", product);
// difference, union, intersec
List<Product> diff = redis.opsForSet().difference("cart1", "cart2");
List<Product> union = redis.opsForSet().union("cart1", "cart2");
List<Product> intersect = redis.opsForSet().intersect("cart1", "cart2");
//// 키 바인딩.. 주어진 키에 집중한다
// cart라는 키가 제공하는 리스트 엔트리의 Product 객체
BoundOperations<String, Product> cart = redis.boundListOps("cart");
Product popped = cart.rightPop();
cart.rightPush(product1);
cart.rightPush(product2);
키와 값의 직렬 변환 설정
엔트리가 Redis에 키-값으로 저장된 것을 직렬화하는 직렬 변환기를, 스프링 데이터 Redis가 지원한다
GenericToStringSerializer - 일반적인 스프링 변환 서비스
JacksonJsonRedisSerializer - Jackson1를 이용하여 JSON 직렬 변환
Jackson2JsonRedisSerializer - Jackson2를 이용하여 JSON 직렬 변환
JdkSerializationRedisSerializer - 자바 직렬 변환
OxmSerializer - XML 직력별환 용, 스프링 O/X 매핑 진행자/비진행자를 이용한 변환
StringRedisSerializer - String 키와 값의 직렬변환
RedisTemplate은 JdkSerializationRedisSerializer를 사용.. StringRedisTemplate은 StringRedisSerializer를 사용 => 다른 직렬 변환도 당연히 사용 가능하다
==> Jackson2JsonRedisSerializer를 사용하여, JSON으로 직렬 변환하고 싶을 때의 예시
@Bean
public RedisTemplate<String, Product> redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Product> redis = new RedisTemplate<String, Product>();
redis.setConnectionFactory(cf);
// 키는 String으로
redis.setKeySerializer(new StringRedisSerializer());
// 값은 JSON으로 직렬화
redis.setValueSerializer(new Jackson2JsonRedisSerializer<Product>(Product.class));
return redis;
}