복붙노트

[SCALA] 스칼라 스트림과 같은 SQL ResultSet의 치료

SCALA

스칼라 스트림과 같은 SQL ResultSet의 치료

나는 데이터베이스를 조회하고 (전진 전용, 읽기 전용)의 ResultSet 등을받을 때, 결과 집합은 데이터베이스 행의 목록과 같은 역할을합니다.

나는 스칼라 스트림 등이 ResultSet을 처리 할 수있는 방법을 찾기 위해 노력하고있다. 많은 양의 RAM을 소비하지 않으면 서이 등 필터,지도, 등의 작업을하실 수 있습니다.

나는 개별 항목을 추출하는 꼬리 재귀 방법을 구현하지만,이 결과 집합이 매우 큰 경우 모든 항목이 동시에 메모리에 문제가 될 것을 요구한다 :

// Iterate through the result set and gather all of the String values into a list
// then return that list
@tailrec
def loop(resultSet: ResultSet,
         accumulator: List[String] = List()): List[String] = {
  if (!resultSet.next) accumulator.reverse
  else {
    val value = resultSet.getString(1)
    loop(resultSet, value +: accumulator)
  }
}

해결법

  1. ==============================

    1.나는 그것을 테스트하지 못했지만, 왜 작동하지 않을까요?

    나는 그것을 테스트하지 못했지만, 왜 작동하지 않을까요?

    new Iterator[String] {
      def hasNext = resultSet.next()
      def next() = resultSet.getString(1)
    }.toStream
    
  2. ==============================

    2.@의 elbowich의 답변 유틸리티 기능 :

    @의 elbowich의 답변 유틸리티 기능 :

    def results[T](resultSet: ResultSet)(f: ResultSet => T) = {
      new Iterator[T] {
        def hasNext = resultSet.next()
        def next() = f(resultSet)
      }
    }
    

    당신이 형식 유추를 사용할 수 있습니다. 예컨대 :

    stmt.execute("SELECT mystr, myint FROM mytable")
    
    // Example 1:
    val it = results(stmt.resultSet) {
      case rs => rs.getString(1) -> 100 * rs.getInt(2)
    }
    val m = it.toMap // Map[String, Int]
    
    // Example 2:
    val it = results(stmt.resultSet)(_.getString(1))
    
  3. ==============================

    3.이 소리는 암시 클래스에 대한 좋은 기회를 좋아한다. 먼저 암시 클래스 어딘가를 정의 :

    이 소리는 암시 클래스에 대한 좋은 기회를 좋아한다. 먼저 암시 클래스 어딘가를 정의 :

    import java.sql.ResultSet
    
    object Implicits {
    
        implicit class ResultSetStream(resultSet: ResultSet) {
    
            def toStream: Stream[ResultSet] = {
                new Iterator[ResultSet] {
                    def hasNext = resultSet.next()
    
                    def next() = resultSet
                }.toStream
            }
        }
    }
    

    다음으로, 단순히 당신이 당신의 쿼리를 실행하고 ResultSet 객체를 정의 곳이 암시 클래스를 가져옵니다

    import com.company.Implicits._
    

    마지막으로 toStream 방법을 사용하여 데이터를 얻을. 아래와 같이 예를 들어, 모든 ID를 얻을 :

    val allIds = resultSet.toStream.map(result => result.getInt("id"))
    
  4. ==============================

    4.나는 비슷한 것을 필요로했다. 아주 대답을 멋진 elbowich에 구축, 나는 그것을 조금 포장, 대신 문자열, 나는 결과를 반환 (당신이 어떤 열을 얻을 수 있도록)

    나는 비슷한 것을 필요로했다. 아주 대답을 멋진 elbowich에 구축, 나는 그것을 조금 포장, 대신 문자열, 나는 결과를 반환 (당신이 어떤 열을 얻을 수 있도록)

    def resultSetItr(resultSet: ResultSet): Stream[ResultSet] = {
        new Iterator[ResultSet] {
          def hasNext = resultSet.next()
          def next() = resultSet
        }.toStream
      }
    

    나는 액세스 테이블 메타 데이터에 필요한, 그러나 이것은 (대신 md.getColumns의)는 stmt.executeQuery (SQL을 할 수있는) 테이블 행에 대한 작동합니다 :

     val md = connection.getMetaData()
     val columnItr = resultSetItr( md.getColumns(null, null, "MyTable", null))
          val columns = columnItr.map(col => {
            val columnType = col.getString("TYPE_NAME")
            val columnName = col.getString("COLUMN_NAME")
            val columnSize = col.getString("COLUMN_SIZE")
            new Column(columnName, columnType, columnSize.toInt, false)
          })
    
  5. ==============================

    5.ResultSet의 다음으로 탐색하고 바로 변경 가능한 객체이기 때문에, 우리는 다음 행의 우리 자신의 개념을 정의 할 필요가있다. 우리는 다음과 같은 입력 기능을 수행 할 수 있습니다 :

    ResultSet의 다음으로 탐색하고 바로 변경 가능한 객체이기 때문에, 우리는 다음 행의 우리 자신의 개념을 정의 할 필요가있다. 우리는 다음과 같은 입력 기능을 수행 할 수 있습니다 :

    class ResultSetIterator[T](rs: ResultSet, nextRowFunc: ResultSet => T) 
    extends Iterator[T] {
    
      private var nextVal: Option[T] = None
    
      override def hasNext: Boolean = {
        val ret = rs.next()
        if(ret) {
          nextVal = Some(nextRowFunc(rs))
        } else {
          nextVal = None
        }
        ret
      }
    
      override def next(): T = nextVal.getOrElse { 
        hasNext 
        nextVal.getOrElse( throw new ResultSetIteratorOutOfBoundsException 
      )}
    
      class ResultSetIteratorOutOfBoundsException extends Exception("ResultSetIterator reached end of list and next can no longer be called. hasNext should return false.")
    }
    

    편집하다: 스트리밍 이상에 따라 다른 것을 번역.

  6. ==============================

    6.이 구현은, 비록 더 길고 더 웃기시는 결과 집합의 계약에 더 나은 대응이다. 부작용이 hasNext (...)로부터 제거하고, 다음으로 이동 한 ().

    이 구현은, 비록 더 길고 더 웃기시는 결과 집합의 계약에 더 나은 대응이다. 부작용이 hasNext (...)로부터 제거하고, 다음으로 이동 한 ().

    new Iterator[String] {
      private var available = resultSet.next()
      override def hasNext: Boolean = available
      override def next(): String = {
        val string = resultSet.getString(1)
        available = resultSet.next()
        string
      }
    }
    
  7. ==============================

    7.나는 위의 구현의 대부분이 비 결정적 hasNext 방법이있다 생각합니다. 두 번째 행에 커서를 이동합니다 그것을 두 번 호출. 나는 그런 일을 사용하는 권합니다 :

    나는 위의 구현의 대부분이 비 결정적 hasNext 방법이있다 생각합니다. 두 번째 행에 커서를 이동합니다 그것을 두 번 호출. 나는 그런 일을 사용하는 권합니다 :

      new Iterator[ResultSet] {
        def hasNext = {
          !resultSet.isLast
        }
        def next() = {
          resultSet.next()
          resultSet
        }
      }
    
  8. ==============================

    8.

    Iterator.continually(rs.next())
      .takeWhile(identity)
      .map(_ => Model(
          id = rs.getInt("id"),
          text = rs.getString("text")
       ))
    
  9. ==============================

    9.여기에 우리가 hasNext가 부작용 무료 반복자 계약을 수여하는 솔루션을 필요로 할 때위한 세르게이 Alaev의 및 thoredge의 솔루션과 유사한 대안이다.

    여기에 우리가 hasNext가 부작용 무료 반복자 계약을 수여하는 솔루션을 필요로 할 때위한 세르게이 Alaev의 및 thoredge의 솔루션과 유사한 대안이다.

    함수 F를 가정하면의 ResultSet => T :

    Iterator.unfold(resultSet.next()) { hasNext =>
      Option.when(hasNext)(f(resultSet), resultSet.next())
    }
    

    나는 그것이 도움이 된 ResultSet에지도 "확장 메서드"로이 발견했습니다.

    implicit class ResultSetOps(resultSet: ResultSet) {
        def map[T](f: ResultSet => T): Iterator[T] = {
          Iterator.unfold(resultSet.next()) { hasNext =>
            Option.when(hasNext)(f(resultSet), resultSet.next())
          }
        }
      }
    
  10. from https://stackoverflow.com/questions/9636545/treating-an-sql-resultset-like-a-scala-stream by cc-by-sa and MIT license