1

我正在创建一个具有多个输入表单的应用程序,其中大约 22 个。我想创建一个将表单数据保存到数据库中的类。表单只需通过 getter 获取文本字段值并通过调用数据库类构造函数保存值。

The huddle:
数据库类使用准备好的语句。我在传递将值绑定到参数的部分时遇到问题,该部分看起来像:

tmt.setInt(1, 35);  // This would set a value such as age
stmt.setInt(2, 'Another value');

任何人都可以对如何解决这个问题有任何想法吗?

构造函数中的变量意味着: String data:各种文本字段值 String table:数据库中将存储值的特定表 String sql:将值绑定到参数的部分(我在上面的“The huddle”中提到过)

这是数据库类:

// STEP 1. Import required packages
import java.sql.*;
import java.util.List;

public class UpdateAndQuerry {

    public static String data;
    public static String table;
    public static String sql;

    public UpdateAndQuerry (String data, String table, String sql) {
        this.data = data;
        this.table = table;
        this.sql = sql;
    }

    // JDBC driver name and database URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost/EMP";

    //  Database credentials
    static final String USER = "username";
    static final String PASS = "password";

    public static void main (String[] args) {
        Connection conn = null;
        PreparedStatement stmt = null;

        try {
            // STEP 2: Register JDBC driver
            Class.forName("com.mysql.jdbc.Driver");

            // STEP 3: Open a connection
            System.out.println("Connecting to database...");
            conn = DriverManager.getConnection(DB_URL,USER,PASS);

            // STEP 4: Execute a query
            System.out.println("Creating statement...");
            // String sql = "UPDATE Employees set age = ? WHERE id = ?";

            stmt = conn.prepareStatement(sql);

            // Bind values into the parameters.
            stmt.setInt(1, 35);  // This would set age
            stmt.setInt(2, 102); // This would set ID

            // Let us update age of the record with ID = 102;
            int rows = stmt.executeUpdate();
            System.out.println("Rows impacted : " + rows );

            // Let us select all the records and display them.
            sql = "SELECT id, first, last, age FROM Employees";
            ResultSet rs = stmt.executeQuery(sql);

            // STEP 5: Extract data from result set

            while (rs.next()) {
                // Retrieve by column name
                int id  = rs.getInt("id");
                int age = rs.getInt("age");
                String first = rs.getString("first");
                String last = rs.getString("last");

                // Display values
                System.out.print("ID: " + id);
                System.out.print(", Age: " + age);
                System.out.print(", First: " + first);
                System.out.println(", Last: " + last);
            }

            // STEP 6: Clean-up environment
            rs.close();
            stmt.close();
            conn.close();

        } catch (SQLException se) {

            // Handle errors for JDBC
            se.printStackTrace();
        } catch (Exception e) {
            // Handle errors for Class.forName
            e.printStackTrace();

        } finally {
            // finally block used to close resources
            try {
                if (stmt != null)
                    stmt.close();
            } catch (SQLException se2) {
            } // nothing we can do
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            } // end finally try
        } // end try

        System.out.println("Goodbye!");
    } // end main
} // end JDBCExample
4

3 回答 3

2

由于数据的可变性,几乎不可能编写一个可以做所有事情的“霸主”。当然,您可能可以在字段值和列名/数字之间设置某种映射和交叉映射......但这很快就会变得混乱......

更好的解决方案是在可能的情况下尝试强制调用者向您提供有效数据。

您可以专注于创建一系列完成所需工作的类,而不是专注于一个类来完成所有工作,从抽象级别开始并从那里构建功能,随着您的进展越来越详细......

例如,您可以使用工厂模式

public class Employee {
    private int id;
    private String first;
    private String last;
    private int age;

    public Employee(int id, String first, String last, int age) {
        this.id = id;
        this.first = first;
        this.last = last;
        this.age = age;
    }

    /* getters and setters */
}

public class EmployeeQuery extends AbstractQuery<Employee> {

    public EmployeeQuery() {
    }

    protected String getTableName() {
        return "Employees";
    }

    protected String getSelectQuery() {
        return "id, first, last, age";
    }

    protected Employee parse(ResultSet rs) {
        int id  = rs.getInt("id");
        int age = rs.getInt("age");
        String first = rs.getString("first");
        String last = rs.getString("last");
        return new Employee(id, first, last, age);
    }

