Pgjdbc执行COPY的记录

最近接触了Pgjdbc执行COPY命令的代码,在使用中也产生了一些想法,在此记录

简单的测试代码

从表中读入,写入另一张表

package org.postgresql.newTest;

import org.junit.Test;

import org.postgresql.copy.CopyManager;
import org.postgresql.core.BaseConnection;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @author ljx
 * @version 1.0
 * @description: TODO
 * @date 2024/8/23 11:19
 */
public class CopyTest {

  private static final String DB_URL = "jdbc:postgresql://xxxxxxxxxx"
      + "/mydb";
  private static final String USER = "testuser";
  private static final String PASSWORD = "Helloworld";

  //在windows上除非你给予用户对该文件夹完全控制的权限,否则无法自动新建文件
  private static final String FILE_PATH = "D:\\javap\\testfile\\test2";


  public void copyIn(String tabName) {

    try (Connection connection = getConnection();
         Reader reader = new FileReader(new File(FILE_PATH));) {

      CopyManager copyManager = new CopyManager((BaseConnection) connection);
      copyManager.copyIn("COPY " + tabName + " FROM STDIN ", reader);
    } catch (Exception e) {
      handleException(e);
    }
  }

  private Connection getConnection() throws SQLException, ClassNotFoundException {
    Class.forName("org.postgresql.Driver");
    return DriverManager.getConnection(DB_URL, USER, PASSWORD);
  }


  private void handleException(Exception e) {
    e.printStackTrace();
    System.err.println("Error occurred while copying data: " + e.getMessage());
  }


  /**
   * @description: 使用copyOut
   * @param: tableName
   * @return: void
   * @author
   * @date: 2024/8/23 15:55
   */
  public void copyOut(String tableName) {
    try {
      Connection connection = getConnection();
      //仅限于测试,使用时建议使用OutputStream
      FileWriter fileWriter = new FileWriter(new File(FILE_PATH));
      CopyManager copyManager = new CopyManager((BaseConnection) connection);
      String copyStatement = "COPY " + tableName + " TO STDOUT ";
      //上限1600,记得清理缓存
      copyManager.copyOut(copyStatement, fileWriter);
      fileWriter.close();
    } catch (IOException | SQLException | ClassNotFoundException e) {
      throw new RuntimeException(e);
    }
  }
  @Test
  public void copyIOTest() {

    copyOut("tab_test");
    copyIn("tab_test_copy1");
  }
}

读二进制数据,以bytea为例

首先忽略Pg有没有自动转换问题,仅仅进行测试二进制数据的读写

首先找一个图片文件,之后在表中以bytea格式存储该文件,之后使用getBytes方法读出其数据,并转为16进制,简单的输出一下。与原文件的16进制形式对比,我们发现其以\x开头,而其他部分没有变化,这显然是数据库对其进行的处理,再次推测,是否必须加上\x才是Pg内部的存储格式?而加上该\x之后,对图片的显示并无影响,因而推测,是否是所有的文件加上\x的二进制表示都不会影响使用?

测试将图片文件加上16进制的\x存入库内,再读出,查看图片是否正常,是否添加了两重的\x

代码如下:

public void copyByteaTest() throws IOException {
    byte[] data = Files.readAllBytes(Paths.get("D:\\javap\\testfile\\test_addx.jpg"));
    String chars = bytesToHex(data, 0);
    //生成点测试数据
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 1; i <= 100; i++) {
      stringBuilder.append(i);
      stringBuilder.append(",");
      stringBuilder.append(chars);
      stringBuilder.append(",");
      stringBuilder.append(chars);
      if(i != 100){
        stringBuilder.append("\n");
      }

    }
    //写入测试文件
    String tem =stringBuilder.toString();
    byte[] datas = tem.getBytes();
    OutputStream out = new FileOutputStream("D:\\javap\\testfile\\test_addx");
    out.write(datas);
    out.close();

    //写入数据库
    try (Connection connection = getConnection();
         Reader reader = new FileReader(new File("D:\\javap\\testfile\\test_addx"));) {

      CopyManager copyManager = new CopyManager((BaseConnection) connection);
      copyManager.copyIn("COPY tab_test_copy1(id,img,img_copy) FROM STDIN WITH(DELIMITER ',') ", reader);
    } catch (Exception e) {
      handleException(e);
    }
//从库中读出一个
    try (Connection conn = getConnection();
         Statement st = conn.createStatement();) {
      ResultSet rs = st.executeQuery("SELECT * FROM tab_test_copy1 WHERE id = 1");
      rs.next();
      byte[] imgBytes = rs.getBytes(1);
//       System.out.println(bytesToHex(imgBytes,0).substring(0,4));//检查是否双重\\x
      FileOutputStream out2 = new FileOutputStream(new File("D:\\javap\\testfile\\test_addx_copy.jpg"));//图片格式是否毁坏
      out2.write(imgBytes);
    } catch (SQLException | ClassNotFoundException | IOException e) {
      throw new RuntimeException(e);
    }

  }

经检查,只有一重\x,因而推测以\x开头应该是Pg数据库内部的一种保存机制,考虑到\x中若将\考虑为转义,其应该为\x,也就是16进制。

posted @ 2024-08-26 13:36  li-羡鱼  阅读(3)  评论(0编辑  收藏  举报