Отображение данных из базы данных в JTable - PullRequest
3 голосов
/ 18 марта 2011

Я пишу программу с использованием jdbc, которая будет интерфейсом для базы данных (что-то вроде CRUD-приложения). Я предполагаю, что мне нужно написать класс (например, DBCLass), который будет выполнять все операции с базой данных (select, update, insert, delete и, возможно, некоторую другую логику, которая будет сведена к этим операциям). Пользовательский интерфейс состоит из набора таблиц и нескольких кнопок. Чтобы использовать Jtable, мне нужно реализовать класс (например, Model), который является подклассом AbstractTableModel. Так что этот класс будет отображать мои данные пользователю. Мне нужно реализовать такую ​​модель для всех таблиц в моей схеме базы данных. Я не хочу писать логику в тех классах, которые отображают данные для пользователя, и я думаю, что не очень хорошо писать логический код в таких классах. Но также некорректно загружать все данные из таблицы БД в память (например, ArrayList), а затем отображать их в Model. Итак, я хочу посоветовать, как лучше всего решить эту проблему.

редактирование: Небольшой пример:

Statement stmt = ....;
ResaultSet rs = stmt.executeQuery("SELECT * FROM table1");

javadoc говорит, что метод executeQuery возвращает объект ResultSet, который содержит данные, полученные с помощью данного запроса. Поэтому, если у нас много данных (размер которых больше, чем разрешенный размер для нашей виртуальной машины), наша программа завершится ошибкой. Так что мой вопрос все еще актуален

Ответы [ 6 ]

4 голосов
/ 04 апреля 2011

Загрузите исходный код для SQuirreL SQl и посмотрите на реализацию таблицы.

Некоторые вещи на заметку:

Таблицы базы данных не являются Java JTables. Таблица в базе данных на самом деле является набором (проклинайте дурака, который использовал неправильный термин) с элементами, и у каждого элемента есть свойства (обычно называемые «столбцами», которые не являются JColumn, что объясняет, почему их так сложно сопоставить) .

Набор может вырасти до любого размера. У него нет внутреннего порядка. Вы можете выполнять множество операций над множествами, например: объединение, различие, подмножество.

Следовательно, не таблица, особенно таблица UI.

Не существует простой парадигмы пользовательского интерфейса, которая отображает «set» в «table». Вы можете

  1. Загрузка N записей и просмотр результатов.

  2. Вы можете загрузить больше, когда пользователь прокручивает вниз

  3. Вы можете посчитать размер набора и настроить полосу прокрутки соответственно. Когда пользователь прокручивает данные, они извлекаются из БД и отображаются.

Плюсы + минусы:

Решение 1 является наиболее простым для реализации и тем, которое пользователи ненавидят больше всего. Почему им нужно ждать, чтобы увидеть данные снова, когда идти назад? Это особенно расстраивает, если каждый выбор занимает 15 секунд. Страница ... подожди ... страница ... упс! Там это было! Черт! Подожди, подожди, подожди ... назад ... подожди ... ааааа.

Кроме того, базы данных часто испытывают трудности с поиском данных. Для некоторых запросов производительность может быть катастрофической.

Решение 2 простое в реализации, особенно если вы можете держать ResultSet открытым навсегда. Но 100% времени вы не можете. Он начнет терпеть неудачу, если вы будете держать его открытым в течение пары часов или дня. По истечении этого времени БД будет думать «о, он мертв, Джим» и закроет соединение, и ваш пользователь получит приятное сообщение об ошибке, и вы получите злой пользователя.

Так что вам тоже нужно побывать здесь, но не так часто. С другой стороны, пользователям не нужно снова ждать данных, которые у них уже есть. Один важный момент: если набор содержит миллионы строк, пользователи интуитивно понимают, что им нужно атаковать проблему под другим углом при прокрутке вниз. В конце концов, они устают и просят лучшего решения (вместо того, чтобы сердиться на вас, потому что ваша глупая программа не может отобразить 15 миллионов строк менее чем за 0,0000000001).

Решение 3 хуже, чем # 2, опять же. Если таблица будет расти, пользовательский интерфейс станет непригодным для использования: даже если смотреть на прокрутку, вы попадете в случайное место в таблице. Так что это делает вашу мышь бесполезной. А ваши пользователи злые.

Поэтому я обычно пробую решение, которое:

  1. Читает 1000 строк, макс. Плюс я останавливаюсь после 100 строк (поэтому у пользователя есть хотя бы некоторые данные), если чтение строк занимает более 1 секунды. Обычно запрос выполняется медленно, и чтение результирующего набора практически не занимает времени, но мне нравится защищаться здесь.

  2. Вверху каждого столбца находится фильтр и «порядок по», который можно сопоставить непосредственно с SQL. Таким образом, я могу убедиться, что если вы хотите, чтобы данные сортировались по столбцу, они сортируются по всем значениям (а не только по тем, которые вы видите на экране).

