Java JDBC 使用 SQLite/操作数据
JDBC 提供了许多不同的方法来处理数据和数据对象操作。通常这些方法分为三类:代理 Prepared 语句的方法,期望从数据库返回数据的的方法(这些方法总是会返回一个 ResultSet),以及最后是在不期望返回信息的情况下对数据库进行操作的方法,例如创建一个表或从表中删除一些数据。
使用 PreparedStatement (PS) 方法与数据库交互有充分的理由,特别是当交互重复时,因为 PS 会被发送到数据库进行编译,这意味着在随后的调用中,数据库可以访问调用而无需重新编译,从而导致更快的执行时间。
与使用与 Connection 对象关联的 Statements 的其他方法调用一样,PreparedStatement 也与 Connection 相关联。
[.. pseudocode ..]
Connection conn = new Connection(); // whatever it might be
String psString = "UPDATE myTable SET myText = 'First Update'";
String psStringWithParms = "UPDATE myTable SET myText = ?";
// prepare & execute the psString
PreparedStatement ps = conn.prepareStatement(psString);
ps.executeUpdate();
// now we will overwrite this using the parameterised psString
PreparedStatement psParms = conn.prepareStatement(psStringWithParms);
psParms.setString(1,"Revised update");
psParms.executeUpdate();
在与数据库交互时,经常会遇到不知道列名或给定 SQL 查询将返回的数据类型的场景。幸运的是,JDBC 类提供了两个非常有用的接口,可以利用它们来解决这个问题:ResultSetMetaData 和 DatabaseMetaData。
可以在此处找到结果集接口的 Java 文档:[1]。该接口在任何给定的结果集实例中都能够有效地暴露列名和数据类型(以及更多内容)。
例如,可以使用以下示例方法来暴露列名
public static String[] getColumnNameArray(ResultSet rs) {
String sArr[] = null;
try {
ResultSetMetaData rm = rs.getMetaData();
String sArray[] = new String[rm.getColumnCount()];
for (int ctr = 1; ctr <= sArray.length; ctr++) {
String s = rm.getColumnName(ctr);
sArray[ctr - 1] = s;
}
return sArray;
} catch (Exception e) {
System.out.println(e);
return sArr;
}
}
可以对数据类型做同样的事情
public static String[] getColumnTypeArray(ResultSet rs) {
String sArr[] = null;
try {
ResultSetMetaData rm = rs.getMetaData();
String sArray[] = new String[rm.getColumnCount()];
for (int ctr = 1; ctr <= sArray.length; ctr++) {
String s = rm.getColumnTypeName(ctr);
sArray[ctr - 1] = s;
}
return sArray;
} catch (Exception e) {
System.out.println(e);
return sArr;
}
}
通过使用 ResultSetMetaData 的 getColumnCount() 方法,可以避免不必要的将数据传递到 Vector 并重新转换为 String[] 数组,因为可以直接从一开始就适当地调整 String[] 数组的大小。
到目前为止,你可能已经注意到,除了调用的 ResultSetMetaData 方法外,这两段代码在功能上几乎相同,可以在这里进行一些合理化,例如使用一个处理迭代的第三个方法,或者可能使用 java.lang.reflect 动态加载方法。在生产系统中,你可能希望避免在反射中增加 JVM 的工作量(Java 反射本身很昂贵),但可以轻松地编写一个 switch 块来完成适当的简化,传递一个额外的参数来指示在构造 String[] 数组时要调用哪个方法。
现在,让我们通过假设正在创建一个名为 testme 的数据库表的查询类,并且不知道它的列名和类型来将这些代码整合在一起。
import java.sql.ResultSetMetaData;
public class MyDbTest
{
public void main(String[] args)
{
SqliteDb db = new Sqlite("C:/DbStore/test.db");
String sqltest = "SELECT * FROM testme";
Vector<Object> v = new Vector<Object>();
try
{
ResultSet rs = db.executeQry(sqltest);
String[] columnNames = getColumnNameArray(rs);
String[] columnTypes = getColumnTypeArray(rs);
//iterate the rows in the result set...
while(rs.next())
{
// now walk each column in the array...
for (int i = 1; i < columnNames.length; i++)
{
Object o = rs.getObject(columnNames[i]);
if (columnTypes[i].toUpper().equals("VARCHAR"))
{
sVal = o.toString();
}
[etcetera ..]
[..]
}
}
catch (Exception e)
{
[..]
}
}
有关列类型的完整列表,请参阅附录。