[강의요약] 스프링부트 개념과 활용 - 스프링 데이터 (3/3)

개인적인 학습을 위한 Inflearn - 스프링부트 개념과 활용(백기선) 강의 요약입니다.

개념과 원리 위주로 요약합니다.

이전 글 에서 이어집니다.

4부. 스프링 부트 활용 - 스프링 데이터


9. Redis

신규 프로젝트 생성 : springbootredis (spring-boot-starter만 추가)

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>me.cherrue</groupId>
    <artifactId>springbootredis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.2.0.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>

9-1. 의존성 추가

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

9-2. Redis 설치 (docker)

# terminal
$ docker run -p 6379:6379 --name redis_boot -d redis
$ docker exec -i -t redis_boot redis-cli
127.0.0.1:6379> keys *
(empty array)

9-3. Redis 사용하기

9-3-1. StringRedisTemplate : 문자열 특화

// RedisRunner.java
@Component
public class RedisRunner implements ApplicationRunner {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        ValueOperations<String, String> values = redisTemplate.opsForValue(); // redis operations class
        values.set("cherrue", "chen"); // key, value
        values.set("springboot", "2.0");
        values.set("hello", "world");
    }
}

결과

// docker redis cli console
127.0.0.1:6379> keys *
1) "springboot"
2) "hello"
3) "cherrue"

127.0.0.1:6379> get cherrue
"chen"

9-3-2. CrudRepository : db 사용하듯 Repository로 접근

// account.Account.java
@RedisHash("accounts")
public class Account {
    @Id private String id;

    private String username;

    private String email;
}
// account.AccountRepository.java
public interface AccountRepository extends CrudRepository<Account, String> {
}
// RedisRunner.java
@Component
public class RedisRunner implements ApplicationRunner {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    AccountRepository accountRepository;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        ValueOperations<String, String> values = redisTemplate.opsForValue(); // redis operations class
        values.set("cherrue", "chen"); // key, value
        values.set("springboot", "2.0");
        values.set("hello", "world");

        Account account = new Account();
        account.setEmail("cherrue@email.com");
        account.setUsername("cherrue");

        accountRepository.save(account);

        Optional<Account> byId = accountRepository.findById(account.getId());

        System.out.println(byId.get().getUsername());
        System.out.println(byId.get().getEmail());
    }
}

결과

뒤에 랜덤 값이 붙은 키가 생기는데 이건 get() 으로 읽을 수 없다

127.0.0.1:6379> keys *
1) "springboot"
2) "hello"
3) "cherrue"
4) "accounts:5ef82c90-976a-4be3-b9e1-94270bb70c5f"
5) "accounts"

127.0.0.1:6379> get accounts:5ef82c90-976a-4be3-b9e1-94270bb70c5f
(error) WRONGTYPE Operation against a key holding the wrong kind of value

hget(hash get) 으로 호출, 뒤에 필드명을 적어주어야 한다.

모두 가져오고 싶다면 hgetall 명령어를 사용한다.


127.0.0.1:6379> hget accounts:5ef82c90-976a-4be3-b9e1-94270bb70c5f email
"cherrue@email.com"

127.0.0.1:6379> hgetall accounts:5ef82c90-976a-4be3-b9e1-94270bb70c5f email
(error) ERR wrong number of arguments for 'hgetall' command

127.0.0.1:6379> hgetall accounts:5ef82c90-976a-4be3-b9e1-94270bb70c5f
1) "_class"
2) "me.cherrue.springbootredis.account.Account"
3) "id"
4) "5ef82c90-976a-4be3-b9e1-94270bb70c5f"
5) "username"
6) "cherrue"
7) "email"
8) "cherrue@email.com"

9-4. Redis 커스터마이즈

application.properties에서 spring.redis.* 변경

  • spring.redis.port=6379
  • spring.redis.url={ remote ip }

10. MongoDB

프로젝트 생성 : springbootmongo (starter 의존성만 추가)

MongoDB : json 기반의 도큐먼트 단위로 동작하여 스키마가 없다.

10-1. 의존성 추가

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

10-2. MongoDB 설치(DB)

