首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >要求用户从支票账户取钱,并将其转移到储蓄账户-跟踪。

要求用户从支票账户取钱,并将其转移到储蓄账户-跟踪。
EN

Code Review用户
提问于 2014-06-03 15:57:52
回答 2查看 351关注 0票数 3

我对此做了一些修改:

要求用户从支票账户取钱并将其转移到储蓄账户。

我所做的改变是:

  • 改进方法和变量的名称,以更好地描述它们所做的事情
  • 将db凭据传递给属性文件。
  • 设置不同的db用户(从“root”到“test_user”)
  • 添加/删除了几个函数/变量,以及其他一些小更改(复制/粘贴问题、间距等)

对于如何在我的MainApplication类中处理/调用db变量,我仍然犹豫不决。您是否认为initializeDatabaseVariables方法是可以接受的,还是更愿意继续创建一个不同的类来处理数据库连接(初始化、连接、关闭)?

下面是修改后的源代码。如果还有什么值得修改的地方,请不要犹豫,告诉我。

config.properties

代码语言:javascript
复制
#Mon Jun 02 21:37:18 CEST 2014
port=3306
hostname=localhost
password=
database=jdbc_example
username=test_user

MainApplication类

代码语言:javascript
复制
package com.jdbcbank;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;

public class MainApplication {

    // Database access
    static String DB_NAME;
    static String HOSTNAME;
    static String DB_PORT;
    static String DB_URL;

    // Database credentials
    static String DB_USR;
    static String DB_PASS;

    // Connection variables
    static Connection conn = null;
    static Statement statement = null;
    static ResultSet result = null;
    static PreparedStatement pStatement = null;

    public static void main(String[] args) throws SQLException {

        initializeDatabaseVariables();

        int testUserId = 1;
        int accountBalances[];

        try {

            // Connect to database
            MainApplication.connectToDb();

            // Get current balance
            BankAccount bankAccount = new BankAccount();

            accountBalances = bankAccount.getAccountBalances(testUserId);
            System.out.println("---------------");
            System.out.println("Current balance ");
            System.out.println("---------------");
            System.out.println("Checking Account: " + accountBalances[0]+ " USD");              
            System.out.println("Savings Account: " + accountBalances[1]+ " USD\n");

            checkIfValueIsNegative(accountBalances[0]); 

            System.out
                    .print("Enter the amount (in USD) you wish to move to your savings account: ");

            // Run transaction
            Scanner transferAmountScanner = new Scanner(System.in);     
            int transferAmount = transferAmountScanner.nextInt();
            transferAmountScanner.close();  

            checkIfValueIsOutOfRange(testUserId, transferAmount);
            checkIfValueIsNegative(transferAmount);     
            bankAccount.moveAmountFromCheckingToSavings(transferAmount);

            // Get new balance
            accountBalances = bankAccount.getAccountBalances(testUserId);
            System.out.println();
            System.out.println("-----------");
            System.out.println("New balance ");
            System.out.println("-----------");
            System.out.println("Checking Account: " + accountBalances[0]+ " USD");
            System.out.println("Savings Account: " + accountBalances[1]+ " USD\n");
            System.out.println("Thank you.");

        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        } finally {
            // Close all connections
            close(conn, statement, pStatement, result);
        }

    }

