【问题标题】:Java- Multi-threading to improve performance on inserting data into dbJava-多线程以提高将数据插入数据库的性能
【发布时间】:2018-10-26 02:46:46
【问题描述】:

我正在 MYSQL 中的一个表上构建一个索引表(反转文件)。它的工作方式是从文件中提取所有单词并将它们存储到哈希集,然后将单词一一插入到我的数据库表中。

它工作得很好,我知道倒排文件确实需要一些时间来建立索引表。我正在尝试优化表的索引时间,并且正在考虑使用多线程。它会加快性能吗?

但是,我不太确定如何将它与我当前的程序集成,因为我是多线程的新手。

代码:

public static void main(String[] args) throws Exception {

        StopWatch stopwatch = new StopWatch();
        stopwatch.start();



        File folder = new File("D:\\PDF1");
        File[] listOfFiles = folder.listFiles();

        for (File file : listOfFiles) {
            if (file.isFile()) {
                HashSet<String> uniqueWords = new HashSet<>();
                String path = "D:\\PDF1\\" + file.getName();
                try (PDDocument document = PDDocument.load(new File(path))) {

                    if (!document.isEncrypted()) {

                        PDFTextStripper tStripper = new PDFTextStripper();
                        String pdfFileInText = tStripper.getText(document);
                        String lines[] = pdfFileInText.split("\\r?\\n");
                        for (String line : lines) {
                            String[] words = line.split(" ");

                            for (String word : words) {
                                uniqueWords.add(word)
                                ;

                            }

                        }
                        // System.out.println(uniqueWords);

                    }
                } catch (IOException e) {
                    System.err.println("Exception while trying to read pdf document - " + e);
                }
                Object[] words = uniqueWords.toArray();



                MysqlAccessIndex connection = new MysqlAccessIndex();

                for(int i = 1 ; i <= words.length - 1 ; i++ ) {

                    connection.readDataBase(path, words[i].toString());

                }

                System.out.println("Completed");

            }
        }

MySQL 连接:

public class MysqlAccessIndex {
    public Connection connect = null;
    public Statement statement = null;
    public PreparedStatement preparedStatement = null;
    public ResultSet resultSet = null;

    public void connect() throws Exception {
        // This will load the MySQL driver, each DB has its own driver
        Class.forName("com.mysql.jdbc.Driver");
        // Setup the connection with the DB
        connect = DriverManager
                .getConnection("jdbc:mysql://126.32.3.20/fulltext_ltat?"
                        + "user=root&password=root");

        // Statements allow to issue SQL queries to the database
        statement = connect.createStatement();
        System.out.print("Connected");

    }
    public MysqlAccessIndex() throws Exception {

        connect();
    }


    public void readDataBase(String path,String word) throws Exception {
        try {

            // Result set get the result of the SQL query


            // This will load the MySQL driver, each DB has its own driver
            Class.forName("com.mysql.jdbc.Driver");
            // Setup the connection with the DB
            connect = DriverManager
                    .getConnection("jdbc:mysql://126.32.3.20/fulltext_ltat?"
                            + "user=root&password=root");

            // Statements allow to issue SQL queries to the database
            statement = connect.createStatement();
            System.out.print("Connected");
            // Result set get the result of the SQL query

            preparedStatement = connect
                    .prepareStatement("insert IGNORE into  fulltext_ltat.indextable values (default,?, ?) ");

            preparedStatement.setString(  1, path);
            preparedStatement.setString(2, word);
            preparedStatement.executeUpdate();
            // resultSet = statement
            //.executeQuery("select * from fulltext_ltat.index_detail");



            //  writeResultSet(resultSet);
        } catch (Exception e) {
            throw e;
        } finally {
            close();
        }

    }

我将不胜感激。

【问题讨论】:

  • 如果你的 Java 程序可以被分解成更小的部分,每个部分都可以独立运行,那么它可能会受益于多线程。是这样吗?
  • @TimBiegeleisen 如果不分解成更小的部分,创建几个线程来运行我的 main 方法会有所帮助吗?
  • 它会工作还是帮助?不是同一个问题。
  • 在循环中的代码readDataBase 中,您每次都在连接 - 这将非常慢, - 考虑使用 DBCP
  • 一个提示:您可以立即开始向数据库添加单词,您无需等待文本剥离器完成,只需将单词传递给另一个线程,并保持恒定的数据库连接在另一个线程上。

标签: java mysql


【解决方案1】:

不,将数据推送到具有多个线程的数据库通常不会加快任何速度。

请尝试以下方法:

[1] 批量添加数据时,请使用您的数据库引擎提供的批量添加数据原语。我不知道mysql是否支持这个,以及如何从java中做到这一点。例如,在 postgres 中,您将使用 COPY 而不是 INSERT。

[2] 特别是如果您不能使用 COPY 或类似功能,请关闭所有索引(删除它们),然后执行所有插入,然后添加索引,这比先创建索引然后插入要快。

[3] 使用事务,并每隔约 100 次插入提交事务。在大多数情况下,这比每次插入后提交更快,也比在数十万次后提交更快。

[4] 更早开始。在您的示例代码中,您可以立即开始插入,而不是先将所有数据填充到哈希集中,然后再添加。

[5] 不要一直做准备好的陈述;重复使用同一个。

[6] 你做了两次声明,然后什么也不做。不;你在浪费资源。

[7] 准备好的语句需要关闭。你没有关闭它们。这可能会大大减慢速度。不要做这么多(应该做一个),完成后关闭它们。搜索“ARM”,这是一个 java 构造,可以轻松正确地关闭资源。到现在已经十多岁了。

【讨论】:

  • 根据您的第 1 点,我尝试了批量插入,但对性能没有太大帮助。
  • 您能否澄清第 5 点?我不明白我在哪里重新使用了我的preparedStatement。 4:我使用hashset是因为我想在其中存储唯一的单词,而hashset不允许重复,所以当我插入数据库时​​,没有重复的单词。
  • @Daredevil 你没有重用你的preparedstatement。你应该开始这样做。
  • 我应该如何重复使用它?
  • @Daredevil 您可以再次调用 .setString(1, path) (因此,在循环外创建preparedstatement),然后继续调用 .executeUpdate() 。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 2017-07-06
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多