在我的一个使用 Java Swing 和 MySQL 实现的 DBMS 项目中,我遇到了一个非常有趣的问题。
考虑以下代码:
if(source == insert){
insertRecord(columnNames, numOfColumns);
getAllRecords();
displayAllRecords();
}
预期结果:
此代码是事件处理程序的一部分,它决定单击按钮时要执行的操作。
当用户想要插入一条记录时,他单击按钮并调用 insertRecord()
函数。这个插入函数继承自一个抽象类。
插入 getAllRecords()
函数后执行“SELECT”查询并将结果存储到全局 ResultSet 中。
然后 displayAllRecords()
函数将屏幕上的记录显示在表格中。
显然发生了什么:
在执行 insertRecord()
函数的同时,还执行了另外两个函数 getAllRecords()
和 displayAllRecords()
。
这意味着插入后显示的不是我的数据,而是插入前存在的数据。
问题:
这似乎是一个与 Swing 和线程中的并发相关的问题,但是是否有任何简单的解决方案可以应用来使代码按我希望的方式工作,而不会对我的程序产生不利影响?
(如果你想看其他代码,请在评论中告诉我,我会把它们作为编辑发布。原始代码很长,因此我没有发布。)
编辑 1:为上述方法添加代码:
getAllRecords() 的代码
public void getAllRecords(){
// res is a global ResultSet field
try{
res = sqlConn.getStatement().executeQuery("SELECT * FROM " + tableName);
}catch(Exception e){
System.out.println("Error obtaining data!");
}
}
代码:displayAllRecords()
public void displayAllRecords() {
try{
table = new JTable(buildTableModel()); // code provided at bottom
}
catch(SQLException e){
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Unexpected error!");
}
displayResult();
}
displayResult() 代码
public void displayResult(){
//updates the view port of the JScrollPane that is used for the table
tablePane.getViewport().remove(table);
table.revalidate();
tablePane.getViewport().add(table);
custFrame.repaint();
}
buildTableModel() 的代码
public DefaultTableModel buildTableModel() throws SQLException{
//res is a global ResultSet field
Vector<String> columnNames = new Vector<String>();
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
ResultSetMetaData metadata = res.getMetaData();
//getting names of columns
int columnCount = metadata.getColumnCount();
for(int i = 0; i < columnCount; i++){
columnNames.add(metadata.getColumnName(i+1));
}
//getting all data
while(res.next()){
Vector<Object> vec = new Vector<Object>();
for(int i = 0; i < columnCount; i++){
vec.add(res.getObject(i+1));
}
data.add(vec);
}
return new DefaultTableModel(data, columnNames);
}
insertRecord() 的代码
public void insertRecord(ArrayList<String> columnNames, int numOfColumns){
//creation of the GUI... don't know if it matters so kept it
formFrame = new JFrame("INSERT DATA IN TABLE");
labelList = new ArrayList<JLabel>();
textList = new ArrayList<JTextField>();
submit = new JButton("SUBMIT");
prompt = new JLabel("Enter all the details:");
formFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
formFrame.setAlwaysOnTop(true);
formFrame.setResizable(false);
formFrame.setAutoRequestFocus(true);
formFrame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(10, 10, 10, 10);
gbc.fill = GridBagConstraints.BOTH;
formFrame.add(prompt, gbc);
gbc.gridy++;
for(int i = 0; i < numOfColumns; i++, gbc.gridy++){
labelList.add(new JLabel());
labelList.get(i).setText(columnNames.get(i).toUpperCase());
formFrame.add(labelList.get(i), gbc);
}
gbc.gridx = 1;
gbc.gridy = 1;
for(int i = 0; i < numOfColumns; i++, gbc.gridy++){
textList.add(new JTextField(30));
formFrame.add(textList.get(i), gbc);
}
gbc.gridx = 0;
gbc.gridwidth = 2;
formFrame.add(submit, gbc);
formFrame.pack();
formFrame.setVisible(true);
// creation and processing of the insert query
class InsertHandler implements ActionListener{
@Override
public void actionPerformed(ActionEvent e){
String query = "INSERT INTO " + tableName
+ " VALUES( ";
int numOfColumns = textList.size();
for(int i = 0; i < numOfColumns - 1; ++i){
query += "'" + textList.get(i).getText() + "', ";
}
query += "'" + textList.get(numOfColumns-1).getText() + "')";
try {
sqlConn.getStatement().executeUpdate(query);
} catch (SQLException e1) {
JOptionPane.showMessageDialog(null, "Insertion failed!");
}
}
};
submit.addActionListener(new InsertHandler());
}
(抱歉,代码又长又复杂。我已尽力对其进行注释。如果您能提供任何帮助,我将不胜感激。)
最佳答案
您的insertRecord()
方法不会在数据库中插入记录。它所做的只是显示一个新框架。然而,您希望在显示这个新框架后立即插入记录并准备好读取和显示。事实并非如此。
要插入,用户必须盯着框架,喝完咖啡,去洗手间,回来,最后决定点击提交按钮。然后,也只有到那时,数据才会被插入到数据库中。但是 getAllRecords()
和 displayAllRecords()
方法会执行很长时间,因为一旦显示帧,调用方法的执行就会继续。
所以,这里有两个解决方案:
用模态 JDialog 替换
insertRecord()
显示的框架。模态 JDialog 将阻止执行,直到对话框关闭。然后,您将能够检查用户是否确实点击了提交按钮,并刷新显示的数据。在数据插入成功后,调用
InsertHandler.actionPerformed()
方法刷新数据。
关于java - Swing:函数的执行顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22581349/