    public static void initializeDatabaseVariables() {

        Properties prop = new Properties();
        InputStream input = null;

        try {

            input = new FileInputStream("config.properties");

            // Load properties file
            prop.load(input);

            // Initialize database variables
            DB_NAME = prop.getProperty("database");
            HOSTNAME = prop.getProperty("hostname");
            DB_PORT = prop.getProperty("port");
            DB_USR = prop.getProperty("username");
            DB_PASS = prop.getProperty("password");
            DB_URL = "jdbc:mysql://" + HOSTNAME + ":" + DB_PORT + "/" + DB_NAME;

        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    System.out.println("Error: " + e.getMessage());
                }
            }
        }
    }

    public static void checkIfValueIsNegative(int value) {

        if (value < 0) {
            throw new IllegalArgumentException(
                    "Oops! Negative values not allowed.");
        }

    }

    public static void checkIfValueIsOutOfRange(int testUserId,
            int transferAmount) throws SQLException {

        int checkingBalance = new BankAccount().getAccountBalances(testUserId)[0];

        if (transferAmount > checkingBalance) {
            throw new IllegalArgumentException("Oops! Insuficient funds to transfer.");
        }
    }

    public static void connectToDb() {

        try {
            // Load driver
            Class.forName("com.mysql.jdbc.Driver");

            // Set connection
            conn = DriverManager.getConnection(DB_URL, DB_USR, DB_PASS);
            conn.setAutoCommit(false);
            statement = conn.createStatement();

        } catch (ClassNotFoundException e) {
            System.out.println("Error: " + e.getMessage());
        } catch (SQLException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

    public static void close(Connection conn, Statement statement,
            PreparedStatement pStatement, ResultSet result) {
        if (conn != null)
            try {
                conn.close();
            } catch (SQLException e) {
                System.out.println("Error: " + e.getMessage());
            }
        if (statement != null)
            try {
                statement.close();
            } catch (SQLException e) {
                System.out.println("Error: " + e.getMessage());
            }
        if (pStatement != null)
            try {
                pStatement.close();
            } catch (SQLException e) {
                System.out.println("Error: " + e.getMessage());
            }
        if (result != null)
            try {
                result.close();
            } catch (SQLException e) {
                System.out.println("Error: " + e.getMessage());
            }
    }

}

BankAccount类

代码语言:javascript
复制
package com.jdbcbank;

import java.sql.*;

public class BankAccount {

    public void moveAmountFromCheckingToSavings(int transferAmount) throws SQLException {

        try {
            // Withdraw from checking and deposit into saving
            withdrawFromChecking(MainApplication.statement, transferAmount, 1);
            depositIntoSaving(MainApplication.statement, transferAmount, 1);

            // Execute batch and commit if no issues are found
            MainApplication.statement.executeBatch();
            MainApplication.conn.commit();

            // Print message
            System.out.println("Successful transaction!");

        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
            MainApplication.conn.rollback();
        }
    }

    public int[] getAccountBalances(int id) throws SQLException {

        // Array to be returned
        int balance[] = new int[2];

        // Get results
        String query = "SELECT * from bank_account WHERE id = " + id;
        MainApplication.result = MainApplication.statement.executeQuery(query);

        while (MainApplication.result.next()) {
            // Retrieve by column name
            balance[0] = MainApplication.result.getInt("checking_balance");
            balance[1] = MainApplication.result.getInt("saving_balance");
        }
        return balance;

    }

    public static void withdrawFromChecking(Statement statement, int amount,
            int id) throws SQLException {

        statement
                .addBatch("UPDATE bank_account SET checking_balance = checking_balance - "
                        + amount + " WHERE id = " + id);

    }

    public static void depositIntoSaving(Statement statement, int amount, int id)
            throws SQLException {

        statement
                .addBatch("UPDATE bank_account SET saving_balance = saving_balance + "
                        + amount + " WHERE id = " + id);
    }

}
EN

回答 2

Code Review用户

发布于 2014-06-04 02:02:55

一般性建议

  • 想办法缩短你的方法。
  • 干(不要重复)。

具体点

  • 结合以上各点:将您的printlns系列提取为一种新的BankAccount.displayBalances()方法。这还将使您能够摆脱accountBalances变量。
  • 你的全局变量太多了。保留Connection一段时间,但是所有其他的都可以是本地的,范围很小。创建新的Statements或ResultSets没有任何开销,当您重用这样的变量时,bug很容易出现。
  • 看看是否可以将主方法简化为一个简短的命令列表,必要时参数从一个传递到下一个。像"connectToDb“、"loadAccount”、"transferUserSpecifiedAmount“和"displayBalances”这样的东西就足够了。您可以为诸如new ScannercheckIfValueIsOutOfRangeprintln这样的东西找到更好的地方。
  • 在您的主要方法中不要有业务逻辑。您可以将逻辑移动到新方法boolean validateMoveAmountFromCheckingToSavings(int),或者如果业务逻辑禁止,则让方法moveAmountFromCheckingToSavings抛出异常。
  • 关于initializeDatabaseVariables的问题:最好避免使用全局变量。也许可以创建一个Properties MainApplication.loadProperties()方法,并在main方法中保留返回的属性。更改connectToDb()以将该Properties作为参数。您甚至可能希望创建String MainApplication.createConnectionString(Properties),这是非常自我记录的。
  • 阅读close ConnectionStatementPreparedStatementResultSet中的所有方法。你可能会发现你不需要关闭所有的东西。
票数 3
EN

Code Review用户

发布于 2014-06-04 07:48:48

我认为重新设计一下你的阶级等级会带来好处的。你所拥有的实体似乎:

  • 包含帐户信息的数据库。
  • 源帐户(存储在数据库中)
  • 目标帐户(也存储在数据库中)

基于此,您将创建主应用程序的一个实例和BankAccount (源和目标帐户)的两个实例。

主应用程序将创建一个数据库连接,然后为源和目标(或检查/保存任何内容)构造两个帐户(同级)。BankAccount的构造函数将把数据库连接作为参数。所以主要的应用程序需要做的就是:

  • 启动数据库事务
  • 从源帐户转移到目标帐户。这应该很简单,就像destinationAccount.deposit(sourceAccount.withdraw(amount));资金不足时应该抛出一个异常一样--这需要捕获并执行数据库回滚。
  • 提交数据库事务

好的类层次结构的一个标志是完全没有静态方法--也就是说,每个动作都对一个对象起作用。当前的设计在主应用程序中有属于BankAccount类的方法。例如,depositIntoSaving(数量)应该是savingsAccount.deposit(数量)

此外,我不喜欢检查异常(例如,SQLException)。我倾向于从源代码中捕捉到这些信息,并将它们转化为RunTimeException实例,这些实例不会在代码中出现不必要的抛出声明--但这是个人偏好,而且我可能要挑起一场宗教战争。

祝好运!

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/52367

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档