ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Scalikejdbc 를 이용해 DB 데이터 읽기
    scala jdbc/scalikejdbc 2021. 11. 14. 21:35

    문제

    MySQL test.person 테이블 스키마와 들어 있는 데이터는 아래와 같다.

    CREATE table person
    (
     name varchar(128),
     age INT
    )
    name age
    a 10
    b 20

     

    test.person 에 저장된 데이터를 scalikejdbc 를 이용해 읽어보자

     

    코드

    build.sbt 에 아래 라이브러리를 추가한다.

    libraryDependencies ++= Seq(
      "org.scalikejdbc" %% "scalikejdbc"          % "4.0.0",
      "org.scalikejdbc" %% "scalikejdbc-config"   % "4.0.0",
      "org.postgresql"  % "postgresql"            % "42.5.0",
      "mysql"           % "mysql-connector-java"  % "8.0.27"
    )

     

    코드 작성

    connectionTimeoutMillis 는 pool.borrow() timeout 값으로 필요에 따라 충분히 크게 설정한다.

    poolConnectionTimeoutMillis defines the amount of time a query will wait to acquire a connection before throwing an exception. This used to be called connectionTimeoutMillis
    import scalikejdbc._
    
    case class Person(name: String, age: Int)
    object Person extends SQLSyntaxSupport[Person] {
      override def tableName: String = "person"
      def apply(rs: WrappedResultSet): Person = Person(
        rs.string("name"),
        rs.int("age")
      )
    }
    
    object ScalikeTest {
      def main(args: Array[String]): Unit = {
        Class.forName("org.postgresql.Driver")
        // Class.forName("com.mysql.jdbc.Driver")
        
        val settings = ConnectionPoolSettings(
          initialSize = 4,
          maxSize = 20,
          connectionTimeoutMillis = 120000L,
          validationQuery = "select 1"
        )
        ConnectionPool.singleton("jdbc:postgresql://localhost:5432/postgres", "user_id", "user_password", settings)
        // ConnectionPool.singleton("jdbc:mysql://db.host:3306/test", "user_id", "user_password", settings)
        
        implicit val session       = AutoSession
        
        // DB.autoCommit(), DB.localTx()
        val entities: List[Person] = DB.readOnly(implicit session => sql"select * from person".map(rs => Person(rs)).list().apply())
        // val entities: List[Person] = sql"select * from person".map(rs => Person(rs)).list().apply()
    
        for {
          e <- entities
        } println(s"${e.name} ${e.age}")
      }
    }

     

    출력 결과

    a 10
    b 20

     

    설명

    val name = "Alice"
    
    val personAge: Option[Int] = DB.readOnly { implicit session =>
      sql"select age from person where name = ${name}" // don't worry, prevents SQL injection
        .map(rs => rs.int("age")) // extracts values from rich java.sql.ResultSet
        .single                   // single, list, traversable
        .apply()                  // Side effect!!! runs the SQL using Connection
    }

     

    Internals

    기본적으로 아래와 같은 구조이다.

    Global object 인 ConnectionPool 에 각각의 connection pool 을 이름(예: MyPool) 과 함께 등록하고, NamedDB 로 사용한다.

    import scalikejdbc._
    
    Class.forName("...")
    val settings: ConnectionPoolSettings = ConnectionPoolSettings(...)
    ConnectionPool.add("MyPool", ..., settings)
    
    implicit val session: DBSession = NamedAutoSession("MyPool")
    NamedDB("MyPool").???

    보통 connection pool 을 하나만 등록하기 때문에 connection pool 이름을 default 로 지정할 수 있다.

    라이브러리 차원에서 connection pool 이 하나일 때 아래처럼 편히 쓰도록 지원한다. (내부적으로 pool 이름을 default 로 처리)

     

    import scalikejdbc._
    
    Class.forName("...")
    val settings: ConnectionPoolSettings = ConnectionPoolSettings(...)
    ConnectionPool.singleton(..., settings)
    // ConnectionPool.add("default", ..., settings)
    
    implicit val session: DBSession = AutoSession
    // implicit val session: DBSession = NamedAutoSession("default")
    
    DB.readOnly.???
    // NamedDB("MyPool").readOnly.???

     

    'scala jdbc > scalikejdbc' 카테고리의 다른 글

    SQLSyntax - sqls  (0) 2023.03.26
    SQL string 을 실행하기  (0) 2023.03.21

    댓글

Designed by Tistory.