我正在学习Java,现在正在学习JDBC。我想我已经掌握了如何使用结果集对象,但我想确保我做得正确。
请参阅下面的代码。它在名为"restaurant"的数据库中查询名为"menu"的表。该表有四列:
- id_menuInteger,表的主键
- name字符串,菜单项的名称(例如"Double cheeseburger")
- descrString,菜单项的描述(例如"全麦面包上的两个全牛肉饼。")
- price双倍,物品的价格(例如5.95)(注意,我知道我可以使用Money类型,但我尽量保持简单)
下面是menuItem对象的Java代码。表中的每一行都应该用于创建一个menuItem对象:
public class menuItem {
public int id = 0;
public String descr = "";
public Double price = 0.0;
public String name = "";
public menuItem(int newid, String newdescr, Double newprice, String newname){
id = newid;
descr = newdescr;
price = newprice;
name = newname;
}
}
一切都是公开的,只是为了简化这个练习。
以下是填充数据库的代码。目前,这段代码是主类中的一个方法。
public static ArrayList<menuItem> reQuery() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException{
ArrayList<menuItem> mi = new ArrayList<menuItem>();
//Step 1. User Class.forname("").newInstance() to load the database driver.
Class.forName("com.mysql.jdbc.Driver").newInstance();
//Step 2. Create a connection object with DriverManager.getConnection("")
//Syntax is jdbc:mysql://server/database? + user=username&password=password
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/miguelel_deliveries?" + "user=root&password=");
//Step 3. Create a statement object with connection.createStatement();
Statement stmt = conn.createStatement();
//Step 4. Create variables and issue commands with the Statement object.
ResultSet rs = stmt.executeQuery("Select * from menu");
//Step 5. Iterate through the ResultSet. Add a new menuItem object to mi for each item.
while(rs.next()){
menuItem item = new menuItem(rs.getInt("id_menu"),rs.getString("descr"),rs.getDouble("price"),rs.getString("name"));
mi.add(item);
}
return mi;
}
此代码有效。最后我得到了一个menuItem的ArrayList,这样每个元素都对应于表中的一行。但这是最好的方式吗?我可以将其概括为一种处理结果集的方法吗?
对于数据库中的每个表或视图,创建一个Java类,该类的属性等效于表的列。
将表内容加载到ResultSet对象中。
使用while(ResultSet.next())迭代ResultSet,在步骤1中为ResultSet中的每个项创建一个新对象(来自类)。
创建每个新对象时,将其添加到类的ArrayList中。
根据需要操作ArrayList。
这是一种有效的方法吗?有更好的方法吗?
代码逻辑很好,但实现有几个问题:
- 它不尊重命名约定。类以大写字母开头
- 你不应该使用公共字段。如果构造函数立即重新初始化字段,则将字段初始化为默认值是无用的
- 您没有关闭连接,这意味着每次执行该方法时,它都会打开一个连接,导致内存被白白消耗,并且您的程序最终会由于达到最大打开连接数而失败。连接应该在finally块中关闭,或者使用自Java7以来可用的try-with-resources构造。ResultSet和语句也应该关闭,尽管不关闭它们不像不关闭连接那样有问题
- 对于足够新的驱动程序和JVM,Class.forName().newInstance()不应该是必需的
- 选择的类型很奇怪。例如,价格存储在一个可以为null的Double变量中。但是您使用getDouble()来获取它的值,它永远不会返回null。此外,使用双倍价格是一个糟糕的选择。请改用BigDecimal
- 使用CCD_ 1是一种不好的做法。选择所需的列,而不是所有列
我不会对每个表创建一个类进行概括。很多时候,您不会查询单个表中的所有列,而是查询多个联接表中的某一列。
我也会考虑使用ORM(JPA)而不是JDBC。这将使您的代码更加干净、更短、可读和安全。