我的SQL更新有什么问题?JAVA

我的SQL更新有什么问题?JAVA,java,Java,这里是catch异常 com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:您有一个 SQL语法错误;检查与您的产品相对应的手册 MariaDB服务器版本,以便在“Select*FROM”附近使用正确的语法 表顺序按兰德=从表顺序按兰德-1'中选择* 第1行 请帮忙 我的SQL更新有什么问题 问题不在SQL更新中 查看错误消息中的SQL: private void subtractCredit(String accountType){

这里是catch异常

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:您有一个 SQL语法错误;检查与您的产品相对应的手册 MariaDB服务器版本,以便在“Select*FROM”附近使用正确的语法 表顺序按兰德=从表顺序按兰德-1'中选择* 第1行

请帮忙

我的SQL更新有什么问题

问题不在SQL更新中

查看错误消息中的SQL:

private void subtractCredit(String accountType){                      //subtract credit by 1
    String CREDITS = "UPDATE CUSTOMERS SET "+accountType+" = "+accountType+" -1, CREDITSUSED=CREDITSUSED+1 WHERE USERNAME='"+username+"'";
    try{
        ps=con.prepareStatement(CREDITS);
        ps.executeUpdate();
    }catch(Exception e){
        System.out.println(e);
    }
}

public String[] getAccount(String accountType){             //Generate a random account.
    accountType = "Select * FROM "+accountType+" ORDER BY RAND()";  
    String[] arr = new String[2];
    try{
        ps = con.prepareStatement(accountType);
        rs = ps.executeQuery();          
        if(rs.next()){
            arr[0] = rs.getString("USERNAME");
            arr[1] = rs.getString("PASSWORD");
            subtractCredit(accountType);
        }
    }catch(Exception e){
        System.out.println(e);
    }        
    return arr;
}    
你应该问自己的问题:

这看起来像更新SQL吗?不!! “选择”缺少什么?没有表名! 如果getAccount是导致此错误的方法,那么对于任何费心阅读代码的人来说,原因应该是显而易见的。accountType的值错误。如果代码完全如您所示,accountType必须包含字符串表。这是行不通的,因为表是SQL保留字。名为table的表是架构设计错误,因为它会导致SQL语法错误

另一种可能性是,代码实际上是这样说的:

        Select * FROM TABLE ORDER BY RAND()
如果是这样,问题是您调用了一个空字符串作为帐户类型的方法

当您解决了这个问题后,我希望您关注代码中的其他一些重要问题:

通过如下方式进行字符串碰撞来组装SQL:

    accountType = "Select * FROM TABLE " + 
            accountType + " ORDER BY RAND()";  
有潜在危险。如果accountType的值可以来自用户输入、HTTP请求参数或任何不受您控制的其他内容,则此代码容易受到SQL注入攻击

通常的解决方案是将常量SQL字符串与?占位符,然后使用PreparedStatement.setXxxx方法调用注入实际参数值。不幸的是,表名不能以这种方式注入

像您这样捕获异常是个坏主意。当然,它捕获了您预期的SQLException。问题是,它还捕获了一系列您可能没有预料到的其他异常。例如,如果try块中的代码有一个bug导致它抛出一个NullPointerException。。。你也会明白的

使用System.out.printlne输出诊断错误:

对于最终用户来说,异常消息是不透明的,是一种警报。 对于开发人员来说,您确实需要stacktrace。 将开发人员诊断发送到标准输出通常是个坏主意。使用日志框架。 您的错误恢复几乎肯定是错误的。如果SQL查询失败,则getAccount方法返回一个包含空字符串的字符串[2]。如果调用代码没有对此进行测试,那么当您尝试使用伪造的帐户详细信息时,很可能会得到NPE

正确的做法是很可能引发另一个异常,或者如果不想添加代码来处理这个堆栈,那么通过删除try-catch来允许SQLException传播。。。并在方法签名中声明异常

这是次要的,但大多数人认为更新方法参数的值是不好的风格。将新值分配给accountType时,您正在执行此操作。更好的样式是声明一个局部变量并使用它来保存SQL字符串


考虑从两个方法中提取的这一系列语句,但变量名称对应:

accountType = "Select * FROM "+accountType+" ORDER BY RAND()";

该错误确实发生在UPDATE语句中,但只有部分错误出现在消息中。上面的一系列语句解释了它是如何做到这一点的。特别是,考虑赋值给ActoType对后续语句的影响。

难道您不奇怪,在错误消息中的SQL片段确实被拧了起来,看起来不像您的方法产生的SQL吗?您肯定异常被抛出到那个代码中吗?例外情况是选择但发布的代码是UPDATEDid。如果您尝试使用标准调试器调试应用程序,那么如果您在搜索引擎上键入相同的错误,则会有许多问题指示。我建议先调试,然后从堆栈跟踪中搜索最具体的错误。@user3320018-您错过了最重要的第一步。1阅读错误消息和stacktrace的其余部分,2思考一下。谷歌搜索应该是调试时要做的事情的一个重要部分。您可以推广PreparedStatement的使用,但要将参数值串联到字符串中,而不是在查询中使用参数化参数,并使用PreparedStatementsetXyz。@LuiggiMendoza-不幸的是,您不能将表名作为参数插入。所以你的建议是有效的,对选择没有帮助。@StephenC我知道。我的意思是关于第二个查询,更新客户集+。。。
getAccount("TABLE");  // inferred

accountType = "Select * FROM "+accountType+" ORDER BY RAND()";  

String CREDITS = "UPDATE CUSTOMERS SET "+accountType+" = "+accountType
        + " -1, CREDITSUSED=CREDITSUSED+1 WHERE USERNAME='"+username+"'";
ps=con.prepareStatement(CREDITS);
ps.executeUpdate();