我很好奇,我们可以动态输入参数吗?例如,我有一个像这样的对象:
class Fields {
private Integer id;
private String name;
public Fields(Integer id, String name) {
this.id = id;
this.name = name;
}
//Getter - setter here
}
现在,我准备声明:
public void main() {
PreparedStatement ps = conn.PrepareStatement("SELECT * FROM table WHERE id = ? AND name = ?");`
}
然后我设置
Fields param = new Fields(2, "xxx");
嗯..叫我懒,怎样才能把参数发送到PrepareStatement,如
ps.setParameters(param)
或者也许:
ps.setParameters(param.getAsArray())
为了更好地说明我的观点,我想做一些类似的事情:
for (Fields f: fieldList) {
sql += f + " = ?";
}
请原谅我的遗失" AND" /" OR"上述代码的运算符。我的最终目标是通过仅填充部分字段来传递实体类,从而创建整个字段和相应参数。然后代码将跳过空字段并将填充的字段作为参数。
好吧,只是为了好奇。
谢谢
答案 0 :(得分:1)
您可以直接将值放在参数中,而不使用 Field 类。
ps.setParameters(2, "xxx");
试试这些,希望它对您有用。
Field field1 = new Field(0,1,"id");
Field field2 = new Field(1,"Nathan","name");
List<Field> fields = new ArrayList<>();
fields.add(field1);
fields.add(field2);
StringBuilder strBuilder = new StringBuilder("SELECT * FROM table WHERE ");
// Dynamically Construct your SQL Query String
for(int i = 0 ; i < fields.size() ; i++) {
String strTemp = " AND ";
String strTempEquals = " = ?";
if(fields.size()-1 == i) {
strTemp = ";";
}
strBuilder.append(fields.get(i).getColumnName());
strBuilder.append(strTempEquals);
strBuilder.append(strTemp);
}
PreparedStatement ps = conn.PrepareStatement(strBuilder);
// Dynamically pass your values from your Field class to the parameters of PreparedStatement
for (Field tempField : fields) {
ps.setParameter(tempField.getIndex(),tempField.getValue());
}
我在字段类中进行了一些更改。
class Field {
private Integer index;
private Object value;
private String columnName;
// Constructor
//Getters and Setter
}
答案 1 :(得分:1)
尝试使用像这样的参数化构造函数我希望这是你需要的
class Fields {
private Integer id;
private String name;
public Fields(int id,String name)
{
this.id=id;
this.name=name;
setParameter();
}
public void setParameter()
{
PreparedStatement ps = conn.PrepareStatement("SELECT * FROM table WHERE id = ? AND name = ?");
ps.setInt(1,id);
ps.setString(2,name);
}
}
答案 2 :(得分:1)
好的..这是一个非常粗糙的解决方案。我仍然不喜欢这样一个事实,即我必须重复所有字段两次以获得字段的字符串或其他类型,但随时可以进一步完善它,因为这仍然非常粗糙。此外,您需要在ps.setObject()failafe之前扩展下面的ps.setSomething()参数。您还需要在没有任何条件的情况下预测查询,例如跳过那些标准对象扫描并直接执行。但我希望你明白这一点。
public static String addPrefix(String prefix, String field) {
return new StringBuilder(prefix)
.append(Character.toUpperCase(field.charAt(0)))
.append(field.substring(1))
.toString();
}
public static <T> List<T> query(Connection conn, T criteria, String operator) throws SQLException {
List<T> list = null;
Class<?> targetClass = criteria.getClass();
if (targetClass.getAnnotation(Table.class) == null) throw new SQLException("ERROR: Table not defined at entity class " + targetClass.getName());
StringBuilder SQL = new StringBuilder("SELECT * FROM ").append(targetClass.getAnnotation(Table.class).name());
List<Object> parameters = new ArrayList<>();
try {
Field[] fields = targetClass.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(Column.class) == null) continue;
Method m = targetClass.getMethod(addPrefix("get", field.getName()).toString());
Object o = m.invoke(criteria);
if (o == null) continue;
if (parameters.isEmpty()) SQL.append(" WHERE"); else SQL.append(operator);
SQL.append(" ").append(field.getAnnotation(Column.class).name()).append(" = ?");
parameters.add(o);
}
try (Connection connection = IwiPrivate.getInstance().getConnection()) {
try (PreparedStatement ps = connection.prepareStatement(SQL.toString())) {
Integer x = 1;
for (Field field : fields) {
String type = field.getType().getName();
Method m = targetClass.getMethod(addPrefix("get", field.getName()));
Object o = m.invoke(criteria);
if (o == null) continue;
if (type == "java.lang.String") ps.setString(x, (String) parameters.get(x));
else if (type == "java.lang.Integer") ps.setInt(x, (Integer) parameters.get(x));
else ps.setObject(x, parameters.get(x)); //Put more set traps here.
}
try (ResultSet rs = ps.executeQuery();) {
while (rs.next())
list.add((T) Database.mapSingle(rs, targetClass));
}
}
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(QueryExperiment.class.getName()).log(Level.SEVERE, null, ex);
}
return list;
}
现在,要使用它,只需像这样创建实体对象
@Table(name = "testTable")
public class Entity {
@Column(name = "id")
private Integer id;
@Column(name = "name")
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
然后将其作为标准
public void testQuery() {
Entity criteria = new Entity();
criteria.setId(7777);
try (Connection connection = yourDatabase.getConnection()) {
List<Entity> assets = QueryTest.query(connection, criteria, "AND");
} catch (SQLException ex) {
Logger.getLogger(IwiPrivateTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
它将创建一个SQL:
SELECT * FROM testTable WHERE id = ?
并使用setInt
如果你想避免使用ORM并创建简单的查询,我相信这种方法可以正常工作。
答案 3 :(得分:0)
PreparedStatement有一个setObject(int, java.lang.Object)方法。您可以在接受字段数组/列表的类或方法中使用它,并将名称附加到sql并使用setObject方法设置参数。
请记住,此方法极易受到SQL注入攻击,因此请谨慎使用。
答案 4 :(得分:0)
在Java代码中,使用spring jdbc也可以实现这一点。
以下示例代码可供参考:目前,我们正在循环更新100个参数。如果我们知道参数的数量,那么我们就这样做。 如果您的条件是具有100个参数的表,则可以按照以下方法进行一些修改。
public Class MappingDTO{
private String attribute1;
private String attribute2;
private String attribute3;
private String attribute4;
.
.
.
.
.
private String attribute100;
public getAttribute1(){
return attribute1;
}
.
.
.
public getAttribute100(){
return attribute1;
}
}
updated=jdbcTemplate.batchUpdate("our query", new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int index) throws SQLException {
MappingDTO mappingDTO = mappingDTOList.get(index);
Class<?> tClass = mappingDTO.getClass();
int i=1;
for (i = 1; i <= 100; i++) { //100 max attributes can be updated //dynamic preparestatemetn setter
Method method=null;
try {
method = tClass.getMethod("getAttribute"+(i), new Class[] {});
} catch (NoSuchMethodException e) {
LOG.error("Exception thrown | uploadStatementTemporaryTableUpdate | No such method exception | while trying to find methods", e);
} catch (SecurityException e) {
LOG.error("Exception thrown | uploadStatementTemporaryTableUpdate |Security Exception | while trying to find methods", e);
}
String str1=null;
try {
str1 = (String)method.invoke(mappingDTO, new Object[] {});
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
} catch (InvocationTargetException e) {
}
ps.setString(i, str1);
}
}
@Override
public int getBatchSize() {
// TODO Auto-generated method stub
return mappingDTOList.size();
}
});