构建泛型prepareStatement时遇到麻烦:我有8个SQL表,它们都以相同的方式操作,因此我想构建一个唯一的管理器,它可以插入/选择8个表中的任何一个。
为此,每个表都有一个描述符,可以在插入时提供表的字段,名称和值数组。
在管理器中,要插入的预准备语句具有以下形式:
"INSERT INTO " + table_name + " VALUES (?)"
然后,我用
之类的东西填补空白myPreparedStatement.setString(1, values.getAllValues());
getAllValues()方法必须返回一个包含每个字段的字符串,例如“'This','Is',3,'example'”。 我对字符串和数字没有问题,但我无法在这些值中添加任何日期......
以2008年9月3日为例,我使用了以下格式: 2008-09-03, 03年8月9日, 080903, 03092018,但都失败了。 “yyMMdd”格式似乎是我在这里和那里看到的最佳选择,但我有错误:
"java.sql.SQLDataException: ORA-01843: not a valid month"
我不知道为什么......之前有人遇到过这个问题吗?
我知道这里有很多帖子讨论在数据库中插入日期,但它们都使用
preparedStatement.setDate(pos, Date);
声明,我不能这样做,因为日期在我的所有表格中都不是相同的位置。
编辑:
正如评论中所述,这是一个简单的样本,可以重现我正在尝试做的事情。如果你想再现,我让你处理连接和数据库设置:
public class Sample {
public void saveAll() throws ServiceException {
Connection c = null;
PreparedStatement ps = null;
String sql = "INSERT INTO " + getTableName() +" VALUES (?)";
try {
c = getConnection();
c.setAutoCommit(false);
batch = c.prepareStatement(sql);
batch.setString(getAllFieldValues());
int res = batch.executeUpdate();
c.commit();
} catch (BatchUpdateException b) {
throw new ServiceException("Erreur lors de l'exécution du batch", b);
} catch (SQLException s) {
throw new ServiceException("Impossible de sauvegarder les beans en base.", s);
} finally {
getManager().close(batch);
freeConnection(c);
}
}
public String getAllFieldValues() {
return "'Hello', 'World', 42, '171228'";
}
public String getTableName() {
return "myTableName";
}
}
答案 0 :(得分:1)
JDBC中没有generic preparedStatement
这样的东西。要在表T中插入四列,必须使用
INSERT into T (col1,col2,col3,col4) values (?,?,?,?)
你可能省略第一个包含列名的列表,但这是一个不良做法,因为您信任可能会更改的表的实际列。
仅使用
INSERT into T values (?,?,?,?)
正常工作,直到有人通过添加或删除列来修改表,然后才会失败。
所有绑定变量必须使用setXXX方法设置为额外的,并且列的相应类型和索引以1开头。
stmt.setInt(1,100)
stmt.setString(2,'xxx')
答案 1 :(得分:0)
如果我能正确理解你的问题。为了在预准备语句中动态放置日期值,您可以覆盖setString()方法以使您的自定义代码检查日期值,否则。
或者更确切地说,如果您还可以使用本地方法来检查来的字符串是否为格式化日期。
为此您可以简单地传递Date String并附加一些前缀,以便您可以在自定义setString()方法中进行检查。
setString(String string, int position){
if(string.contains("SPECIFIC_PREFIX_CONSTANT")){
//batch.setDate(position, string.substring("REMOVE PREFIX AND ATTACH"));
}else{
//batch.setString(position, string);
}
}
答案 2 :(得分:0)
好的,我设法让我的东西工作,非常感谢你们所有人! 如果有人在我的问题上结束,我会回顾我现在的代码,这有效:)
因此,如前所述,我们有一个管理器与数据库交互,并且不知道他与之交互的表格。
以下是此经理的保存方法的代码:
public void saveAll(AbstractBeanClass[] values, String refSelected) {
// connexion setup
Connection c = null;
PreparedStatement batch = null;
// fetch table's fields, to prepare the placeholders
String fields = values[0].getAllFields();
String sql = "INSERT INTO " + values[0].getTableName() + " (" + fields + ") VALUES (";
StringBuffer places = new StringBuffer();
int [] res = null;
// Start at 1 to have one field left, to end the parenthesis
for(int i = 1; i < values[0].getNumberOfFields(); i++) {
places.append("?, ");
}
// last field
places.append("?)");
sql = sql.concat(places.toString()); // We now have a full (?, ..., ?)
try {
c = getConnection();
c.setAutoCommit(false);
batch = c.prepareStatement(sql);
// Filling the batch
int j = 1;
for(AbstractBeanClass bean : values) {
int i = 1;
for(String type : bean.getAllTypes()) {
switch(type) {
case "int" : {
batch.setInt(i, (int) bean.getOrderedValue(i));
}
break;
case "String" : {
batch.setString(i, (String)bean.getOrderedValue(i));
}
break;
case "Date" : {
batch.setDate(i, (java.sql.Date) bean.getOrderedValue(i));
}
break;
}
i++;
}
batch.addBatch();
// In case of numerous insertions, some Databases don't allow more than 1000 inserts at a time
if(j%1000 == 0) {
res = batch.executeBatch();
for(int k : res) {
if(k == Statement.EXECUTE_FAILED) {
getManager().close(batch);
freeConnection(c);
throw new RuntimeException("Error while inserting values.");
}
}
}
j++;
}
// last execution
res = batch.executeBatch();
for(int i : res) {
if(i == Statement.EXECUTE_FAILED) {
getManager().close(batch);
freeConnection(c);
throw new RuntimeException("Error while inserting values in database.");
}
}
c.commit();
logger.debug("Insertion succeeded, we inserted " + j + " lines.");
} catch (BatchUpdateException b) {
throw new RuntimeException("Error in batch : ", b);
} catch (SQLException s) {
throw new RuntimeException("Error : we couldn't save the values : ", s);
} finally {
getManager().close(batch);
freeConnection(c);
}
}
所以这是程序的主要部分,但它需要表描述符。为了简单起见,我创建了一个抽象类来声明我需要的方法,并且所有表描述符都扩展了这个类,这里是声明:
package com.fr.sncf.fret.boctarification.domaine.referentiel;
import java.io.Serializable;
import java.text.SimpleDateFormat;
public abstract class DaoGenericReferentielBean implements Serializable {
private static final long serialVersionUID = 1L;
protected String allFields;
// the date Format used to insert the dates in base
protected final SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd");
public DaoGenericReferentielBean() {
// empty constructor
}
/**
* Return all columns' names, ordered according to database's order
* @return
*/
public String getAllFields() {
return this.allFields;
}
/**
* Returns all values ordered by columns' order
* @return String
*/
public abstract String getAllFieldsValues();
/**
* @return the table name
*/
public abstract String getTableName();
/**
* @return the number of field in this table
*/
public abstract int getNumberOfFields();
/**
* Returns the ordered list of column's type
*/
public abstract String[] getAllTypes();
/**
* Return the value corresponding to the given index
* Values are treated here according to the database's columns order
* @param index the column's number
* @return an Object, either an int, or a String, or a Date
*/
public abstract Object getOrderedValue(int index);
}
现在你只需要根据这个模型描述你的桌子,希望它有所帮助!