NoSQL

MongoDB์˜ ์œ ์ง€์„ฑ ๋„ํ๋จผํŠธ

MongoDB : ์˜คํ”ˆ์†Œ์Šค ๋„ํ๋จผํŠธ ๋ฐ์ดํ„ฐ(๋น„์ •๊ทœํ™” ๋œ ๊ตฌ์กฐ์˜ ์ •๋ณด) ๋ฒ ์ด์Šค

-> ์Šคํ”„๋ง์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ - ์‚ฌ์šฉํ•˜๋Š” ์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•

  • ๊ฐ์ฒด ๋„ํ๋จผํŠธ ๋งคํ•‘์„ ์œ„ํ•œ ์• ๋„ˆํ…Œ์ด์…˜

  • MongoTemplate์„ ์‚ฌ์šฉํ•œ ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•ก์„ธ์Šค

  • ์ž๋™ ๋Ÿฐํƒ€์ž„ ์ €์žฅ์†Œ ์ƒ์„ฑ

์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA์™€ ๋‹ฌ๋ฆฌ, ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ MongoDB๋Š” ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ ๋„ํ๋จผํŠธ์— ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•œ ์• ๋„ˆํ…Œ์ด์…˜์„ ์ œ๊ณต. ๋˜ํ•œ MongoDB๋Š” ๋‹ค์ˆ˜์˜ ์ผ๋ฐ˜ ๋„ํ๋จผํŠธ ์ฒ˜๋ฆฌ ํƒœ์Šคํฌ๋ฅผ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณต


MongoDB ํ™œ์„ฑํ™”

@Configuration
@EnableMongoRepositories("orders.db") 
public class MongoConfig extends AbstractMongoConfiguration {
    @Override
    protected String getDatabaseName() {
        return "OrdersDB"; // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ช…์„ ์ง€์ •ํ•ด์ค€๋‹ค.
    }
    @Override
    public Mongo mongo() throws Exception { // Mongoํด๋ผ์ด์–ธํŠธ๋ฅผ ์ƒ์„ฑ
        return new MongoClient("mongodbserver", 37017); // ๋””๋น„ ์„œ๋ฒ„ ์„ค์ •๊ณผ ํฌํŠธ์„ค์ •(๊ธฐ๋ณธ localhost, 27017)
    }
}

=> AbstractMongoConfiguration(์ตœ๊ทผ ๋ฒ„์ „์—์„œ๋Š” depreacted) ์„ ์‚ฌ์šฉํ•˜์—ฌ ์•”์‹œ์ ์œผ๋กœ ์ง์ ‘ MongoTemplate์„ ์„ ์–ธํ•˜์ง€ ์•Š์Œ. MongoFactoryBean์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ MongoClient() ์‚ฌ์šฉ

* MongoDB์— ์ธ์ฆ๋œ ์„œ๋ฒ„๋กœ ์•ก์„ธ์Šค๊ฐ€ ํ•„์š”ํ•  ์ˆ˜๊ฐ€ ์žˆ์Œ

@Override
public Mongo mongo() throws Exception {
     
     MongoCredential credential = MongoCredential.createMongoCRCredential(
                             env.getProperty("mongo.username"),"OrdersDB", env.getProperty("mongo.password").toCharArray());
     return new MongoClient(new ServerAddress("localhost", 37017),Arrays.asList(credential));
     // ์ธ์ฆ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ MongoClient ๋งŒ๋“ค๊ธฐ
}

MongoDB ํผ์‹œ์Šคํ„ดํŠธ๋ฅผ ์œ„ํ•œ ์• ๋„ˆํ…Œ์ด์…˜ ๋ชจ๋ธ ํƒ€์ž…

MongoDB๋Š” ๊ฐ์ฒด-๋„ํ๋จผํŠธ ๋งคํ•‘ ์• ๋„ˆํ…Œ์ด์…˜์„ ๊ฐ€์ง€์ง€ ์•Š์œผ๋ฉฐ, ๋‹จ์ง€ ๊ฐญ์„ ์ฑ„์šธ ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ๊ฐ€์ง„๋‹ค. ์ž๋ฐ” ํƒ€์ž…์„ MongoDB ๋„ํ๋จผํŠธ์— ๋งคํ•‘ํ•œ๋‹ค