참고) 도커 run 스크립트 알아내기 : dockerhub 사이트에서 검색 ([https://hub.docker.com//mongo](https://hub.docker.com//mongo))

$ docker run -p 27017:27017 --name mongo_boot -d mongo

$ docker exec -i -t mongo_boot bash                                                                                             37s 00:01:31
root@15df444c4b3d:/# mongo
MongoDB shell version v5.0.6

> db
test

> use test
switched to db test

> db.accounts.find({})
>

10-3. 사용하기

엔티티에 @Document(collection={ 원하는 컬렉션 명 }) 사용

  • collection = RDB의 테이블명과 유사 개념

자동설정

10-3-1. MongoTemplate

// account.Account.java
@Document(collection = "accounts")
public class Account {
    @Id
    private String id;

    private String username;

    private String email;

... (getter setter)
}
// SpringbootmongoApplication
@SpringBootApplication
public class SpringbootmongoApplication {

    @Autowired
    MongoTemplate mongoTemplate;

    public static void main(String[] args) {
        SpringApplication.run(SpringbootmongoApplication.class, args);
    }

    @Bean
    public ApplicationRunner applicationRunner() {
        return args -> {
            Account account = new Account();
            account.setEmail("aaa@bbb");
            account.setUsername("aaa");

            mongoTemplate.insert(account);

            System.out.println("finished");
        };
    }
}

결과

> db.accounts.find({})
{ "_id" : ObjectId("62179fe4bbfb0c61921005b7"), "username" : "aaa", "email" : "aaa@bbb", "_class" : "me.cherrue.springbootmongo.account.Account" }

10-3-2. MongoRepository

// account.AccountRepository.java
public interface AccountRepository extends MongoRepository<Account, String> {
}
// SpringbootmongoApplication
@SpringBootApplication
public class SpringbootmongoApplication {

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    AccountRepository accountRepository;

    public static void main(String[] args) {
        SpringApplication.run(SpringbootmongoApplication.class, args);
    }

    @Bean
    public ApplicationRunner applicationRunner() {
        return args -> {
            Account account = new Account();
            account.setEmail("cherrue@ccc");
            account.setUsername("ddd");

//            mongoTemplate.insert(account);
            accountRepository.insert(account);

            System.out.println("finished");

        };
    }
}

결과

> db.accounts.find({})
{ "_id" : ObjectId("62179fe4bbfb0c61921005b7"), "username" : "aaa", "email" : "aaa@bbb", "_class" : "me.cherrue.springbootmongo.account.Account" }
{ "_id" : ObjectId("6217a0abdab0e12e46f3bc81"), "username" : "ddd", "email" : "cherrue@ccc", "_class" : "me.cherrue.springbootmongo.account.Account" }

10-4. 내장형 mongoDB와 테스트

운영용 mongo db 를 사용하면 번거롭다. 내장 mongodb를 사용해 테스트하자

10-4-1. 의존성 추가

		<dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

10-4-2. 슬라이싱 테스트 구현

내장 MongoDB를 사용하면 슬라이싱 테스트가 가능

  • @DataMongoTest : Mongo 관련 Repository만 생성
// account.AccountRepository.java
public interface AccountRepository extends MongoRepository<Account, String> {
    public Optional<Account> findByEmail(String email);
}
@RunWith(SpringRunner.class)
@DataMongoTest
public class AccountRepositoryTest {
    @Autowired
    AccountRepository accountRepository;

    @Test
    public void findByEmail() {
        Account account = new Account();
        account.setUsername("cherrue");
        account.setEmail("cherrue@email.com");

        accountRepository.save(account);

        Optional<Account> byId = accountRepository.findById(account.getId());
        assertThat(byId).isNotEmpty();

        Optional<Account> byEmail = accountRepository.findByEmail(account.getEmail());
        assertThat(byEmail).isNotEmpty();
        assertThat(byEmail.get().getUsername()).isEqualTo("cherrue");
    }
}

11. Neo4j

Neo4j : 노드 간 연관 관계를 표현할 때 다양한 기능과 속도가 빠른 그래프 데이터베이스

신규 프로젝트 생성 : springbootneo4j (starter 의존성만)

11-1. 의존성 추가

neo4j 의존성 버전이 올라가면서 template 빈이 사라짐. SessionFactory나 Repository를 사용.

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-neo4j</artifactId>
        </dependency>

11-2. Neo4j 설치

$ docker run -p 7474:7474 -p 7687:7687 -d --name neo4j_boot neo4j

http://localhost:7474/browser/ 에 접속하면 데이터를 웹브라우저에서 볼 수 있다.

  • 기본 로그인 계정은 id = neo4j / password = neo4j
  • 서버에 연결 시 초기 비번을 변경하라고 시킨다. 1111로 바꾸었다.

11-3. 사용하기

바꾼 비번 적용

# application.properties
spring.data.neo4j.password=1111
spring.data.neo4j.username=neo4j

엔티티에 @NodeEntity 사용

@NodeEntity
public class Account {
    @Id
    @GeneratedValue
    private Long id;

    private String username;

    private String email;
... (getter, setter)
}

Runner 작성 (Session Factory 사용)

@Component
public class Neo4jRunner implements ApplicationRunner {
    @Autowired
    SessionFactory sessionFactory;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        Account account = new Account();
        account.setEmail("cherrue@email.com");
        account.setUsername("cherrue");

        Session session = sessionFactory.openSession();
        session.save(account);
        sessionFactory.close();

        System.out.println("finished");
    }
}

인데, neo4j 버전이 수업과 달라서인지 접속이 안 된다.

old 버전 syntax라는 것 같다.

Caused by: org.neo4j.ogm.exception.CypherException: Cypher execution failed with code 'Neo.ClientError.Statement.SyntaxError': The old parameter syntax `{param}` is no longer supported. Please use `$param` instead (line 1, column 8 (offset: 7))
"UNWIND {rows} as row CREATE (n:`Account`) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type"
        ^.

난 neo4j에는 관심이 없어서 강의 내용만 듣고 넘어간다.


12. 스프링 데이터 정리

12-1. SQL database

spring jdbc → JdbcTemplate으로 쉽게 사용

DataSource 객체의 Connection

12-2. embedded database : h2. 설정없이 바로 사용 가능 + dev-tools h2 console

12-3. DBCP : Hikari db connection pool

12-4. RDB : mysql, mariaDB

12-5. spring data jpa 사용 방법 : Entity와 Repository

12-6. db 초기화

spring.jpa.hibernate.ddl-auto = create-drop, update, validate 등

spring.data.generate-ddl = true

12-7. NoSQL : redis, mongo, neo4j

  • template 또는 Repository로 연동하여 사용
  • 커스텀은 application.properties에서 작성하거나, 직접 Bean을 등록

댓글남기기