为什么我的 PreparedStatement SQL 查询不起作用?仅适用于硬编码字符串

Why doesn't my PreparedStatement SQL query work? Only works with a hardcoded string

我正在尝试使用 PreparedStatement 生成 SQL 查询。当我使用硬编码 String 或串联时它工作得很好,但我完全不知道为什么它在使用 PreparedStatement.

时不起作用
public Customer createCustomer(Customer customer) {

     //Ommitted code

     int result = statement.executeUpdate(createPreparedStatementQuery(customer), Statement.RETURN_GENERATED_KEYS)
);

使用 PreparedStatement 创建查询

public static String createPreparedStatementQuery(Customer customer){
    String query = "INSERT INTO customers(Customer_Name, Address, Postal_Code, Phone, Created_By, Last_Updated_By, Division_ID) " +
            "VALUES (?, ?, ?, ?, ?, ?, (SELECT Division_ID FROM first_level_divisions WHERE division = ?));";
    try {
        PreparedStatement statement = ConnectionManager.getConnection().prepareStatement(query);
        statement.setString(1, customer.getName());
        statement.setString(2, customer.getAddress());
        statement.setString(3, customer.getPostalCode());
        statement.setString(4, customer.getPhoneNumber());
        statement.setString(5, customer.getCreatedBy());
        statement.setString(6, customer.getLastUpdatedBy());
        statement.setString(7, customer.getDivision());
        
        System.out.println(statement); //Successfully returns the query
        
        return statement.toString();
    }catch (SQLException e){
        System.out.println(e.getMessage());
        return null;
    }
}

这给出了错误:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'com.mysql.cj.jdbc.ClientPreparedStatement: INSERT INTO customers(Customer_Name, ' at line 1

但是,对于通过连接或硬编码创建的字符串,查询执行得非常好。

public static String createConcatQuery(Customer customer) {
    String query =  "INSERT INTO customers(Customer_Name, Address, Postal_Code, Phone, Created_By, Last_Updated_By, Division_ID) " +
            "VALUES ('"
            + customer.getName() + "', '"
            + customer.getAddress() + "', '"
            + customer.getPostalCode() + "', '"
            + customer.getPhoneNumber() + "', '"
            + customer.getCreatedBy() + "', '"
            + customer.getLastUpdatedBy() + "', "
            + "(SELECT Division_ID FROM first_level_divisions WHERE division = '"
            + customer.getDivision() + "'));";
    System.out.println(query);
    return query;
}
String hardCodedQuery = "INSERT INTO customers(Customer_Name, Address, Postal_Code, Phone, Created_By, Last_Updated_By, 

Division_ID) VALUES ('ee', 'ee', 'ee', 'ee', 'test', 'test', (SELECT Division_ID FROM 

first_level_divisions WHERE division = 'Newfoundland and Labrador'));";

我已经复制并粘贴了从日志中输出的两个查询。 concat 查询和 preparedstatement 查询都 return 相同的 String:

我完全不明白为什么它此时不起作用。有人可以帮我弄清楚我在使用 PreparedStatement 时做错了什么吗?

完整的 StackTrace:

java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'com.mysql.cj.jdbc.ClientPreparedStatement: INSERT INTO customers(Customer_Name, ' at line 1
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
    at com.mysql.cj.jdbc.StatementImpl.executeUpdateInternal(StatementImpl.java:1337)
    at com.mysql.cj.jdbc.StatementImpl.executeLargeUpdate(StatementImpl.java:2117)
    at com.mysql.cj.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1342)
    at sample.data.CustomerRepository.createCustomer(CustomerRepository.java:144)
    at sample.controller.CustomerController.createCustomer(CustomerController.java:165)
    at sample.controller.CustomerController.confirmAlert(CustomerController.java:153)
    at sample.controller.CustomerController.onBtnSaveClick(CustomerController.java:146)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8411)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access00(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent(GlassViewEventHandler.java:432)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:410)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)

您必须在 createPreparedStatementQuery() 函数中调用 statement.executeQuery()。或者您可以 return 来自 createPreparedStatementQuery() 函数的语句对象并在 createCustomer().

中调用 statement.executeQuery()

N.B。您可以根据需要使用 statement.executeUpdate()statement.executeQuery()

您的 createPreparedStatementQuery() 基本上是在 return 原始查询中使用 ?将其标记为 createCustomer() 中的语句对象。外面的语句对象不知道你在里面的语句对象中设置的参数。