๋งคํ•‘ ๋ฐ์ดํ„ฐ

@Document @Id๋Š” JPA์˜ @Entity, @Id์™€ ๋น„์Šทํ•˜๋‹ค

@Document // ๋„ํ๋จผํŠธ
 public class Order {
 
  @Id // ์•„์ด๋”” ์„ ์–ธ
  private String id;
  
  @Field("client") // ๊ธฐ๋ณธ ํ•„๋“œ๋ช… ์˜ค๋ฒ„๋ผ์ด๋“œ
  private String customer; // ์ปค์Šคํ„ฐ๋จธ ํ”„๋กœํผํ‹ด๋Š” @Feild๋กœ ์• ๋„ˆํ…Œ์ด์…˜ ๋˜๊ณ , ๋„ํ๋จผํŠธ๊ฐ€  ์ง€์† ์œ ์ง€๋ ๋•Œ field๋กœ ๋ช…๋ช…๋œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋งคํ•‘
  
  private String type;
  
  private Collection<Item> items = new LinkedHashSet<Item>();

  public String getCustomer() {
    return customer;
  }
  
  public void setCustomer(String customer) {
    this.customer = customer;
  }
  
  public String getType() {
    return type;
  }
  
  public void setType(String type) {
    this.type = type;
  }
}

*item์˜ ๊ฒฝ์šฐ๋Š” JPA์—์„œ @OneToMany๋กœ ์• ๋„ˆํ…Œ์ด์…˜ ๋˜์–ด์žˆ๊ณ , ๋…๋ฆฝ๋œ ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.(์˜ˆ์‹œ)

๋ฐ์ดํ„ฐ ๊ด€๊ณ„๋Š” ๊ฐ€์ง€์ง€๋งŒ, ๋น„์ •๊ทœํ™” ๋˜์–ด์žˆ์Œ

MongoTemplate์„ ์‚ฌ์šฉํ•˜์—ฌ MongoDB ์•ก์„ธ์Šค

AbstractAbstractMongoConfiguration์„ ํ™•์žฅํ•˜์—ฌ MongoTemplate ๋นˆ์„ ์„ค์ •ํ•˜์˜€๋‹ค

MongoTemplate์˜ ๊ตฌํ˜„ ์ธํ„ฐํŽ˜์ด์Šค์ธ MongoOperations์„ ํƒ€์ž…์œผ๋กœ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฃผ์ž…์„ ํ•ด์•ผํ•จ

@Autowired
MongoOperations mongo;

* 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 OrderRepository extends MongoRepository<Order, String> {}
// MongoRepsoitory< ๋„ํ๋จผํŠธ , ์•„์ด๋”” >

* ์ „ ์žฅ์˜, JpaRepositoryํ™•์žฅ๊ฐ€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๋Ÿฐํƒ€์ž„ ์‹œ์— ์ €์žฅ์†Œ์˜ ๊ตฌํ˜„์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

ํ•ด๋‹น ๊ตฌํ˜„์ฒด๋Š”, ์œ„์˜ ํ‘œ์— ๋งž๋Š” ๊ตฌํ˜„ ๋ฉ”์†Œ๋“œ๋ฅผ ์ƒ์†ํ•œ๋‹ค

๋งž์ถคํ˜• ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ

* JPA๋•Œ์™€ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค.

List<Order> findByCustomer(String c) - ๋“ฑ

* ๋™์‚ฌ - ๋Œ€์ƒ By - ์กฐ๊ฑด


์ฟผ๋ฆฌ ์ง€์ • ํ•˜๊ธฐ

@Query ์• ๋„ˆํ…Œ์ด์…˜ ์‚ฌ์šฉ

@Query("{'customer': 'Chuck Wagon', 'type' : ?0}")
List<Order> findChucksOrders(String t);

-> JPA์™€ ๋™์ผ


