0

永続化のために JDBC 経由で SQLite を使用する Java アプリケーションを作成しています。

アプリケーションの起動時に必要なことは次のとおりです。

  1. DB が存在しない場合は、適切なスキーマで作成します
  2. DB が存在する場合は、DB に適切なスキーマがあるかどうかを確認します

DBを作成するために、構造を作成するために必要なSQLコマンド(CREATE TABLEなど)を外部ファイルに外部化し、実行時にロードして実行することを考えました。BufferedReaderwithを使用して.readLine()、各 SQL コマンドをStatement.executeUpdate(). これを行うためのよりスマートな方法はありますか?

データベーススキーマの起動チェックに関しては、これは「良い設計」と考えるべきだと思いますが、実際にはやり過ぎなのか、役に立たないのかはわかりません。私が思いついた解決策の 1 つですが、「ベンダーに依存する」という欠点があります。

  1. すべての構造の名前に既知のプレフィックスを使用して DB を作成します (例: nwe_)
  2. sqlite_masterでテーブルをクエリしますWHERE name LIKE 'nwe_%'
  3. SQL列の内容を、DB の作成に使用した SQL コマンド ファイルと比較します。

繰り返しますが、これを行うためのよりスマートな方法はありますか? (「ベンダー依存」ではないかもしれませんが、現時点ではこれはあまり問題ではありません)

ありがとう。

4

2 に答える 2

4

私はプロのプログラマーではなく、これが初めての Java アプリケーションですが、データベースの検証も行うことにしました。幸いなことに、sqlite データベースには、データベース内の各テーブルの sql ステートメントを含むシステム テーブルがあります。したがって、データベース構造をチェックするための高速で汚れた方法があります。

public class Model {
    private Map<String, String> tableSql;

    Model(){
        // declare right database's tables syntax 
        tableSql = new HashMap<String, String>();
        tableSql.put("settings",    "CREATE TABLE [settings] ( [id]     INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [item] ... )");
        tableSql.put("scheta",      "CREATE TABLE [scheta] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [sname] ...)");
        tableSql.put("nomera",      "CREATE TABLE [nomera] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [nvalue] ...)");
        tableSql.put("corr",        "CREATE TABLE [corr] (  [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [cname] ...)");
        tableSql.put("category",    "CREATE TABLE [category] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [cname] ...)");
        tableSql.put("price",       "CREATE TABLE [price] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [cdate] ...)");
    }

    public void Connect( String path){
        File DBfile = new File (path);
        boolean DBexists = DBfile.exists();
        Statement stmt = null;
        ResultSet rs;

        try {
            Class.forName("org.sqlite.JDBC");
            c = DriverManager.getConnection("jdbc:sqlite:" + path);
            c.setAutoCommit(true);

            stmt = c.createStatement();
            if( DBexists ){
                // check database structure
                for (String tableName : tableSql.keySet()) {
                    rs = stmt.executeQuery( "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '" + tableName + "'");
                    if(rs.isBeforeFirst()){
                        rs.next();
                        // table and field names may be inside square brackets or inside quotes...
                        String table_schema_there = rs.getString(1).replaceAll("\\s+"," ").replaceAll("[\\[\\]'`]", "\"");
                        String table_schema_here = tableSql.get(tableName).replaceAll("\\s+"," ").replaceAll("[\\[\\]'`]", "\"");;
                        if( ! table_schema_there.equals(table_schema_here) ){
                            notifyListeners( new ModelResponse( false, "Structure error. Wrong structure of table "  + tableName));
                            System.exit(0);
                        }
                    }
                    else{
                        notifyListeners( new ModelResponse( false, "Structure error. The table is missing: "  + tableName ));
                        System.exit(0);
                    }
                }
            }
            else{
                // empty DB file created during connection so we need to create schema
                for (String tableName : tableSql.keySet()) {
                    stmt.executeUpdate(tableSql.get(tableName));
                }
            }
        } 
        catch ( Exception e ) {
            notifyListeners( new ModelResponse( false, e.getMessage()));
            System.exit(0);
        }
    }
}
于 2014-04-22T18:21:17.203 に答える
1

メタデータ テーブルを調べて、データベースの独自の検証を作成できます。これは不可能ではありませんが、維持するコードが多くなります。また、多くの DDL ステートメントを記述してデータベース構造を構築することもできます。これも不可能ではありませんが、維持するコードが多くなります。

そのような道をたどる場合は、より高度なロジックをお勧めします

if (!checkDatabase()) {
  try {
    if (wantsToInstall()) {
      installDatabase();
    }
  } catch (Exception e) {
    exit();
  }
}

または特定のインストーラー (既存のアイテムの上にインストールする可能性を減らすため)。データ項目の削除を提供する拡張機能を実行できますが、インストール/アップグレード中に予期しない既存のオブジェクトに遭遇した場合の対処方法については意見が分かれています。

現在、これを行うライブラリがいくつかあります。しかし、彼らがこの機能を追加する頃には、そのようなライブラリーはおそらく単純なデータベース構造のメンテナンス以上のことを処理します。JDO や他のいくつかを見てください。DataNucleus の環境は、20 以上の異なるデータベースでうまく機能するように調整されたデータベース構造を喜んで作成することを知っています (それらはすべて、動作方法に微妙な違いがあることを思い出してください)。

于 2012-06-01T15:17:28.947 に答える