通过构造函数将值传递给数据库

时间:2013-09-18 06:04:25

标签: java sql

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

蜷缩:
数据库类使用预准备语句。我无法将绑定值bin的部分传递给参数,该部分看起来像:

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

有没有人对如何解决这个问题有任何想法?

构造函数中的变量意味着:     字符串数据:各种文本字段值     字符串表:数据库中将存储值的特定表     String sql:将值bin绑定到参数的部分(我在上面的“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

3 个答案:

答案 0 :(得分:2)

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

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

不是专注于单个类来完成所有事情,而是可以专注于创建一系列完成所需工作的类,从抽象级别开始并从那里构建功能,随着时间的推移变得更加详细。 ..

例如,您可以使用factory pattern

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});
}

例如......

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

答案 1 :(得分:1)

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

您可以使用Map来携带任意形式字段,但最好将其包装在一个类中(可能名为“DataForm”?)。这样你可以附上一个ID&amp;键入,标题字段,如名称/标题,日期和用户,以及用于乐观锁定的版本计数器。

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

您可能还需要DataForms的类型信息,以帮助例如。加载到正确的类型,写入NULL和验证。这将是一个DataFormType,其中(最简单的)是FieldName的地图 - &gt;类,或(更有用)FieldName的地图 - &gt; 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
}

答案 2 :(得分:-1)

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

  1. 而不是将String数据传递给构造函数传递一个Objects列表。
  2. 使用反射识别对象的类型并相应地调用setter
  3. 以下是Reflections API链接http://docs.oracle.com/javase/tutorial/reflect/