๋งž์ถคํ˜• ์ €์žฅ์†Œ ํ˜ผํ•ฉ

... JPA์™€ ๋™์ผ

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 ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง„๋‹ค.

}

๋งž์ถคํ˜• ์ฟผ๋ฆฌ ์ง€์ • : ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ @Query ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค

@Query("match (o:Order)-[:HAS_ITEMS]->(i:Item) " +
       "where i.product='Spring in Action' return o")
List<Order> findSiAOrders();

๋งž์ถคํ˜• ์ €์žฅ์†Œ ๋™์ž‘ ํ˜ผํ•ฉ

MongoDB์™€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค

* OrderOperation ์ค‘๊ฐ„ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ

public interface OrderOperations {
  List<Order> findSiAOrders();
}

* OrderRepository ํ™•์žฅ

public interface OrderRepository
       extends GraphRepository<Order>, OrderOperations {
   ~~~
}

--> ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, Impl ํด๋ž˜์Šค๋กœ ๊ตฌํ˜„์ฒด ํด๋ž˜์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•จ

* OrderRepositoryImpl

public class OrderRepositoryImpl implements OrderOperations {
  private final Neo4jOperations neo4j;
  
  @Autowired
  public OrderRepositoryImpl(Neo4jOperations neo4j) {
    this.neo4j = neo4j;
  }
  
  public List<Order> findSiAOrders() {
    Result<Map<String, Object>> result = neo4j.query(
            "match (o:Order)-[:HAS_ITEMS]->(i:Item) " +
            "where i.product='Spring in Action' return o",
            EndResult<Order> endResult = result.to(Order.class);
            
    return IteratorUtil.asList(endResult);
  }
}

Redis์—์„œ ํ‚ค-๊ฐ’ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ

* ํ‚ค-๊ฐ’ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค : ๋”•์…”๋„ˆ๋ฆฌ, ํ•ด์‹œ ๋งต๊ณผ ๊ฐ™์€, ๋‹จ์ˆœํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ์Šคํ† ๋ฆฌ์ง€ ํŒจ๋Ÿฌ๋‹ค์ž„ - Redis

* ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ Redis๋Š”, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ์„ ๊ตฌํ˜„


Redis์— ์—ฐ๊ฒฐํ•˜๊ธฐ

์Šคํ”„๋ง๋ฐ์ดํ„ฐ๋Š” Redis๋ฅผ ์œ„ํ•œ 4๊ฐ€์ง€ Connection Factory๋ฅผ ์ œ๊ณตํ•œ๋‹ค

** JedisConnectionFactory **JredisConnectionFactory ** LettuceConnectionFactory ** SrpConnectionFactory

-> ์ฑ…์—์„œ๋Š” JedisConnectionFactory๋ฅผ ์‚ฌ์šฉ

@Bean
public RedisConnectionFactory redisCF() {
  JedisConnectionFactory cf = new JedisConnectionFactory();
  cf.setHostName("redis-server"); // ํ˜ธ์ŠคํŠธ ์„œ๋ฒ„ ์„ค์ •
  cf.setPort(7379); // ํฌํŠธ ์„ค์ •
  cf.setPassword("foobared");  // ๋น„๋ฐ€๋ฒˆํ˜ธ ์„ค์ •
  return cf; 
}

RedisTemplate ์‚ฌ์šฉํ•˜๊ธฐ

ConnectionFactory๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ byte ๋ฐฐ์—ด์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

RedisConnectionFactory cf = ...;
RedisConnection conn = cf.getConnection();
// ์„ธํŒ…
conn.set("greeting".getBytes(), "Hello World".getBytes())

// ๊ฒ€์ƒ‰
byte[] greetingBytes = conn.get("greeting".getBytes());
String greeting = new String(greetingBytes);

ํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ 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);
redisTemplate์˜ ๋‹ค์–‘ํ•œ ๋ฉ”์†Œ๋“œ

ํ‚ค์™€ ๊ฐ’์˜ ์ง๋ ฌ ๋ณ€ํ™˜ ์„ค์ •

์—”ํŠธ๋ฆฌ๊ฐ€ 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;
}

Last updated