JavaFX应用Inno打包后SQLite数据库创建及增删操作异常
问题根因
两种打包方案的异常核心原因一致:数据库文件存放路径错误,触发Windows系统Program Files目录的权限保护机制。
- 代码中直接使用
String dbName = "patientdata";定义相对路径访问数据库,程序启动时相对路径的根目录为JAR包所在的安装文件夹。 - Inno Setup默认配置会将程序安装到
C:\Program Files (x86)\[程序名]目录,该目录为Windows系统级受保护目录,普通用户权限仅拥有读取权限,无写入权限:- 方案1仅打包JAR时,程序尝试在安装目录下新建SQLite数据库文件,因无写入权限创建失败
- 方案2将预生成的数据库文件随安装包放到安装目录时,读取存量数据不需要写入权限因此可以正常运行,但新增、删除操作需要修改数据库文件,因无写入权限执行失败
- Eclipse开发环境下程序的工作目录为项目源码文件夹,当前登录用户对该文件夹拥有完全读写权限,因此开发阶段功能运行完全正常。
修复方案
1. 修改数据库文件存储路径
桌面应用的用户数据禁止存放在安装目录,需存储到系统为当前用户分配的可读写应用数据目录,修改getConnection()方法中数据库路径相关逻辑:
public static Connection getConnection() { Connection conn = null; Statement stmt = null; try { String dbName = "patientdata"; // 获取当前用户专属的AppData应用数据目录,该目录默认拥有完全读写权限 String appDataPath = System.getenv("APPDATA") + File.separator + "PatientManageSystem"; File appFolder = new File(appDataPath); // 程序目录不存在则自动创建 if (!appFolder.exists()) { appFolder.mkdirs(); } File file = new File(appFolder, dbName); if(file.exists()) { System.out.println("patient file exists: "+ file.getAbsolutePath()); } else { System.out.println("patient file not exist: Created new one "); } try{ Class.forName("org.sqlite.JDBC"); // 连接字符串使用数据库文件的绝对路径 conn = DriverManager.getConnection("jdbc:sqlite:"+file.getAbsolutePath()); System.out.println("data base connection established: "+ conn.toString()); // 后续建表逻辑保持原有代码即可 stmt = conn.createStatement(); String pat = "CREATE TABLE if not exists newpatient " + "(patientId INTEGER NOT NULL," + " patientName CHAR(50) NOT NULL, " + " patientAge INTEGER NOT NULL, " + "patientGender CHAR(10) NOT NULL,"+ "patientAddress CHAR(100) NOT NULL,"+ "patientMobile BIGINT(10) NOT NULL)"; System.out.println("newpatient Table Created: "); stmt.executeUpdate(pat); stmt.close(); stmt = conn.createStatement(); String hist = "CREATE TABLE if not exists history " + "(id INTEGER NOT NULL," + " date DATE NOT NULL, " + " start TIME NOT NULL, " + "stop TIME NOT NULL)"; System.out.println("history Table Created: "); stmt.executeUpdate(hist); stmt.close(); Dialog<Void> pop = new Dialog<Void>(); pop.setContentText("Data base accessed"); pop.getDialogPane().getButtonTypes().add(ButtonType.CLOSE); Node closeButton = pop.getDialogPane().lookupButton(ButtonType.CLOSE); closeButton.setVisible(false); pop.showAndWait(); }catch(SQLException tb){ System.err.println(tb.getClass().getName() + ": " + tb.getMessage()); Dialog<Void> pop = new Dialog<Void>(); pop.setContentText("Data base not accessed"); pop.getDialogPane().getButtonTypes().add(ButtonType.CLOSE); Node closeButton = pop.getDialogPane().lookupButton(ButtonType.CLOSE); closeButton.setVisible(false); pop.showAndWait(); } }catch(Exception e) { System.err.println(e.getClass().getName() + ": " + e.getMessage()); } return conn; }
代码中PatientManageSystem可替换为你自己的程序实际名称
2. 调整Inno Setup打包规则
- 不需要将预生成的空数据库文件打入安装包,程序第一次启动时会自动在当前用户的AppData目录下创建数据库文件及对应表结构
- 若需要给新用户预置初始数据,可将带初始数据的数据库文件作为资源打入JAR包内部,程序首次启动时检测到用户目录下无数据库文件,就将JAR包内的初始数据库复制到AppData对应目录后再建立连接,禁止直接读写JAR包内部的数据库文件——JAR为压缩包格式,内部文件不支持直接写入修改。
3. 代码优化建议
现有代码采用字符串拼接方式生成SQL语句,存在SQL注入风险,且输入内容包含单引号时会直接导致SQL执行报错,建议替换为PreparedStatement预编译方式执行增删改操作,示例如下:
private void insertrecord() { String query ="INSERT INTO newpatient(patientId,patientName,patientAge,patientGender,patientAddress,patientMobile) VALUES (?,?,?,?,?,?)"; // 使用try-with-resources语法自动关闭连接和语句对象,避免数据库文件被长期锁定 try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(query)){ pstmt.setInt(1, Integer.parseInt(newpatient_id.getText())); pstmt.setString(2, newpatient_name.getText()); pstmt.setInt(3, Integer.parseInt(newpatient_age.getText())); pstmt.setString(4, selectedGender); pstmt.setString(5, newpatient_address.getText()); pstmt.setLong(6, Long.parseLong(newpatient_mobile.getText())); pstmt.executeUpdate(); System.out.println("Saved"); Main.selected_patient_id = Integer.parseInt(newpatient_id.getText()); } catch(Exception e) { System.out.println("Exception in Save"); e.printStackTrace(); } }
现有代码中数据库连接、Statement执行完成后未主动关闭,会持续占用数据库文件句柄,运行时间长了会触发SQLite数据库锁,建议所有数据库操作都采用try-with-resources写法自动释放资源。
内容的提问来源于stack exchange,提问作者mexco
相关产品推荐
相关产品推荐