    protected String getUpdateColumns() {
        return "first = ?, last = ?, age = ?";
    }

    protected String getUpdateConstraint() {
        return "id = ?";
    }

    protected void bindValues(Employee record, PreparedStatement stmt) {
        stmt.bindString(1, record.getFirst());
        stmt.bindString(2, record.getLast());
        stmt.bindInt(3, record.getAge());
        stmt.bindInt(4, record.getID());
    }

}

public abstract class AbstractQuery<T> {
    protected abstract String getTableName();
    protected abstract String getSelectQuery();
    protected abstract T parse(ResultSet rs);
    protected abstract String getUpdateColumns();
    protected abstract String getUpdateConstraint();
    protected abstract void bindValues(T record, PreparedStatement stmt);

    public List<T> list() throws SQLException {
        List<T> results = new ArrayList<T>(25);
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            con = // get connection
            stmt = con.createStatement();
            String query = "SELECT " + getSelectQuery() + " FROM " + getTableName();
            rs = stmt.executeQuery(query);
            while (rs.hasNext()) {
                results.add(parse(rs));
            }
        } finally {
            try {
                rs.close();
            } catch (Exception exp) {
            }
            try {
                stmt.close();
            } catch (Exception exp) {
            }
            // Close the connection if you need to...
        }
        return results;
    }

    public int update(T record) throws SQLException {
        int result = -1;
        Connection con = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            con = // get connection
            String query = "UPDATE " + getTableName() + " SET " + getUpdateColumns() + " WHERE " + getUpdateConstraint();
            stmt = con.prepareStatement(query);

            bindValues(record, stmt);

            result = stmt.executeUpdate();
        } finally {
            try {
                rs.close();
            } catch (Exception exp) {
            }
            try {
                stmt.close();
            } catch (Exception exp) {
            }
            // Close the connection if you need to...
        }
        return result;
    }
}

如果这与您想要的位置有点偏离,您可以创建AbstractQuery一个具有查询和Object数组的方法,并简单地使用bindObject将值绑定到查询...

protected int update(String query, Object[] values) {
    //...
    stmt = con.prepareStatement(query);
    for (int index = 0; index < values.length; index++) {
         Object value = values[index];
         stmt.bindObject((index + 1), value);
    }
    //...
}

然后在你身上EmployeeQuery,你可以有一个采用实际参数的方法......

public int update(int id, String first, String last, int age) {
    return update(
        "UPDATE EMPLOYEES SET first = ?, last = ?, age = ? WHERE id = ?",
        new Object[]{first, last, age, id});
}

例如....

请注意,我几乎直接输入了这个,所以我没有通过编译器运行它,所以可能会有一些错误,但我希望它会帮助产生一些想法......

于 2013-09-18T06:49:33.683 回答
1

“保存”和“查询”应该是单独的操作/方法。你现有的设计是完全错误的。

您可以使用 Map 来携带任意表单字段,但最好将其包装在一个类中(也许命名为“DataForm”?)。这样,您可以附加 ID 和类型、名称/标题、日期和用户等标题字段以及用于乐观锁定的版本计数器。

保存和加载这些 DataForm 的代码可能应该与 DataForm 本身分开。load(),create()并且save()都应该是单独的操作。Save 可以通过是否设置了非零 ID 来区分 INSERT 和 UPDATE。

您可能还需要 DataForms 的类型信息,以提供帮助。加载到正确的类型、写入 NULL 和验证。这将是一个带有(最简单的)FieldName -> Class 的映射的 DataFormType,或者(更有用的)FieldName -> DataFieldType 的映射。

public interface DataFieldType {
    public Class getDataType();
    public int   getSqlType();

    public void storeToDB (Object value, PreparedStatement stmt);
    public Object loadFromDB (ResultSet rs);

    public String formatToUI (Object value);
    public void parseAndValidate (String text, BindingResult errors);  // to work with Spring framework
}
于 2013-09-19T01:04:52.223 回答
-1

要实现您期望的功能,您必须使用 JAVA Reflection API。另外我会建议以下方法

  1. 不是将字符串数据传递给构造函数,而是传递一个对象列表。
  2. 使用反射识别它是对象的类型,并相应地调用设置器

这是反射 API 链接http://docs.oracle.com/javase/tutorial/reflect/

于 2013-09-18T06:18:22.840 回答