Scalaからデータベースに接続する

Posted 2010年12月1日 by

Scalaからリレーショナル・データベースに接続する方法としては、
Java JDBCドライバを直接操作する方法と、scala.dbc かscala.dbc2を使う方法があります。
前者はJavaで書いていたと同じに使うことができます。
後者はまだ開発途上のようです。

現在、Javaでデータベースを操作する場合、JavaJDBCドライバのライブラリを直接使うよりはいろいろなフレームワークを利用しています。


我々も、現在 seedo.database パッケージを開発中です。
このパッケージの開発方針は、

1.ScalaのDBパッケージとしてリレーショナルデータベースを抽象化して、OracleやMySQL、DB2、SQL-Serverといった各種ベンダーの固有の機能や特徴を隠蔽しないことです。
ビジネスで使う限りはそのベンダーのデータベースの機能を使い切りたい。かといって型定義やSQL文法の細かい違いはできる限り吸収してしまいたい。

2.Scala文法とSQL文法を融合しない。インピーダンス・ミスマッチという古くて新しい言語問題です。
データベースを操作するために新しいライブラリや文法はもう覚えたくない。SQLはSQL言語として使うほうがいいと考えています。

3.プログラムのメンテナンス性を向上させる。読みやすさ重視です。ソースコードから動作がトレースできること。設計書やXMLなど設定ファイルを参照しなくてもプログラムの動作が追えることです。それと、JDBCは決まり文句が多すぎでした。Scalaのようにバッサリと無駄な記述はなくしてしまいたい。

4.性能は、Java JDBCドライバの関数で書いたものと遜色ないこと。

5.プログラム検証は、静的チェックが基本。プログラミングするよりプログラムテストの方がはるかにコストがかかりますから。動的チェックとしてSQL文の生成をデータベースのディクショナリを参照して実行する機能も有用でしょう。

今後の予定
2010年中にVersion1.0をリリースする予定でいます。

Javaとは違うScalaの良い特徴をいかした仕様になるよう研究中です。
scala.dbc2のいいところも取り入れましょう。Scalaらしい仕様だと思いますから。



SeeDo Scala Framework リリース
2011/1/1 になってしまいましたが、SeeDo Scala framework ( eWave Solutions Inc.(c) 2000-2011, LAMP/EPFL) をリリースします。
バージョンはVersion0.9 です。
downloadは、seedo.jar

JPAのannotationを使いますので、jpa.jarも download してください。

この2つのJarファイルを eclipse のプロジェットプロパティの Java ビルドパスの外部 JAR に追加します。

Oracleのsample user のscott のbean class のソースコードは、scott.zipから download できます。

DB アクセスは、テストコードで動作を確認できます。

Oracle11g でしか動作テストしていません。近日、MySQLで動作確認したバージョンをリリースします。

/*
 * SeeDo
 *  eWave Solutions Inc.(c) 2000-2011, LAMP/EPFL 
 */
package test

import org.scalatest.junit.JUnitSuite
import org.scalatest.junit.ShouldMatchersForJUnit
import org.junit.Test
import org.junit.Before
import org.junit.After
import org.junit.BeforeClass
import org.junit.AfterClass
import seedo._
import seedo.database._
import scott.bean._

