Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用Hibernate尽可能快地插入数据_Java_Database_Performance_Hibernate_Jpa - Fatal编程技术网

Java 如何使用Hibernate尽可能快地插入数据

Java 如何使用Hibernate尽可能快地插入数据,java,database,performance,hibernate,jpa,Java,Database,Performance,Hibernate,Jpa,我读取文件并从中创建一个对象,然后将其存储到postgresql数据库。我的文件有100000个文档,我从一个文件中读取这些文档并将其拆分,最后存储到数据库中。 我无法创建列表并将所有文档存储在列表中,因为我的RAM很少。我对数据库的读写代码如下。但我的JVM堆已满,无法继续存储更多文档。如何高效地读取文件并存储到数据库 public void readFile() { StringBuilder wholeDocument = new StringBuilder(); try

我读取文件并从中创建一个对象,然后将其存储到postgresql数据库。我的文件有100000个文档,我从一个文件中读取这些文档并将其拆分,最后存储到数据库中。 我无法创建
列表
并将所有文档存储在
列表
中,因为我的RAM很少。我对数据库的读写代码如下。但我的JVM堆已满,无法继续存储更多文档。如何高效地读取文件并存储到数据库

public void readFile() {
    StringBuilder wholeDocument = new StringBuilder();
    try {
        bufferedReader = new BufferedReader(new FileReader(files));
        String line;
        int count = 0;
        while ((line = bufferedReader.readLine()) != null) {
            if (line.contains("<page>")) {
                wholeDocument.append(line);
                while ((line = bufferedReader.readLine()) != null) {
                    wholeDocument = wholeDocument.append("\n" + line);
                    if (line.contains("</page>")) {
                        System.out.println(count++);
                        addBodyToDatabase(wholeDocument.toString());

                        wholeDocument.setLength(0);
                        break;
                    }
                }
            }
        }
        wikiParser.commit();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public void addBodyToDatabase(String wholeContent) {
    Page page = new Page(new Timestamp(System.currentTimeMillis()),
            wholeContent);
    database.addPageToDatabase(page);
}

public static int counter = 1;

public void addPageToDatabase(Page page) {
    session.save(page);
    if (counter % 3000 == 0) {
        commit();
    }
    counter++;
}
public void readFile(){
StringBuilder wholeDocument=新建StringBuilder();
试一试{
bufferedReader=新bufferedReader(新文件读取器(文件));
弦线;
整数计数=0;
而((line=bufferedReader.readLine())!=null){
如果(第行包含(“”)){
wholeDocument.append(行);
而((line=bufferedReader.readLine())!=null){
wholeDocument=wholeDocument.append(“\n”+行);
如果(第行包含(“”)){
System.out.println(count++);
addBodyToDatabase(wholeDocument.toString());
wholeDocument.setLength(0);
打破
}
}
}
}
commit();
}catch(filenotfounde异常){
e、 printStackTrace();
}捕获(IOE异常){
e、 printStackTrace();
}最后{
试一试{
bufferedReader.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
public void addbody数据库(字符串wholeContent){
Page Page=新页面(新时间戳(System.currentTimeMillis()),
整体内容);
数据库。addPageToDatabase(第页);
}
公共静态整数计数器=1;
公共无效addPageToDatabase(第页){
会话保存(第页);
如果(计数器%3000==0){
提交();
}
计数器++;
}

我对您的数据文件的结构不是很确定。如果您能提供一个文件示例,这将很容易理解

内存消耗的根本原因是读取/迭代文件的方式。一旦有东西被读取,就会留在记忆中。您应该使用
java.io.FileInputStream
org.apache.commons.io.FileUtils

下面是一个使用
java.io.FileInputStream进行迭代的示例代码

try (
        FileInputStream inputStream = new FileInputStream("/tmp/sample.txt");
        Scanner sc = new Scanner(inputStream, "UTF-8")
) {
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        addBodyToDatabase(line);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
下面是一个使用
org.apache.commons.io.FileUtils进行迭代的示例代码

File file = new File("/tmp/sample.txt");
LineIterator it = FileUtils.lineIterator(file, "UTF-8");
try {
    while (it.hasNext()) {
        String line = it.nextLine();
        addBodyToDatabase(line);
    }
} finally {
    LineIterator.closeQuietly(it);
}

您应该开始一个事务,执行保存操作并提交一个事务。(保存后不要开始事务!)。您可以尝试使用排除缓存的内存消耗

并在代码中使用更多更小的值,例如20

if (counter % 20 == 0)
您可以尝试尽可能将
StringBuilder
作为方法的参数传递。

我使用@RookieGuy answer。

我用

session.flush();
session.clear();
最后读取所有文档并存储到数据库中

tx.commit();
session.close();
改变

wholeDocument = wholeDocument.append("\n" + line);


首先,您应该在这里应用一种方法

主任务解析该文件,并将最多100个项目的批发送到。
ExecutorService
应具有与可用数据库连接数相等的工作线程数。如果您有4个CPU核,那么假设数据库可以进行8个并发连接,而无需进行太多的上下文切换

然后,您应该配置一个连接池
DataSource
,并将minSize设置为maxSize和8。尝试HikariCP或ViburDBCP进行连接池

然后需要配置JDBC批处理。如果您使用的是MySQL,则标识生成器将禁用沐浴功能。如果您使用的是支持序列的数据库,请确保还使用增强的标识符生成器(它们是Hibernate 5.x中的默认选项)


通过这种方式,实体插入过程被并行化,并与主解析线程解耦。主线程应该等待ExecutorService在关闭之前完成所有任务。

实际上,如果不进行真正的分析,就很难向您提出建议,并找出是什么原因导致代码运行缓慢或效率低下

但是,我们可以从您的代码中看到一些东西

  • 您正在低效地使用StringBuilder

    wholeDocument.append(“\n”+行)应写为
    wholeDocument.append(“\n”).append(行)取而代之

    因为你原来写的东西会被编译器翻译成
    whileDocument.append(新的StringBuilder(“\n”).append(line.toString())
    。您可以看到您创建了多少不必要的
    StringBuilder
    s:)

  • 关于使用Hibernate的思考

    我不确定您是如何管理您的
    会话的
    ,还是如何实现您的
    提交()
    ,我假设您做对了,还有更多事情需要考虑:

    • 您是否在Hibernate中正确设置了批大小?(
      hibernate.jdbc.batch_size
      )默认情况下,jdbc批大小大约为5。您可能希望确保将其设置为更大的大小(以便内部Hibernate将以更大的批发送插入)

    • 鉴于您不需要一级缓存中的实体供以后使用,您可能需要执行间歇会话
      flush()
      +
      clear()
      ,以

    • 触发上一点中提到的批插入
    • 清除一级缓存
  • 为此功能从休眠状态切换

    冬眠很酷,但它不是万能的。鉴于此功能,您只需根据文本文件内容将记录保存到数据库中。您不需要任何实体行为,也不需要使用一级缓存进行后续处理,考虑到额外的处理和空间开销,这里没有太多的理由使用Hibernate。简单地执行JDBCWI
    wholeDocument.append("\n" + line);