{"id":2935,"date":"2013-02-28T22:59:53","date_gmt":"2013-02-28T21:59:53","guid":{"rendered":"http:\/\/www.gamlor.info\/wordpress\/?p=2935"},"modified":"2021-03-11T09:14:42","modified_gmt":"2021-03-11T08:14:42","slug":"adbcj-in-scala-getting-started","status":"publish","type":"post","link":"https:\/\/www.gamlor.info\/wordpress\/2013\/02\/adbcj-in-scala-getting-started\/","title":{"rendered":"ADBCJ in Scala: Getting Started"},"content":{"rendered":"<p>What, again asynchronous database access? Yes, because I&#8217;m currently knee deep in this stuff. (^^) This post series will show how to use ADBCJ in Scala 2.10, share a few tips, performance insights etc.<\/p>\n<div id=\"attachment_2951\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2013\/02\/ScalaADBCJ.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2951\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2013\/02\/ScalaADBCJ-300x167.png\" alt=\"ADBCJ and Scala, new buddies\" width=\"300\" height=\"167\" class=\"size-medium wp-image-2951\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2013\/02\/ScalaADBCJ-300x167.png 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2013\/02\/ScalaADBCJ.png 900w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2951\" class=\"wp-caption-text\">ADBCJ and Scala, new buddies<\/p><\/div>\n<h2>Grabbing the Bits<\/h2>\n<p>Of course, first we need to grab the bits. We can get it via SBT. Currently there are only snapshots available on my snapshot repository. We pull the Scala ADBCJ API, the ADBCJ connection pool and the MySQL driver.<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=build.sbt\"><\/script><noscript><pre><code class=\"language-scala scala\">name := &quot;Scala ADBCJ Demo&quot;\n\nversion := &quot;1.0&quot;\n\nscalaVersion := &quot;2.10.0&quot;\n\nlibraryDependencies += &quot;info.gamlor.adbcj&quot; %% &quot;scala-adbcj&quot; % &quot;0.6-SNAPSHOT&quot;\n\nlibraryDependencies += &quot;org.adbcj&quot; % &quot;adbcj-connection-pool&quot; % &quot;0.6-SNAPSHOT&quot;\n\nlibraryDependencies += &quot;org.adbcj&quot; % &quot;mysql-async-driver&quot; % &quot;0.6-SNAPSHOT&quot;\n\nresolvers += &quot;Gamlor-Repo&quot; at &quot;https:\/\/raw.github.com\/gamlerhart\/gamlor-mvn\/master\/snapshots&quot;<\/code><\/pre><\/noscript>\n<h2>Getting Access to the Database<\/h2>\n<p>The next step is to get access the the database. We do this with the Database object, by passing in the connection URL, username and password. This create a instance which is used to access this database. Usually you should have one instance only per database in your application.<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=DatabaseAcccess.scala\"><\/script><noscript><pre><code class=\"language-scala scala\">  \/\/ Note the &quot;pooled&quot; prefix, for using the connection pool\n  val database: DatabaseAccess = Database(&quot;adbcj:pooled:mysql:\/\/localhost\/adbcj-demo&quot;,\n    &quot;adbcj&quot;,\n    &quot;adbcj-pwd&quot;)<\/code><\/pre><\/noscript>\n<p>Then we can create new connections. The most basic way is to create a connection directly. However, you are then responsible for closing the connection.<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=Connect.scala\"><\/script><noscript><pre><code class=\"language-scala scala\">\/\/ connect() will return a future, which contains the connection\n\/\/ You need to close the connection yourself.\nval simpleConnectionFuture = database.connect()\n\n\/\/ We can use the Scala for construct to deal nicely with futures\nval futureForWholeOperation = for {\n connection &lt;-simpleConnectionFuture\n closeDone &lt;- connection.close()\n} yield &quot;Done&quot;\n<\/code><\/pre><\/noscript>\n<h2>Closing Connections Automatically<\/h2>\n<p>Now closing the connection manually can be error prone and tedious. Therefore helper methods exists. One for using a connection and one for using a connection with a new transaction.<br \/>\nThe closure has to return a future. Since everything is asynchronously, we cannot close the connection when we leave the future. Instead we need to close it when everything is done. So, the connection will be close, when the future returned by the closure is completed.<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=UseHelpers.scala\"><\/script><noscript><pre><code class=\"language-scala scala\">val doneWithConnection:Future[DBResultList] = database.withConnection{\nconnection =&gt;\n  \/\/ do something with the connection\n  \/\/ you need to return a future, because everything is asynchrous\n  \/\/ so the connection can only be closed when everything is done\n  connection.executeQuery(&quot;SELECT 1&quot;)\n}\n\nval doneWithTransactionAndConnection:Future[DBResultList] = database.withTransaction{\nconnection =&gt;\n  \/\/ Same goes for transactions\n  connection.executeQuery(&quot;SELECT 1&quot;)\n}<\/code><\/pre><\/noscript>\n<h2>Some Real Work<\/h2>\n<p>Let&#8217;s do some real work. We create the schema if it doesn&#8217;t exist and then insert a few items. In general, I highly recommend to read the <a href=\"http:\/\/doc.akka.io\/docs\/akka\/2.1.1\/scala\/futures.html\">Akka documentation about futures<\/a>, which gives an idea how to deal with tem.<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=Insert.scala\"><\/script><noscript><pre><code class=\"language-scala scala\">val txDoneFuture = database.withTransaction{\nconnection =&gt;\n  \/\/ Same goes for transactions\n  val schemaCreation = connection.executeQuery(&quot;&quot;&quot;CREATE TABLE IF NOT EXISTS posts(\\n\n  \t\t\t\t\t\tid int NOT NULL AUTO_INCREMENT,\\n\n\t\t\t\t\t\t\ttitle varchar(255) NOT NULL,\\n\n\t\t\t\t\t\t\tontent TEXT NOT NULL,\\n\n\t\t\t\t\t\t\tPRIMARY KEY (id)\\n\n\t\t\t\t\t\t\t) ENGINE = INNODB;&quot;&quot;&quot;)\n\n  val firstPost =connection.executeUpdate(&quot;INSERT INTO posts(title,content) VALUES(&#039;The Title&#039;,&#039;TheContent&#039;)&quot;)\n  val secondPost =connection.executeUpdate(&quot;INSERT INTO posts(title,content) VALUES(&#039;Second Title&#039;,&#039;More Content&#039;)&quot;)\n  val thirdPost =connection.executeUpdate(&quot;INSERT INTO posts(title,content) VALUES(&#039;Third Title&#039;,&#039;Even More Content&#039;)&quot;)\n\n  \/\/ we want to await for all operations at the end\n  for {\n  \tschemaDone &lt;-schemaCreation\n  \tpostOneDone &lt;-firstPost\n  \tpostTwoDone &lt;-secondPost\n  \tpostThreeDone &lt;-thirdPost\n  } yield &quot;All Done&quot;\n\n}<\/code><\/pre><\/noscript>\n<h2>Query<\/h2>\n<p>Let&#8217;s also query for some data. When running queries, your future will contain a immutable result set, which supports the standard collection operations.<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=Select.scala\"><\/script><noscript><pre><code class=\"language-scala scala\">    val postsDataFuture = database.withTransaction{\n      connection =&gt;\n        val postsFuture =connection.executeQuery(&quot;SELECT * FROM posts&quot;)\n\n        postsFuture onSuccess {\n          case rs:DBResultList =&gt; {\n            for (row &lt;- rs){\n              System.out.println(&quot;ID: &quot;+row(&quot;ID&quot;).getLong()+&quot; with title &quot;+row(&quot;title&quot;).getString());\n            }\n          }\n        }\n\n        postsFuture\n    }<\/code><\/pre><\/noscript>\n<h2>Prepared Statements<\/h2>\n<p>Of course, there prepared statement support:<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=PreparedStmt.scala\"><\/script><noscript><pre><code class=\"language-scala scala\">val postsDataFuture= database.withTransaction{\n  connection =&gt;\n  val preparingStmt =connection.prepareQuery(&quot;SELECT * FROM posts WHERE title LIKE ?&quot;)\n\n\tval postsFuture = preparingStmt.flatMap(stmt=&gt;stmt.execute(&quot;Third Title&quot;))\n\n\tpostsFuture onSuccess {\n\t  case rs:DBResultList =&gt; {\n\t\tfor (row &lt;- rs){\n\t\t  System.out.println(&quot;ID: &quot;+row(&quot;ID&quot;).getLong()+&quot; with title &quot;+row(&quot;title&quot;).getString());\n\t\t}\n\t  }\n\t}\n\n\tpostsFuture\n}<\/code><\/pre><\/noscript>\n<h2>One Last Hint, Debugging<\/h2>\n<p>So, this was a small tour through the API. However I want to share one last important thing, which helps you dealing with failures.<\/p>\n<p>Let&#8217;s assume you ran a back query:<br \/>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=NormalStackTrace\"><\/script><noscript><pre><code class=\"language- \">org.adbcj.mysql.codec.MysqlException: 42S02Table &#039;adbcj-demo.thistabledoesnotexist&#039; doesn&#039;t exis \n  at org.adbcj.mysql.codec.packets.ErrorResponse.toException(ErrorResponse.java:49)\n\tat org.adbcj.mysql.codec.decoding.ExpectQueryResult.handleError(ExpectQueryResult.java:31)\n\tat org.adbcj.mysql.codec.decoding.ResponseStart.parse(ResponseStart.java:33)\n\tat org.adbcj.mysql.codec.decoding.AcceptNextResponse.parse(AcceptNextResponse.java:26)\n\tat org.adbcj.mysql.codec.MySqlClientDecoder.doDecode(MySqlClientDecoder.java:96)\n\tat org.adbcj.mysql.codec.MySqlClientDecoder.decode(MySqlClientDecoder.java:67)\n\tat org.adbcj.mysql.netty.Decoder.decode(MysqlConnectionManager.java:177)\n\tat io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:113)\n\t...\n<\/code><\/pre><\/noscript><\/p>\n<p>Then you get a future which contain the error. However, the stack trace of the error does not contain any hint where in the code the query was issues. It just contains a stack trace with the internal event loop:<\/p>\n<p>You can use the debug flat to get a stack trace which points at the location which sent the request. Either add -Dorg.adbcj.debug=true to the JVM flags. Or set the appropriate property when crating the database access. Note that this feature is quite expensive, so I recommend to use it while developing or during an investigation.<\/p>\n<script src=\"https:\/\/gist.github.com\/5057658.js?file=DebugStackTrace\"><\/script><noscript><pre><code class=\"language- \">org.adbcj.DbException: 42S02Table &#039;adbcj-demo.thistabledoesnotexist&#039; doesn&#039;t exis \n  at org.adbcj.support.stacktracing.StackTraceCapturing$CaputureByDefault.capture(StackTraceCapturing.java:20)\n\tat org.adbcj.support.stacktracing.StackTraceCapturing.defaultCapture(StackTraceCapturing.java:11)\n\tat org.adbcj.support.stacktracing.StackTracingOptions$1.captureStacktraceAtEntryPoint(StackTracingOptions.java:12)\n\tat org.adbcj.support.DefaultDbFuture.&lt;init&gt;(DefaultDbFuture.java:45)\n\tat org.adbcj.support.DefaultDbSessionFuture.&lt;init&gt;(DefaultDbSessionFuture.java:50)\n\tat org.adbcj.mysql.codec.MySqlRequests.executeQuery(MySqlRequests.java:28)\n\tat org.adbcj.mysql.codec.MySqlConnection.executeQuery(MySqlConnection.java:108)\n\tat org.adbcj.mysql.codec.MySqlConnection.executeQuery(MySqlConnection.java:102)\n\tat org.adbcj.connectionpool.PooledConnection.executeQuery(PooledConnection.java:78)\n\tat info.gamlor.db.DBConnection$$anonfun$executeQuery$1.apply(DBConnection.scala:109)\n\tat info.gamlor.db.DBConnection$$anonfun$executeQuery$1.apply(DBConnection.scala:109)\n\tat info.gamlor.db.FutureConversions$class.completeWithAkkaFuture(FutureConversions.scala:20)\n\tat info.gamlor.db.DBConnection.completeWithAkkaFuture(DBConnection.scala:31)\n\tat info.gamlor.db.DBConnection.executeQuery(DBConnection.scala:109)\n---&gt;at info.gamlor.adbcj.scalademo.MainDemo$$anonfun$8.apply(MainDemo.scala:99)\n    ... \/\/ RIGHT Location\nCaused by: org.adbcj.mysql.codec.MysqlException: 42S02Table &#039;adbcj-demo.thistabledoesnotexist&#039; doesn&#039;t exist \n\tat org.adbcj.mysql.codec.packets.ErrorResponse.toException(ErrorResponse.java:49)\n\tat org.adbcj.mysql.codec.decoding.ExpectQueryResult.handleError(ExpectQueryResult.java:31)\n\tat org.adbcj.mysql.codec.decoding.ResponseStart.parse(ResponseStart.java:33)\n\tat org.adbcj.mysql.codec.decoding.AcceptNextResponse.parse(AcceptNextResponse.java:26)\n\tat org.adbcj.mysql.codec.MySqlClientDecoder.doDecode(MySqlClientDecoder.java:96)\n\tat org.adbcj.mysql.codec.MySqlClientDecoder.decode(MySqlClientDecoder.java:67)\n\tat org.adbcj.mysql.netty.Decoder.decode(MysqlConnectionManager.java:177)\n\tat io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:113)<\/code><\/pre><\/noscript>\n\n<p>So, that&#8217;s it for now. Future posts will go into more aspects of ADBCJ the interaction with Scala.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What, again asynchronous database access? Yes, because I&#8217;m currently knee deep in this stuff. (^^) This post series will show how to use ADBCJ in Scala 2.10, share a few&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[268,15,17],"tags":[291,292,162,295,226],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/2935"}],"collection":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/comments?post=2935"}],"version-history":[{"count":12,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/2935\/revisions"}],"predecessor-version":[{"id":2953,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/2935\/revisions\/2953"}],"wp:attachment":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/media?parent=2935"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/categories?post=2935"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/tags?post=2935"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}