class testDB extends JUnitSuite with ShouldMatchersForJUnit{
	var drivrName = "oracle.jdbc.driver.OracleDriver"
	var jdbcURL = "jdbc:oracle:thin:@127.0.0.1:1521:ORCL"
//	var jdbcURL = "jdbc:oracle:thin:@192.168.0.105:1521:ORCL"
	var user ="scott"
	var passwd ="tiger"
	var db:Db = _
  @Before def initialize() {
	  println("Start")
	  db = new Db(drivrName,jdbcURL,user,passwd)
  }
  @Test def verifyTable() { // Uses JUnit-style assertions & Uses ScalaTest assertions
	  db.select("ENAME,HIREDATE,EMPNO").from("EMP").where("empno >= ?",7700).orderBy("ename")
	  println(db.toString)
	  println(db.getSql)
	  println(" --- Array")
	  db.executeQuery.foreach(c =>{
	 	  c.foreach(d => {
	 	 	  print(" " + d)
	 	  })
	 	  println
	  })
	  println(" --- ColumnNameList")
	  db.getColumnNameList.foreach(c =>{
	 	  print(" " + c)
	  })
	  println
	  
	  db.select("*").from("EMP").where("empno >= ?",7700).orderBy("ename")
	  println(" --- BEAN")
	  println(db.toString)
	  println(db.getSql)
	  db.executeQuery[EMP](classOf[EMP]).foreach(c =>{
		  println(" " + c.toString + " " + c.toXml)
		  println(" " + c.toJson + " " + c.toXmlModified)
	  })
	  println(" --- ColumnNameList")
	  db.getColumnNameList.foreach(c =>{
	 	  print(" " + c)
	  })
	  println
  	  println(" --- DEPT table")	  
	  db.select("*").from("DEPT").orderBy("deptno")
	  db.executeQuery[DEPT](classOf[DEPT]).foreach(c =>{
		  println(" " + c.toString)
	  })

	  println
  	  println(" --- Update")
	  var empno = 7900
	  db.update("EMP").set("DEPTNO=?", 40).where("EMPNO=?",empno)
  	  println(" --- Update execute SQL="+db.toString)
	  val rt = db.execute
  	  println(" --- before result="+rt.getResultSize)
	  db.select("*").from("EMP").where("empno = ?",empno)
	  db.executeQuery[EMP](classOf[EMP]).foreach(c =>{
		  println(" " + c.toString)
	  })
  	  println(" --- Rollback")
	  db.rollback
	  println(" --- after")
	  db.select("*").from("EMP").where("empno = ?",empno)
	  db.executeQuery[EMP](classOf[EMP]).foreach(c =>{
		  println(" " + c.toString)
	  })
	  
  	  println
  	  println(" --- Begin transaction")
  	  db.begin
  	  println(" --- Insert")
  	  db.insertInto("EMP").column("empno,ename,hiredate,deptno,sal").values("?,?,sysdate,?,?", 1000,"曙",20,2001)
  	  println(" --- Insert execute SQL="+db.toString)
  	  val rt1 = db.execute
  	  println(" --- Insert result="+rt1.getResultSize)
	  db.select("*").from("EMP").where("empno = ?",1000)
	  db.executeQuery[EMP](classOf[EMP]).foreach(c =>{
		  println(" " + c.toString)
	  })
	  println(" --- End Sql")
	  
  	  println(" --- Delete")
  	  db.deleteFrom("EMP").where("empno=?",1000)
  	  println(" --- Delete execute SQL="+db.toString)
  	  val rt2 = db.execute
  	  println(" --- Delete result="+rt2.getResultSize)
	  db.select("*").from("EMP").where("empno = ?",1000)
	  db.executeQuery[EMP](classOf[EMP]).foreach(c =>{
		  println(" " + c.toString)
	  })
	  println(" --- End Sql")

	  println(" --- Commit")
  	  db.commit
  	  println(" --- Emp table list")
	  db.select("*").from("EMP").orderBy("empno")
	  db.executeQuery[EMP](classOf[EMP]).foreach(c =>{
		  println(" " + c.toString)
	  })
	  println(" --- End Sql")
  }
  @After def close() {
	  if(db != null)
		  db.close
	  println("End")
  }
}

実行結果です。

Start
JDBC Driver:Oracle JDBC driver Version:11.1.0.6.0-Production
Database:Oracle Version:11.1
select ENAME,HIREDATE,EMPNO from EMP where empno >= ? order by ename [7700]
select ENAME,HIREDATE,EMPNO from EMP where empno >= ? order by ename
 --- Array
 ADAMS 1987-05-23 00:00:00.0 7876
 CLARK 1981-06-09 00:00:00.0 7782
 FORD 1981-12-03 00:00:00.0 7902
 JAMES 1981-12-03 00:00:00.0 7900
 KING 1981-11-17 00:00:00.0 7839
 MILLER 1982-01-23 00:00:00.0 7934
 SCOTT 1987-04-19 00:00:00.0 7788
 TURNER 1981-09-08 00:00:00.0 7844
 --- ColumnNameList
 ENAME HIREDATE EMPNO
 --- BEAN
