2012年2月1日水曜日

java : sqlite + jdbcでテータベースアタッチのサンプル

前の投稿で「アタッチがアトミックでどうこう」って書いたので、一応アタッチの小さなサンプルコードを書きました。 アトミックかどうかはノータッチで。

jdbcはこちらで配布しているものを使いました。

以下コード。

package sqlitetest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.sqlite.Function;

public class SQLiteTest
{
    private static final String DB_MAIN_NAME = "d:/testmain";
    private static final String DB_SUB_NAME = "d:/testsub";

    public static void main(String[] args) throws ClassNotFoundException
    {
        Class.forName("org.sqlite.JDBC");

        createDatabase(DB_MAIN_NAME, "tmain");
        createDatabase(DB_SUB_NAME, "tsub");

        Connection c = null;
        try
        {
            c = DriverManager.getConnection("jdbc:sqlite:" + DB_MAIN_NAME);
            Statement s = c.createStatement();
            s.execute("attach '" + DB_SUB_NAME + "' as subdb");

            c.setAutoCommit(false);
            s.executeUpdate("insert into tmain values(1, 'foo')");
            s.executeUpdate("insert into tmain values(2, 'bar')");
            s.executeUpdate("insert into tsub values(1, 'hoge')");
            s.executeUpdate("insert into tsub values(2, 'fuga')");
            c.commit();

            ResultSet res = s.executeQuery(
                "select tmain.id as id, tmain.name as main_name, tsub.name as sub_name from tmain, tsub where tmain.id = tsub.id"
            );
            while(res.next())
            {
                System.out.println("id = " + res.getInt("id"));
                System.out.println("main : name = " + res.getString("main_name"));
                System.out.println("sub : name = " + res.getString("sub_name"));
            }
        }
        catch(SQLException exc)
        {
            exc.printStackTrace();
            if(c != null)
            {
                try
                {
                    if(c != null) c.rollback();
                }
                catch(SQLException rexc)
                {
                    rexc.printStackTrace();
                }

            }
        }
        finally
        {
            try
            {
                if(c != null) c.close();
            }
            catch(Exception exc){}
        }
    }

    public static void createDatabase(String dbPath, String tableName)
    {
        Connection c = null;
        try
        {
            c = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
            Statement s = c.createStatement();
            s.executeUpdate("drop table if exists " + tableName);
            s.executeUpdate("create table " + tableName + " (id integer, name string)");
        }
        catch(SQLException exc)
        {
            exc.printStackTrace();
        }
        finally
        {
            try
            {
                if(c != null) c.close();
            }
            catch(SQLException exc){}
        }
    }
}

メインのデータベースとアタッチしたデータベースとでテーブル名がかぶっている場合、アタッチした側にプリフィックスを付けないとダメです。

attach 'd:/testsub' as subdb
select * from subdb.samename ← asで指定したプリフィックスが必要

今回のサンプルではかぶってないのでプリフィックス不要。