在 SQLite 中为 JavaFX 应用程序插入数据
Insert data in SQLite for JavaFX Applications
我下面的这个 class 叫做 Database 以方便操作我的 sqlite 数据库:
public class Database {
private String conString = "jdbc:sqlite:database.db";
private Connection con = null;
public Database() {
try {
Class.forName("org.sqlite.JDBC");
} catch (Exception ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public Connection getConnection() {
try {
con = DriverManager.getConnection(conString);
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
con = null;
}
return con;
}
public void initTables() {
try {
Statement st = getConnection().createStatement();
st.execute("CREATE TABLE IF NOT EXISTS setting(name TEXT, value TEXT)");
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
// ################################################################################
// # SETTING TABLE
// ################################################################################
public List<Setting> getSettings() {
List<Setting> result = new ArrayList<Setting>();
try {
Statement st = getConnection().createStatement();
ResultSet r = st.executeQuery("SELECT * FROM setting");
while (r.next()) {
result.add(new Setting(r.getString("name"), r
.getString("value")));
}
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
result = new ArrayList<Setting>();
}
return result;
}
public void createSetting(Setting s) {
try {
Statement st = getConnection().createStatement();
st.execute("INSERT INTO setting (name,value) VALUES(" + s.getName()
+ "," + s.getValue() + ")");
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public void updateSetting(Setting s) {
try {
Statement st = getConnection().createStatement();
st.execute("UPDATE setting SET value = " + s.getValue()
+ " WHERE name = " + s.getName());
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public Setting findSetting(String name) {
Setting setting = null;
try {
Statement st = getConnection().createStatement();
ResultSet rs = st
.executeQuery("SELECT * FROM setting WHERE name = " + name);
while (rs.next()) {
setting = new Setting(rs.getString("name"),
rs.getString("value"));
}
} catch (Exception ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
setting = null;
}
return setting;
}
}
调用createSetting
方法后,抛出错误:
Jul 21, 2015 3:26:49 PM com.database.Database createSetting
SEVERE: null
java.sql.SQLException: [SQLITE_ERROR] SQL error or missing database (no such column: fname)
at org.sqlite.core.DB.newSQLException(DB.java:890)
at org.sqlite.core.DB.newSQLException(DB.java:901)
at org.sqlite.core.DB.throwex(DB.java:868)
at org.sqlite.core.NativeDB.prepare(Native Method)
at org.sqlite.core.DB.prepare(DB.java:211)
at org.sqlite.jdbc3.JDBC3Statement.execute(JDBC3Statement.java:60)
at com.rameses.database.Database.createSetting(Database.java:68)
at com.rameses.sample.DatabaseSample.handle(DatabaseSample.java:35)
at com.rameses.sample.DatabaseSample.handle(DatabaseSample.java:31)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8390)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)
at javafx.scene.Scene$MouseHandler.access00(Scene.java:3486)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent0(GlassViewEventHandler.java:385)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda7/1740853902.get(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:927)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null5(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda/485815673.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
实际的调用过程是这样的:
save.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event) {
Database db = new Database();
db.createSetting(new Setting(name.getText(),value.getText()));
}
});
问题:您认为错误在哪里,如何解决?
您需要用引号将查询中的值括起来。
所以查询:
st.execute("INSERT INTO setting (name,value) VALUES(" + s.getName()
+ "," + s.getValue() + ")");
应该是:
st.execute("INSERT INTO setting (name,value) VALUES('" + s.getName()
+ "','" + s.getValue() + "')");
问题出在这一行:
st.execute("INSERT INTO setting (name,value) VALUES(" + s.getName()
+ "," + s.getValue() + ")");
原因是要插入的值没有正确转义(实际上根本没有转义)。天真的解决方案(只是为了演示缺陷)是将值括在单引号中。当然,这会让您面临潜在的 SQL 注入问题!
st.execute("INSERT INTO setting (name,value) VALUES('" + s.getName()
// HERE --------------------------------------------^
+ "','" + s.getValue() + "')");
// HERE ---^-^--------------------^
要避免 SQL 注入问题,请使用 PreparedStatement
s:
PreparedStatement ps = getConnection().prepareStatement("INSERT INTO setting (name,value) VALUES(?,?)");
ps.setString(1, s.getName());
ps.setString(2, s.getValue());
ps.executeUpdate();
(您还需要正确关闭语句,尤其是 final
子句中的连接。)
我下面的这个 class 叫做 Database 以方便操作我的 sqlite 数据库:
public class Database {
private String conString = "jdbc:sqlite:database.db";
private Connection con = null;
public Database() {
try {
Class.forName("org.sqlite.JDBC");
} catch (Exception ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public Connection getConnection() {
try {
con = DriverManager.getConnection(conString);
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
con = null;
}
return con;
}
public void initTables() {
try {
Statement st = getConnection().createStatement();
st.execute("CREATE TABLE IF NOT EXISTS setting(name TEXT, value TEXT)");
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
// ################################################################################
// # SETTING TABLE
// ################################################################################
public List<Setting> getSettings() {
List<Setting> result = new ArrayList<Setting>();
try {
Statement st = getConnection().createStatement();
ResultSet r = st.executeQuery("SELECT * FROM setting");
while (r.next()) {
result.add(new Setting(r.getString("name"), r
.getString("value")));
}
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
result = new ArrayList<Setting>();
}
return result;
}
public void createSetting(Setting s) {
try {
Statement st = getConnection().createStatement();
st.execute("INSERT INTO setting (name,value) VALUES(" + s.getName()
+ "," + s.getValue() + ")");
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public void updateSetting(Setting s) {
try {
Statement st = getConnection().createStatement();
st.execute("UPDATE setting SET value = " + s.getValue()
+ " WHERE name = " + s.getName());
} catch (SQLException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public Setting findSetting(String name) {
Setting setting = null;
try {
Statement st = getConnection().createStatement();
ResultSet rs = st
.executeQuery("SELECT * FROM setting WHERE name = " + name);
while (rs.next()) {
setting = new Setting(rs.getString("name"),
rs.getString("value"));
}
} catch (Exception ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null,
ex);
setting = null;
}
return setting;
}
}
调用createSetting
方法后,抛出错误:
Jul 21, 2015 3:26:49 PM com.database.Database createSetting
SEVERE: null
java.sql.SQLException: [SQLITE_ERROR] SQL error or missing database (no such column: fname)
at org.sqlite.core.DB.newSQLException(DB.java:890)
at org.sqlite.core.DB.newSQLException(DB.java:901)
at org.sqlite.core.DB.throwex(DB.java:868)
at org.sqlite.core.NativeDB.prepare(Native Method)
at org.sqlite.core.DB.prepare(DB.java:211)
at org.sqlite.jdbc3.JDBC3Statement.execute(JDBC3Statement.java:60)
at com.rameses.database.Database.createSetting(Database.java:68)
at com.rameses.sample.DatabaseSample.handle(DatabaseSample.java:35)
at com.rameses.sample.DatabaseSample.handle(DatabaseSample.java:31)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8390)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)
at javafx.scene.Scene$MouseHandler.access00(Scene.java:3486)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent0(GlassViewEventHandler.java:385)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda7/1740853902.get(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:927)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null5(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda/485815673.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
实际的调用过程是这样的:
save.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event) {
Database db = new Database();
db.createSetting(new Setting(name.getText(),value.getText()));
}
});
问题:您认为错误在哪里,如何解决?
您需要用引号将查询中的值括起来。
所以查询:
st.execute("INSERT INTO setting (name,value) VALUES(" + s.getName()
+ "," + s.getValue() + ")");
应该是:
st.execute("INSERT INTO setting (name,value) VALUES('" + s.getName()
+ "','" + s.getValue() + "')");
问题出在这一行:
st.execute("INSERT INTO setting (name,value) VALUES(" + s.getName()
+ "," + s.getValue() + ")");
原因是要插入的值没有正确转义(实际上根本没有转义)。天真的解决方案(只是为了演示缺陷)是将值括在单引号中。当然,这会让您面临潜在的 SQL 注入问题!
st.execute("INSERT INTO setting (name,value) VALUES('" + s.getName()
// HERE --------------------------------------------^
+ "','" + s.getValue() + "')");
// HERE ---^-^--------------------^
要避免 SQL 注入问题,请使用 PreparedStatement
s:
PreparedStatement ps = getConnection().prepareStatement("INSERT INTO setting (name,value) VALUES(?,?)");
ps.setString(1, s.getName());
ps.setString(2, s.getValue());
ps.executeUpdate();
(您还需要正确关闭语句,尤其是 final
子句中的连接。)