select * from EMP where empno >= ? order by ename [7700]
select * from EMP where empno >= ? order by ename
 7876,ADAMS,CLERK,7788,1987-05-23 00:00:00.0,1100,null,20 7876ADAMSCLERK77881987-05-23 00:00:00.000110020
 {"EMP" : {"EMPNO" : "7876","ENAME" : "ADAMS","JOB" : "CLERK","MGR" : "7788","HIREDATE" : "1987-05-23 00:00:00.0","SAL" : "1100","COMM" : "null","DEPTNO" : "20"}} 7876ADAMSCLERK77881987-05-23 00:00:00.000110020
 7782,CLARK,MANAGER,7839,1981-06-09 00:00:00.0,2450,null,10 7782CLARKMANAGER78391981-06-09 00:00:00.000245010
 {"EMP" : {"EMPNO" : "7782","ENAME" : "CLARK","JOB" : "MANAGER","MGR" : "7839","HIREDATE" : "1981-06-09 00:00:00.0","SAL" : "2450","COMM" : "null","DEPTNO" : "10"}} 7782CLARKMANAGER78391981-06-09 00:00:00.000245010
 7902,FORD,ANALYST,7566,1981-12-03 00:00:00.0,3000,null,20 7902FORDANALYST75661981-12-03 00:00:00.000300020
 {"EMP" : {"EMPNO" : "7902","ENAME" : "FORD","JOB" : "ANALYST","MGR" : "7566","HIREDATE" : "1981-12-03 00:00:00.0","SAL" : "3000","COMM" : "null","DEPTNO" : "20"}} 7902FORDANALYST75661981-12-03 00:00:00.000300020
 7900,JAMES,CLERK,7698,1981-12-03 00:00:00.0,950,null,30 7900JAMESCLERK76981981-12-03 00:00:00.00095030
 {"EMP" : {"EMPNO" : "7900","ENAME" : "JAMES","JOB" : "CLERK","MGR" : "7698","HIREDATE" : "1981-12-03 00:00:00.0","SAL" : "950","COMM" : "null","DEPTNO" : "30"}} 7900JAMESCLERK76981981-12-03 00:00:00.00095030
 7839,KING,PRESIDENT,null,1981-11-17 00:00:00.0,5000,null,10 7839KINGPRESIDENT1981-11-17 00:00:00.000500010
 {"EMP" : {"EMPNO" : "7839","ENAME" : "KING","JOB" : "PRESIDENT","MGR" : "null","HIREDATE" : "1981-11-17 00:00:00.0","SAL" : "5000","COMM" : "null","DEPTNO" : "10"}} 7839KINGPRESIDENT1981-11-17 00:00:00.000500010
 7934,MILLER,CLERK,7782,1982-01-23 00:00:00.0,1300,null,10 7934MILLERCLERK77821982-01-23 00:00:00.000130010
 {"EMP" : {"EMPNO" : "7934","ENAME" : "MILLER","JOB" : "CLERK","MGR" : "7782","HIREDATE" : "1982-01-23 00:00:00.0","SAL" : "1300","COMM" : "null","DEPTNO" : "10"}} 7934MILLERCLERK77821982-01-23 00:00:00.000130010
 7788,SCOTT,ANALYST,7566,1987-04-19 00:00:00.0,3000,null,20 7788SCOTTANALYST75661987-04-19 00:00:00.000300020
 {"EMP" : {"EMPNO" : "7788","ENAME" : "SCOTT","JOB" : "ANALYST","MGR" : "7566","HIREDATE" : "1987-04-19 00:00:00.0","SAL" : "3000","COMM" : "null","DEPTNO" : "20"}} 7788SCOTTANALYST75661987-04-19 00:00:00.000300020
 7844,TURNER,SALESMAN,7698,1981-09-08 00:00:00.0,1500,0,30 7844TURNERSALESMAN76981981-09-08 00:00:00.0001500030
 {"EMP" : {"EMPNO" : "7844","ENAME" : "TURNER","JOB" : "SALESMAN","MGR" : "7698","HIREDATE" : "1981-09-08 00:00:00.0","SAL" : "1500","COMM" : "0","DEPTNO" : "30"}} 7844TURNERSALESMAN76981981-09-08 00:00:00.0001500030
 --- ColumnNameList
 EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
 --- DEPT table
 10,ACCOUNTING,NEW YORK
 20,RESEARCH,DALLAS
 30,SALES,CHICAGO
 40,OPERATIONS,BOSTON

 --- Update
 --- Update execute SQL=update EMP set DEPTNO=? where EMPNO=? [40] [7900]
 --- before result=1
 7900,JAMES,CLERK,7698,1981-12-03 00:00:00.0,950,null,40
 --- Rollback
 --- after
 7900,JAMES,CLERK,7698,1981-12-03 00:00:00.0,950,null,30

 --- Begin transaction
 --- Insert
 --- Insert execute SQL=insert into EMP (empno,ename,hiredate,deptno,sal) values (?,?,sysdate,?,?) [1000] [曙] [20] [2001]
 --- Insert result=1
 1000,曙,null,null,2011-01-01 14:27:28.0,2001,null,20
 --- End Sql
 --- Delete
 --- Delete execute SQL=delete from EMP where empno=? [1000]
 --- Delete result=1
 --- End Sql
 --- Commit
 --- Emp table list
 7369,SMITH,CLERK,7902,1980-12-17 00:00:00.0,800,null,20
 7499,ALLEN,SALESMAN,7698,1981-02-20 00:00:00.0,1600,300,30
 7521,WARD,SALESMAN,7698,1981-02-22 00:00:00.0,1250,500,30
 7566,JONES,MANAGER,7839,1981-04-02 00:00:00.0,2975,null,20
 7654,MARTIN,SALESMAN,7698,1981-09-28 00:00:00.0,1250,1400,30
 7698,BLAKE,MANAGER,7839,1981-05-01 00:00:00.0,2850,null,30
 7782,CLARK,MANAGER,7839,1981-06-09 00:00:00.0,2450,null,10
 7788,SCOTT,ANALYST,7566,1987-04-19 00:00:00.0,3000,null,20
 7839,KING,PRESIDENT,null,1981-11-17 00:00:00.0,5000,null,10
 7844,TURNER,SALESMAN,7698,1981-09-08 00:00:00.0,1500,0,30
 7876,ADAMS,CLERK,7788,1987-05-23 00:00:00.0,1100,null,20
 7900,JAMES,CLERK,7698,1981-12-03 00:00:00.0,950,null,30
 7902,FORD,ANALYST,7566,1981-12-03 00:00:00.0,3000,null,20
 7934,MILLER,CLERK,7782,1982-01-23 00:00:00.0,1300,null,10
 --- End Sql
End

コメントを残す