【问题标题】:How to use Prepared Statement for Transaction?如何使用 Prepared Statement 进行交易?
【发布时间】:2016-10-29 08:53:34
【问题描述】:

我想在事务的帮助下在两个表中插入数据。我的查询在我的 SQL 中正常工作但我不知道如何在 java 代码上处理它,请帮忙。 我的代码如下所示

 private Boolean executeInsertQuery(Connection conn, String schoolID, String branchID, String studentName, String parentName, String emailId, String password, String className, String section, int age, String dob, String scholarNo, String address, String contactNo, int rollType) throws SQLException {
        Boolean isSuccess = false;
        String statement = "START TRANSACTION;\n" +
                "INSERT INTO child_details (SCHOLAR_NUMBER, SCHOOL_ID,BRANCH_ID,CHILD_NAME,ENROLLED_CLASS," +
                "CHILD_SECTION,CHILD_AGE,CHILD_DOB) VALUES (?,?,?,?,?,?,?,?);\n" +
                "INSERT INTO parents_details (EMAIL_ID, BRANCH_ID,SCHOOL_ID,CHILD_NAME,SCHOLAR_NUMBER,PARENT_CONTACT_NUMBER," +
                "PASSWORD,ROLE_TYPE,PARENT_NAME,ADDRESS) VALUES (?,?,?,?,?,?,?,?,?,?);\n" +
                "COMMIT";

        PreparedStatement stmt = null;
        PreparedStatement statement1 = null;
        try {
            stmt = conn.prepareStatement(statement);
            stmt.setString(1, scholarNo);
            stmt.setString(2, schoolID);
            stmt.setString(3, branchID);
            stmt.setString(4, studentName);
            stmt.setString(5, className);
            stmt.setString(6, section);
            stmt.setInt(7, age);
            stmt.setString(8, dob);
            stmt.setString(9,emailId);
            stmt.setString(10, branchID);
            stmt.setString(11, schoolID);
            stmt.setString(12, studentName);
            stmt.setString(13, scholarNo);
            stmt.setString(14, contactNo);
            stmt.setString(15, password);
            stmt.setInt(16, rollType);
            stmt.setString(17, parentName);
            stmt.setString(18, address);
            int count = stmt.executeUpdate();
         //  int count2 = statement1.executeUpdate();

            if (count > 0) {
                isSuccess = true;
            } else {
                isSuccess = false;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                stmt.close();
                conn.close();
            }
        }
        return isSuccess;
    }


    private Connection getConnection() {

        String url;
        Connection conn = null;
        try {
            if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production) {
                Class.forName("com.mysql.jdbc.GoogleDriver");
                url = "jdbc:google:mysql://############?#######";
            } else {
                Class.forName("com.mysql.jdbc.Driver");
                url = "jdbc:mysql://localhost:3306/#######";
            }
            conn = DriverManager.getConnection(url, "root", "******");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
}

这种情况下如何使用Prepared语句?

【问题讨论】:

  • 我强烈推荐以下内容:a)去掉这些行末尾的 \n 字符 b)在数据库中创建一个可调用语句,并使用准备好的调用调用它 c)如果准备好的语句是唯一的方法,如果你真的需要的话,将它们分开并添加一个批处理
  • 谢谢angerip,我会试试
  • 我正在修改你的一些代码来告诉你我的意思
  • 是的,只需将语句编写为插入,然后使用 addBatch 代替。

标签: java android mysql


【解决方案1】:

提交/回滚事务遵循以下模式:

conn.setAutocommit(false); // No commit per statement

try (PreparedStatement stmt1 = conn.prepareSteatement(...)) { // Automatic close.
    ...
    try (PreparedStatement stmt2 = ... )) {
        ...
        conn.commit();
    }
} catch (SQLException ex) {
    conn.rollback();
}

Try-with-resources 是一种奇怪的语法,它简化了原本需要的关闭代码。

可能需要自动生成的密钥 (getGeneratedKeys) 从第一个语句中获取并插入到第二个语句中 - 例如如果一个具有 AUTOINCR 字段。搜索将给出示例代码。

【讨论】:

    【解决方案2】:

    这就是我要做的。根据我过去的经验,对于多个插入语句,您可以使用批处理、多个准备好的调用语句或可调用语句。使用最后一个想法,您的代码如下所示:

    private Boolean executeInsertQuery(Connection conn, String schoolID, String branchID,
                String studentName, String parentName, String emailId,
                String password, String className, String section,
                int age, String dob, String scholarNo, String address,
                String contactNo, int rollType) throws SQLException {
        boolean isSuccess = false;
        String getDBUSERByUserIdSql = "{call insertChildAndParentDetails(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)}";
        try (CallableStatement callableStatement = conn.prepareCall(getDBUSERByUserIdSql)) {
            callableStatement.setString(1, scholarNo);
            callableStatement.setString(2, schoolID);
            callableStatement.setString(3, branchID);
            callableStatement.setString(4, studentName);
            callableStatement.setString(5, className);
            callableStatement.setString(6, section);
            callableStatement.setInt(7, age);
            callableStatement.setString(8, dob);
            callableStatement.setString(9, emailId);
            callableStatement.setString(10, branchID);
            callableStatement.setString(11, schoolID);
            callableStatement.setString(12, studentName);
            callableStatement.setString(13, scholarNo);
            callableStatement.setString(14, contactNo);
            callableStatement.setString(15, password);
            callableStatement.setInt(16, rollType);
            callableStatement.setString(17, parentName);
            callableStatement.setString(18, address);
            isSuccess = (callableStatement.executeUpdate() > 0);
        } catch (SQLException e) {
            System.out.println("## we have an exception" + e.getMessage());
        }
        return isSuccess;
    }
    

    在您的数据库脚本中,创建一个在上面的 java 代码中引用的存储过程。这是一个使用 oracle DB 的示例(注意:我不知道您的数据库结构,但根据需要添加/删除/更改参数):

    CREATE OR REPLACE PROCEDURE insertChildAndParentDetails(
        p_schoolID IN childTable.SCHOOL_ID%TYPE,
        p_studentName IN parentTable.STUDENTNAME%TYPE,
        p_parentName IN childTable.PARENTNAME%TYPE,
        p_emailId IN childTable.EMAILID%TYPE)
    IS
    BEGIN
    
      INSERT INTO childTable ("SCHOOL_ID", "PARENTNAME", "EMAILID") 
      VALUES (p_schoolID, p_parentName,p_emailId);
    
      INSERT INTO parentTable ("STUDENTNAME") 
      VALUES (p_studentName)
    
      COMMIT;
    
    END;
    /
    

    如果您真的想使用多个准备好的语句,请将您的方法分成两个不同的操作并从另一个方法中调用它们,尽管我个人会远离:

    public void insertData() {
        insertChildData();
        insertParentData();
    }
    

    不过,只要确保您在此处正确执行逻辑,以确保在一种方法中导致异常的事务与另一种方法同步。

    【讨论】:

    • 查询中不需要更改??
    • 按原样放置查询
    • @shailendrakushwah 不确定我是否理解您在评论中的问题。你能澄清什么让你感到困惑吗?
    • @shailendrakushwah 您可以拥有任意数量的表,一个存储过程可以插入多个表。我会用一个示例更新我的答案
    • @shailendrakushwah 你去,更新的答案。只需添加更多参数,更改具体的表名和变量等。
    猜你喜欢
    • 1970-01-01
    • 2014-11-04
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 2022-10-24
    相关资源
    最近更新 更多