使用PreparedStatement插入记录的过程,首先是调用预插入语句创建PreparedStatement对象,如在上一篇中的示意性代码:
String preparedStatement_insert = "insert into tableName (col_long,col_string,col_binarystream,col_date ) values (?,?,?,?)";
PreparedStatement pstmt = con.prepareStatement(preparedStatement_insert);
插入多少个字段的数据由values(?,?,?,?)部分决定,其中的通配符“?”代表了任意类型的数据,而插入什么类型的数据
由字段数据的Java类型决定,通过调用pstmt.setXXX(通配符位号,匹配字段类型的数据)方法实现。
针对一个已经明确的数据库的表,实现一个具体的PreparedStatement插入操作没有什么难度,因为字段的类型已经明确。而实现一个通用的PreparedStatement插入方法就存在着一定的挑战。JadePool如何实现通用的PreparedStatement插入方法,必需要理清SQL字段类型、SQL字段类型的名称及其与Java类三者之间的对应关系;在JadePool中,Field类把分散在元数据中的相关的字段信息整合在一个对象中,保持了三者之间的对应关系,方便了应用。
可以这样使用元数据获取字段名、字段的数据类型、字段类型的名称:
DatabaseMetaData dm = con.getMetaData();
ResultSet rs = dm.getColumns(catalog, null, tableName, null);
while (rs.next()) {
String name = rs.getString("COLUMN_NAME");//参数值可参考dm.getColumns(catalog, null, tableName, null)的帮助文档
fieldSet.add(lowerCase(name));
Field f = new Field();
f.setName(lowerCase(name));
String dataType = rs.getString("DATA_TYPE");
f.setSqlType(new Integer(dataType).intValue());//如:java.sql.Types.INTEGER
String type = rs.getString("TYPE_NAME");//如:BIGINT
f.setTypeName(lowerCase(type));
......
field_map.put(name.toLowerCase(), f);
}
但DatabaseMetaData元数据没有为我们提供字段数据的Java类型,字段数据的Java类型通过以下(ResultSetMetaData元数据)代码获取,这段代码使用了一个小技巧,查询主键值为null的记录,如果没有主键,则将第一个字段当做主键对待。以下这段代码是通过普通的查询,将字段对应的Java类型保存在Field对象中。
///给Field属性typeClassName赋值
String squeryFieldTypeClassName = "select * from " + tableName.toLowerCase() + " where " + table.getFields()[0] + " is null";
if (table.getKeys().length > 0) {
squeryFieldTypeClassName = "select * from " + tableName.toLowerCase() + " where " + table.getKeys()[0] + " is null";
}
Statement stmt0 = con.createStatement();
ResultSet rscname = stmt0.executeQuery(squeryFieldTypeClassName);
ResultSetMetaData rsmd = rscname.getMetaData();
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
String fieldNmae = rsmd.getColumnName(i);
field_map.get(fieldNmae.toLowerCase()).setTypeClassName(rsmd.getColumnClassName(i));//将字段的Java类型保存在Field对象的typeClassName中//通过mssql、mysql、derby
}
stmt0.close();
至此,
通过以上两段代码,我们把字段名、字段的SQL数据类型、SQL数据类型的名称、...以及该字段数据的Java类型的属性值整合到了Field对象中。这为下一步根据条件判断实现通用的PreparedStatement赋值方法奠定了基础。
JadePool作为简化JDBC编程工具,必须要根据字段数据的Java类型、字段的SQL数据类型等信息实现以下全部或者大部分常用的PreparedStatement的通配符所对应的方法。 以下列出所有的对应通配符的PreparedStatement的方法,涉及到共计约28个Java数据类型,将近50个方法:
java.util.Calendar calendar = new GregorianCalendar(2013, 3 - 1, 13);
Object value = new Object();
int index = 1;
int int_sqlType = java.sql.Types.INTEGER;//4
int int_scaleOrLength = 4;
int bytes_size = 256;
int int_length = 10;
long long_length = 10l;
String str_sqlTypeName = "LONG";
//以下是实现通配符所对应的示意性方法,涉及到共计约28个Java数据类型,将近50个方法。
pstmt.setArray(index, (java.sql.Array) value);
pstmt.setAsciiStream(index, (java.io.InputStream) value);
pstmt.setAsciiStream(index, (java.io.InputStream) value, int_length);
pstmt.setAsciiStream(index, (java.io.InputStream) value, long_length);
pstmt.setBigDecimal(index, (java.math.BigDecimal) value);
pstmt.setBinaryStream(index, (java.io.InputStream) value);
pstmt.setBinaryStream(index, (java.io.InputStream) value, int_length);
pstmt.setBinaryStream(index, (java.io.InputStream) value, long_length);
pstmt.setBlob(index, (java.sql.Blob) value);
pstmt.setBlob(index, (java.io.InputStream) value);
pstmt.setBlob(index, (java.io.InputStream) value, long_length);
pstmt.setBoolean(index, (Boolean) value);
pstmt.setByte(index, (byte) 30);
pstmt.setBytes(index, (byte[]) value);
pstmt.setCharacterStream(index, (java.io.Reader) value);
pstmt.setCharacterStream(index, (java.io.Reader) value, int_length);
pstmt.setCharacterStream(index, (java.io.Reader) value, long_length);
pstmt.setClob(index, (java.sql.Clob) value);
pstmt.setClob(index, (java.io.Reader) value);
pstmt.setClob(index, (java.io.Reader) value, long_length);
pstmt.setDate(index, (java.sql.Date) value);
pstmt.setDate(index, (java.sql.Date) value, calendar);
pstmt.setDouble(index, (java.lang.Double) value);
pstmt.setFloat(index, (java.lang.Float) value);
pstmt.setInt(index, (java.lang.Integer) value);
pstmt.setLong(index, (java.lang.Long) value);
pstmt.setNCharacterStream(index, (java.io.Reader) value);
pstmt.setNCharacterStream(index, (java.io.Reader) value, 123l);
pstmt.setNClob(index, (java.sql.NClob) value);
pstmt.setNClob(index, (java.io.Reader) value);
pstmt.setNClob(index, (java.io.Reader) value, 123l);
pstmt.setNString(index, (String) value);
pstmt.setNull(index, int_sqlType);
pstmt.setNull(index, int_sqlType, str_sqlTypeName);
pstmt.setObject(index, value);
pstmt.setObject(index, value, int_sqlType);
pstmt.setObject(index, value, int_sqlType, int_scaleOrLength);
pstmt.setRef(index, (java.sql.Ref) value);
pstmt.setRowId(index, (java.sql.RowId) value);
pstmt.setSQLXML(index, (java.sql.SQLXML) value);
pstmt.setShort(index, (java.lang.Short) value);
pstmt.setString(index, (java.lang.String) value);
pstmt.setTime(index, (java.sql.Time) value);
pstmt.setTimestamp(index, (java.sql.Timestamp) value);
pstmt.setTimestamp(index, (java.sql.Timestamp) value, calendar);
pstmt.setURL(index, (java.net.URL) value);
pstmt.setUnicodeStream(index, (java.io.InputStream) value, int_length);
jadepool-1.0-GBK版本没有完全实现上述通配符所对应的方法,但已经实现了以上常用的方法。JadePool在未来版中,将尽可能的实现上述更多直至全部的方法。