Scalaç¨DBã¢ã¯ã»ã¹ã©ã¤ãã©ãª Querulous ã®ä½¿ãæ¹
ï¼ãã®è¨äºã¯ Scala Advent Calendar jp 2010 ã®1æ¥ç®ã§ããï¼
Scalaç¨ã®Scalaã§æ¸ãããDBã¢ã¯ã»ã¹ã®ããã®ã©ã¤ãã©ãªãquerulousã«ã¤ãã¦æ¸ãã¾ãã
ã¨ããããèªã¿æ¹ããããããã¾ããããã¯ã¥ã¨ã«ã¡ã©ã¹ï¼ï¼ã¿ãããªæãã§ãããããè¨ãã«ããã®ã§ãã¯ã¨ã©ã©ã¹ãã£ã¦ãã¨ã«ãã¾ããããè±èªã®å½¢å®¹è©ã§ãæå³ã¯ãä¸å¹³ããããã®ãä¸å¹³ãããããè¨ãããããã§ããããã¤ååã§ããã
querulousã¯ä»¥åç´¹ä»ããKestrelã¨åæ§ãTwitterã§ä½ããã¦ä½¿ããã¦ãããã®ã§ããããè¾ãã¡ãã£ããããã§ãããå
Twitterã®Nick Kallenæ°ãä½ã£ãããã§ããä»ã¯Githubä¸ã§twitterã¨ããIDã®ä¸ã§ç®¡çããã¦ãã¾ãã
ï¼12/8 è¿½è¨ Nick Kallenæ°ã¯ã¾ã è¾ãã¦ã¾ããã§ããããã¿ã¾ãããAlex Payneæ°ã¨åéããkzys ããææãããã¨ããããã¾ãï¼
æ©è½ã¨ç¹é·ãreadmeããæç²ããã¨
- JDBCã®ããã©ããããã¨ãããæãã«ãã£ã¡ãããã
- ã¿ã¤ã ã¢ã¦ãã¨ãæ»æ´»æ¤ç¥ã¨ããªãã©ã¤ã¨ããé害èæ§ãèãã¦ããã
- çµ±è¨æ å ±ã¨ãããããªãããã°ãã°ã¨ãåºããã便å©ã ãã
- ã³ã¼ãã¨ãè¦ç´ã¨ãä¾åé¢ä¿ã¨ãæå°éã§ãSQLãã¥ã¼ãã³ã°ã®éªéã¯ããªããã
- ã¢ã¸ã¥ã¼ã«åããã¦ã¦ã«ã¹ã¿ãã¤ãºãOKãã
ã¨ããæããããã§ãã
ãæå°éãã£ã¦ã®ã¯ãä¾ãã°JNDIã¯ä½¿ããªãã£ãããMySQLãããµãã¼ããã¦ãªãã£ããã§ãã
ä¾åé¢ä¿ãæå°éã£ã¦ã¨ãã¯ç´å¾ãããããã§ãããLiftã¿ãããªããã¼ãªãã®ããæ¯ã¹ãã°å°ãªãã¨æãã¾ããä¾åããã®ã¯ä»¥ä¸ã®ã©ã¤ãã©ãªç¾¤ã§ãã
- configgy ï¼è¨å®ã¨ãã®ã³ã°ã®ããã®ã©ã¤ãã©ãªï¼
- xrayspecs ï¼Specsã®æ¡å¼µã©ã¤ãã©ãªã以ä¸ã®3ã¤ã¨åããã¦ãã¹ãç¨ããã®ä¸ã®æéè¨æ¸¬é¢é£ã®ã¯ã©ã¹ã»é¢æ°ãããã¼ã«ä½¿ããã¦ã¦ãã¤ã³ã¿ã¼ãã§ã¤ã¹ã«ãåºã¦ãã¾ãï¼
- specs
- jmock
- hamcrest
- mysql-connector-java !! ï¼æ½ãMySQLãªã³ãªã¼ã§ãï¼
- commons-dbcpï¼commons-pool ï¼ãããæ½ãã§ããï¼
- objenesis ï¼ãªãã¬ã¯ã·ã§ã³ç¨ã®ã©ã¤ãã©ãªï¼
- cglibï¼asm ï¼ãã¤ãã³ã¼ããå®è¡æã«ã´ãã§ã´ãã§ãããã¤ï¼
ããã¾ãreadmeãããå®è£
ã«ã¤ãã¦ã®èª¬æãæç²ããã¨
- Querulousã¯QueryEvaluators, Queries, Databasesã®ï¼ã¤ã®ã³ã³ãã¼ãã³ããã¡ã¤ã³ã
- QueryEvaluatorsã¯ã¯ã¨ãªå®è¡ã®ããã®ã¤ã³ã¿ã¼ãã§ã¤ã¹ã
- Queries㯠SELECT/UPDATE/INSERT/DELETE ã¯ã¨ãªãæ½è±¡åãããã®ãç´æ¥Queriesãæä½ãããã¨ã¯ããã¾ããªãã
- Databasesã¯DBæ¥ç¶ã®ç®¡çãè¡ããã®ã
- ãã®3ã¤ã¯ããããã®Factoryãã¤ã³ã¿ã¼ãã§ã¤ã¹ã¨ãã¦æ¸ããã¦ã¦ãå®è£ ã¯decorator-patternã§éãã¦ä½¿ãã
val queryFactory = new DebuggingQueryFactory(new TimingOutQueryFactory(new SqlQueryFactory)) val query = queryFactory(...) // this query will have debugging information and timeouts!
ï¼ããã¯Scalaãªãã ããtraitãwithã§éããã°ããã®ã«ãã¨æããã©ãããã¯ã§ããªãã®ããªã»ã»ã»ããããªãï¼
使ã£ã¦ã¿ã
使ã£ã¦ã¿ã¾ããããquerulousã®jar㯠maven.twttr.com ã§å
¬éããã¦ãã¦ãsbtãmavenããåç
§ãããã¨ãã§ããããã«ãªã£ã¦ã¾ãã
ããããã®è¨å®ã¯ä»¥ä¸ã®ã¨ããã§ãã
sbtã®è¨å®
ããã¸ã§ã¯ããã¡ã¤ã«ã«ä»¥ä¸ã®ããã«ãªãã¸ããªã¨ã©ã¤ãã©ãªã¸ã®åç §ãæ¸ãã°OKã§ãã以ä¸ã¯Scala 2.8ç³»ã®å ´åã®è¨å®ã§ãã2.7ç³»ã®å ´åã¯querulous_2.8.0ã®ã¨ãããquerulous_2.7.7ã«ãã¦ãã ããããªããquerulous_2.8.1ã¯ãªãã¸ããªã«åå¨ããªãã®ã§ã2.8.1ã§ä½¿ãå ´åã¯querulous_2.8.0ã使ãã¾ãããã
import sbt._ class QuerulousSampleProject(info: ProjectInfo) extends DefaultProject(info) { val twitterRepos = "Twitter Maven Repository" at "http://maven.twttr.com" val querulous = "com.twitter" % "querulous_2.8.0" % "1.4.3" }
Mavenã®è¨å®
Mavenã®å ´åã¯pom.xmlã«ä»¥ä¸ã®ã¨ããã«repositoryã¨dependencyã®è¨å®ãæ¸ãã°OKã§ããMavenã¨Ivyã®å ´åã®èª¬æã¯ãreadmeã«ãæ¸ãã¦ããã¾ãããreadmeã®èª¬æã¯ãã¼ã¸ã§ã³è¡¨è¨ãartifactIdãå¤ããã®ã«ãªã£ã¦ããã®ã§æ³¨æãã¦ãã ããã以ä¸ã®è¨è¿°ã¯ä¸è¨ã®sbtã®å ´åã¨åæ§Scala 2.8ç³»åãã§ãã2.7ç³»ã®å ´åã¯querulous_2.8.0ã®ã¨ãããquerulous_2.7.7ã«ãã¦ãã ããã
<repository> <id>twitter.com</id> <url>http://maven.twttr.com/</url> </repository> <dependency> <groupId>com.twitter</groupId> <artifactId>querulous_2.8.0</artifactId> <version>1.4.3</version> </dependency>
QueryEvaluatorã®åå¾
querulousã§ã¯ããã¼ã¿ãã¼ã¹ã«ã¢ã¯ã»ã¹ããããã«ãã¾ãQueryEvaluatorFactoryãä½ãã¾ããåè¿°ã®éããdecolator-patternã«ãªã£ã¦ãã¦ã以ä¸ã®ãããªã³ã¼ãã§ä½æã§ãã¾ããï¼commons-dbcpã使ã£ã¦ã³ãã¯ã·ã§ã³ãã¼ã«ãä½ãä¾ã§ãï¼
import com.twitter.xrayspecs.TimeConversions._ import com.twitter.querulous.evaluator._ import com.twitter.querulous.query._ import com.twitter.querulous.database._ object Database { val factory = new StandardQueryEvaluatorFactory( new ApachePoolingDatabaseFactory( minConns = 2, maxConns = 200, checkIdle = 0 seconds, maxWait = 200 millis, checkHealth = false, evictTime = 30 minutes ), new SqlQueryFactory) // secondsã¨ãmillisã¯com.twitter.xrayspecs.TimeConversionsã§å®ç¾©ããã¦ãã¾ã }
ç¶ãã¦ãããã§ä½æããQueryEvaluatorFactoryã®applyã¡ã½ããã使ç¨ãã¦ãQueryEvaluatorãä½æãã¾ãã
ï¼12/8 è¿½è¨ ãã©ã¡ã¼ã¿dbhostsã«æ¸¡ãã®ã¯ãList[String]ã§ãããã®ã¾ã¾MySQLã®JDBCãã©ã¤ãã«æ¸¡ããã¾ããï¼
lazy val evaluator = factory( dbhosts = List("192.168.0.1:3306", "192.168.0.2:3306"), dbname = "dbname", username = "username", password = "password", urlOptions = "urloption" )
ã¯ã¨ãªã®å®è¡
å ã»ã©ä½æããQueryEvaluatorã使ã£ã¦ã¯ã¨ãªãå®è¡ãã¾ãã以ä¸ã®ããã«SQLãç´æ¥æ¸ãã¦ãç´æçã«å©ç¨ãããã¨ãåºæ¥ã¾ãã
case class User(userId : Long, serviceId : Int, userName : String) // 1ã¬ã³ã¼ãã®SELECT æ»ãå¤ã¯Optionåã«ãªã val oneUser : Option[User] = evaluator.selectOne("SELECT user_id, service_id, user_name FROM users WHERE user_id = ?", userId) { row => User(row.getLong("user_id"), row.getString("user_name")) } // è¤æ°ã¬ã³ã¼ãã®SELECT æ»ãå¤ã¯Seqåã«ãªã val users : Seq[User] = evaluator.select("SELECT user_id, service_id, user_name FROM users WHERE user_id = ?", userId) { row => User(row.getLong("user_id"), row.getString("user_name")) } // UPDATE/DELETE æ»ãå¤ã¯å½±é¿ã®ãã£ãè¡æ° Intåã«ãªã val excuteRet : Int = evaluator.execute("DELETE FROM users WHERE user_id = ? ", userId) // INSERT æ»ãå¤ã¯auto incrementã®çµæå¤ Longåã«ãªã // executeãå®è¡ããå¾ãSELECT LAST_INSERT_ID() ãå®è¡ããä»æ§ã§ã val ret : Int = evaluator.insert("INSERT INTO users(user_id, user_name ) VALUES(?, ?)", 123, "hito_asa")
以ä¸ã§ãï¼
ï¼12/13 ä¿®æ£ INSERTã¨UPDATE/DELETEã®èª¬æãä¸ç·ã«ãªã£ã¦ããã®ãä¿®æ£ãã¾ãããINSERTã¯auto incrementã®çµæå¤ãè¿ãããã§ãï¼