Java:数据库检查和初始化

标签 java sql sqlite db-schema

我正在编写一个 Java 应用程序,它通过 JDBC 使用 SQLite 来实现持久性。

应用程序启动时我需要做的是:

  1. 如果数据库不存在,请使用正确的架构创建它
  2. 如果数据库存在,请检查数据库是否具有正确的架构

为了创建数据库,我想到将创建结构(例如 CREATE TABLE ...)所需的 SQL 命令外部化在外部文件中,在运行时加载并执行它。 我考虑将 BufferedReader 与 .readLine() 结合使用,然后将每个 SQL 命令提供给 Statement.executeUpdate()。有没有更聪明的方法来做到这一点?

关于数据库模式的启动检查,虽然我认为这应该被认为是“好的设计”,但我不知道在实践中它是否会矫枉过正或无用。 我提出的一种解决方案,但其缺点是“依赖于供应商”:

  1. 使用所有结构名称的已知前缀(例如 nwe_)创建数据库
  2. 使用 WHERE name LIKE 'nwe_%' 查询 sqlite_master
  3. SQL 列的内容与我用于创建数据库的 SQL 命令文件进行比较

再说一遍,有没有更聪明的方法来做到这一点? (也许不是“依赖于供应商”,但这对我来说并不是什么大问题)

谢谢。

最佳答案

我不是专业程序员,这是我的第一个 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);
        }
    }
}

关于Java:数据库检查和初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10852626/

相关文章:

ios - 从SQLite提取数据并且只想获取列ID的最后一个值

java - 如何在 Struts 2 中将 WAR 和 JAR 文件打包成 EAR

java - 在 LDAP 搜索过滤器中,是否可以请求多值字段的第一个、第二个、第 n 个或最后一个值?

java - 使用 JAD 反编译 java - 限制

sql - Postgres 过滤 WITH 查询

ios - Sqlite_prepare_v2返回SQLite_ERROR

java - 通过 Kafka 发送/接收 Java 对象

mysql - 从消息线程中获取嵌套的未读消息

mysql - MySQL 中按天分组的性能​​比较

android - SQLite在打开数据库时强制关闭