Это позволяет пользователям разделять огромные объемы данных на значимые подмножества.

3 голосов
/ 18 марта 2011

Таблица из базы данных имеет несколько идей.

1 голос
/ 03 апреля 2011

Макс,

Вот еще один пример реализации универсального sql для таблицы:

http://www.oreillynet.com/pub/a/oreilly/java/news/javaex_1000.html

Это может быть хорошим местом для поиска вашего ответа.

Кроме того, этот локальный вопрос / ответ может помочь вам с размером ResultSet: Java JDBC ResultSet с отложенной загрузкой

Надеюсь, это поможет,

Роберт

0 голосов
/ 01 мая 2015

Вы хотите использовать компонент DBTable из проекта QuickTable .

Проверьте этот SO ответ с примером использования кода.

0 голосов
/ 28 августа 2012

В этом блоге объясняется, как загружать данные в табличную модель с отложенной загрузкой: JTable привязывается к базе данных с отложенной загрузкой

0 голосов
/ 19 марта 2011

Вот класс, который извлекает строки данных и столбцы из базы данных.

Посмотрите на table = new JTable (columns (), columns ());

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.print.PrinterException;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import com.swtdesigner.SwingResourceManager;
import java.util.*;
import java.sql.*;
import javax.swing.*;
public class listing extends JDialog {


private JTable table;
public static Vector rows() {

    Vector data = new Vector();
    String sql= null;
    Connection C;


        try {

            DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
            C = (Connection) DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE",
                    "system", "manager");

            Statement stmt = C.createStatement();
            ResultSet rset = stmt.executeQuery("SELECT * FROM site ");
            ResultSetMetaData md = rset.getMetaData();
            int columns = md.getColumnCount();



            while (rset.next()) {
                Vector row = new Vector(columns);

                for (int i = 1; i <= columns; i++) {
                    row.addElement(rset.getObject(i));
                }

                data.addElement(row);

            }

            rset.close();
            stmt.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println(e.getStackTrace());
        }

        //System.out.println("lignes :  "+data);
        return data;
}


   public static Vector columns()
    {   Connection c ;
        Vector cols = new Vector ();
        String sql2=null;
        try { 
            DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
            c = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE",
                    "system", "manager");

            sql2 = "select * from SITE";

            Statement stmt = c.createStatement();
            ResultSet rs = stmt.executeQuery(sql2);
            ResultSetMetaData md = rs.getMetaData();
            int columns = md.getColumnCount();

              //récupération des noms des colonnes dans la table site

            for (int i = 1; i <= columns; i++) {
            cols.addElement(md.getColumnName(i));
            }
           } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println(e.getStackTrace());
        }
        //System.out.println("colonnes ::: "+cols);
        return cols;
    }

public static void main(String args[]) {
    try {
        listing dialog = new listing();
        dialog.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        dialog.setVisible(true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}


public listing() {
    super();
    getContentPane().setLayout(null);
    setTitle("Listing de la table \"SITE\"");
    setBounds(100, 100, 500, 363);
    setResizable(false);

    final JLabel laTablesiteLabel = new JLabel();
    laTablesiteLabel.setText("La table \"SITE\" contient . . . ");
    laTablesiteLabel.setBounds(10, 34, 274, 16);
    getContentPane().add(laTablesiteLabel);

    final JLabel label = new JLabel();
    label.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/130.png"));
    label.setBounds(402, 18, 49, 48);
    getContentPane().add(label);

    final JButton okButton = new JButton();
    okButton.addActionListener(new ActionListener() {
        public void actionPerformed(final ActionEvent arg0) {
            dispose();
            setVisible(false);
        }


    });
    okButton.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/33-32x32.png"));
    okButton.setText("Ok");
    okButton.setBounds(10, 291, 148, 32);
    getContentPane().add(okButton);

    final JButton refeshButton_1 = new JButton();
    refeshButton_1.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/48-32x32.png"));
    refeshButton_1.setText("Actualiser");
    refeshButton_1.setBounds(171, 291, 148, 32);
    getContentPane().add(refeshButton_1);

    final JScrollPane scrollPane = new JScrollPane();
    scrollPane.setBounds(10, 85, 474, 187);
    getContentPane().add(scrollPane);

    table = new JTable(rows(), columns()); // chargement de JTable 
    scrollPane.setViewportView(table);

    final JButton printButton_1_1 = new JButton();
    printButton_1_1.addActionListener(new ActionListener() {
        public void actionPerformed(final ActionEvent arg0) {
            try {
                table.print();
            } catch (PrinterException e) {

                e.printStackTrace();
            }
        }
    });
    printButton_1_1.setIcon(SwingResourceManager.getIcon(listing.class, "/pictures/Printer_h.png"));
    printButton_1_1.setText("Imprimer");
    printButton_1_1.setBounds(336, 291, 148, 32);
    getContentPane().add(printButton_1_1);




    }

}
...