Advertisement
Guest User

Untitled

a guest
May 27th, 2016
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.67 KB | None | 0 0
  1. import java.sql.{SQLException, ResultSet, Statement, DriverManager, Connection, ResultSetMetaData}
  2. import scala.util.Try
  3.  
  4. /**
  5. * Container object for Functional wrapper methods for JDBC.
  6. */
  7. object Jdbc {
  8.  
  9. /**
  10. * Raw structure for holding any and all fields necessary to create a JDBC connection. Advanced users will
  11. * likely need to expand on this.
  12. * @param url JDBC connection URL. e.g. "jdbc:h2:mem:test1"
  13. * @param username username for associated connection URL. Can be null or ""
  14. * @param password password for associated connection URL. Can be null or ""
  15. */
  16. case class ConnectionInfo(url: String, username: String = "", password: String = "")
  17.  
  18. /**
  19. * Invokes the supplied function parameter with a properly created and managed JDBC Connection
  20. * @param connInfo payload to instantiate the JDBC connection
  21. * @param f function to be invoked using the managed connection
  22. * @tparam T return type of f. Can be any type, including Unit
  23. * @return returns a Try Monad for the operation. On success, will be Success[T], on failure will be Failure[Exception]
  24. */
  25. def withConnection [T] (connInfo: ConnectionInfo, f: Connection => T): Try[T] = {
  26. val conn: Connection = DriverManager.getConnection(connInfo.url, connInfo.username, connInfo.password)
  27.  
  28. val result: Try[T] = Try(f(conn))
  29. conn.close()
  30. result
  31. }
  32.  
  33. /**
  34. * Invokes the supplied function parameter with a properly created and managed JDBC statement
  35. *
  36. * @param connInfo payload to instantiate the JDBC connection
  37. * @param f function to be invoked using the managed statement
  38. * @tparam T return type of f. Can be any type, including Unit
  39. * @return returns a Try Monad for the operation. On success, will be Success[T], on failure will be Failure[Exception]
  40. */
  41. def withStatement [T] (connInfo: ConnectionInfo, f: Statement => T): Try[T] = {
  42. def privFun(conn: Connection): T = {
  43. val stmt: Statement = conn.createStatement()
  44.  
  45. // We do not need to wrap this in a Try Monad because we know we will be executing inside 'withConnection'
  46. // which does it for us. Using another Try(...) here would just create a confusing second layer of structures
  47. // for the caller to sort through
  48. try {
  49. f(stmt)
  50. }
  51. finally {
  52. stmt.close()
  53. }
  54. }
  55.  
  56. withConnection(connInfo, privFun)
  57. }
  58.  
  59. /**
  60. * Invokes the supplied function parameter with a properly created and managed JDBC result set
  61. *
  62. * @param connInfo payload to instantiate the JDBC connection
  63. * @param sql SQL Query to execute and bind to the requested result set
  64. * @param f function to be invoked using the managed result set
  65. * @tparam T return type of f. Can be any type, including Unit
  66. * @return returns a Try Monad for the operation. On success, will be Success[T], on failure will be Failure[Exception]
  67. */
  68. def withResultSet [T] (connInfo: ConnectionInfo, sql: String, f: ResultSet => T): Try[T] = {
  69. def privFun(stmt: Statement): T = {
  70. val resultSet: ResultSet = stmt.executeQuery(sql)
  71.  
  72. // We do not need to wrap this in a Try Monad because we know we will be executing inside 'withConnection'
  73. // which does it for us. Using another Try(...) here would just create a confusing second layer of structures
  74. // for the caller to sort through
  75. try {
  76. f(resultSet)
  77. }
  78. finally {
  79. resultSet.close()
  80. }
  81. }
  82.  
  83. withStatement(connInfo, privFun)
  84. }
  85.  
  86. /**
  87. * A private class that implements the Scala iterator interface for our JDBC results.
  88. * This iterates over a Map of String->AnyRef (String->Object in Java terms) and enables
  89. * Scala collections support directly on the JDBC ResultSet.
  90. *
  91. * Note that the lifetime of the Iterator object must be no longer than the lifetime of
  92. * this ResultSet object. This class makes no attempt to manage or close the associated
  93. * JDBC result set.
  94. *
  95. * @param resultSet The JDBC ResultSet object to project as an iterator.
  96. */
  97. private class ResultsIterator (resultSet: ResultSet) extends Iterator[Map[String, AnyRef]] {
  98. private val columnNames: Seq[String] = {
  99. val rsmd: ResultSetMetaData = resultSet.getMetaData
  100.  
  101. for (i <- 1 to rsmd.getColumnCount) yield rsmd.getColumnName(i)
  102. }
  103.  
  104. /**
  105. * Produces a Scala Map containing the Name->Value mappings of the current row data for the result set
  106. * @param resultSet JDBC ResultSet used to extract current row data
  107. * @return Scala immutable map containing row data of the ResultSet
  108. */
  109. private def buildRowMap(resultSet: ResultSet): Map[String, AnyRef] = {
  110. ( for (c <- columnNames) yield c -> resultSet.getObject(c) ).toMap
  111. }
  112.  
  113. /**
  114. * Retrieves the next row of data from a result set. Note that this method returns an Option monad
  115. * If the end of the result set has been reached, it will return None, otherwise it will return Some[Map[String, AnyRef]]
  116. *
  117. * @param resultSet JDBC ResultSet to extract row data from
  118. * @return Some[Map] if there is more row data, or None if the end of the resultSet has been reached
  119. */
  120. private def getNextRow(resultSet: ResultSet): Option[Map[String, AnyRef]] = {
  121. if (resultSet.next())
  122. Some(buildRowMap(resultSet))
  123. else
  124. None
  125. }
  126.  
  127. /**
  128. * Member variable containing the next row. We need to manage this state ourselves to defend against implementation
  129. * changes in how Scala iterators are used. In particular, we do this to prevent attaching the Scala hasNext function
  130. * to the ResultSet.next method, which seems generally unsafe.
  131. */
  132. private var nextRow = getNextRow(resultSet)
  133.  
  134. /**
  135. * Scala Iterator method called to test if we have more JDBC results
  136. * @return
  137. */
  138. override def hasNext = nextRow.isDefined
  139.  
  140. /**
  141. * Scala Iterator method called to retrieve the next JDBC result
  142. * @return
  143. */
  144. override def next() = {
  145. // Extract the raw Map out of our Option[Map]. This is generally unsafe to do without risking an exception
  146. // but no one should be calling next without first making sure that hasNext returns true, so in our usage model
  147. // we should never invoke get on "None"
  148. val rowData = nextRow.get
  149. nextRow = getNextRow(resultSet)
  150. rowData
  151. }
  152. }
  153.  
  154. /**
  155. * Applies the supplied function to a managed Scala Iterator wrapping a JDBC result set
  156. * @param connInfo payload to instantiate the JDBC connection
  157. * @param sql SQL Query to execute and bind to the requested result set
  158. * @param itFun function to be invoked using the managed result set
  159. * @tparam T return type of f. Can be any type, including Unit
  160. * @return returns a Try Monad for the operation. On success, will be Success[T], on failure will be Failure[Exception]
  161. */
  162. def withResultsIterator [T] (connInfo: ConnectionInfo, sql: String, itFun: ResultsIterator => T): Try[T] =
  163. withResultSet(connInfo, sql, resultSet => itFun(new ResultsIterator(resultSet)))
  164.  
  165. }
  166.  
  167. object Main {
  168. def main(args: Array[String]) {
  169. println("Hello, world!")
  170.  
  171. val connectionInfo = new Jdbc.ConnectionInfo("jdbc:oracle:thin@dellr815c:1521:r12102", "ssvm214_odb", "ssvm214_odb")
  172. val sql = "SELECT order_id, order_num, order_code FROM ord_order ORDER BY order_num"
  173.  
  174. Jdbc.withResultSet(connectionInfo, sql, rs => { println(rs.next()) })
  175.  
  176. import scala.collection.mutable.ListBuffer
  177.  
  178. val results = new ListBuffer[String]
  179. Jdbc.withResultsIterator(connectionInfo, sql, it => {
  180. it.foreach(row => {
  181. row.get("order_num") match {
  182. case Some(order_num) => println("abc"); results.append(order_num.toString)
  183. case None => println("Null value in database")
  184. }
  185. })
  186. }).isSuccess
  187.  
  188. println(results)
  189.  
  190. sys.exit(0)
  191. }
  192.  
  193. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement