使用CSV文件批量导入数据库
程序员文章站
2022-06-11 13:27:51
...
说明
当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。
CSV文件:逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。CSV是一种通用的、相对简单的文件格式,被用户、商业和科学广泛应用。最广泛的应用是在程序之间转移表格数据,而这些程序本身是在不兼容的格式上进行操作的(往往是私有的和/或无规范的格式)。因为大量程序都支持某种CSV变体,至少是作为一种可选择的输入/输出格式。
应用
package test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class CsvInsert extends Thread {
private static final String user = "test";
private static final String pwd = "123";
private static final String url = "jdbc:sqlserver://localhost:1433; DatabaseName=Person";
private static final String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static String SEPARATOR = ","; // CSV文件的分隔符为","
private static int largest_numbers = 200; // 某些数据库一次批量最多为5W条数据,可调整
private String file_path;
// 构造方法,传入文件位置
public CsvInsert(String file_path) {
this.file_path = file_path;
}
// 重写线程run()方法
@Override
public void run() {
this.insertDB(largest_numbers, this.file_path);
}
public static void main(String[] args) throws FileNotFoundException {
CsvInsert insertDB1 = new CsvInsert("xxx/xxx/students.csv");
insertDB1.start(); // 开启线程
}
// @SuppressWarnings("resource")
public boolean insertDB(int rc, String file_path) {
// System.out.println(file_path);
Connection con = null;
boolean flag = false;
PreparedStatement pst = null;
// 计算一共插入多少条数据
long rowCount = 0;
String insertSql = "insert into students (学号,姓名,年级,学院,专业) values(?,?,?,?,?)";
try {
con = getCon();
con.setAutoCommit(false); // 关闭自动提交,开启事务
pst = con.prepareStatement(insertSql);
// 根据路径生成File
File raf = new File(file_path);
BufferedReader buf = null;
// 根据自己的需要可以改变这里读取文件的编码
buf = new BufferedReader(new InputStreamReader(new FileInputStream(raf), "gb2312"));
String line_record = buf.readLine();
long sqlstart = System.currentTimeMillis(); // 开始计时
// 逐行读取
while (line_record != null) {
// 解析每一条记录,按","切割数据
String[] fields = line_record.split(SEPARATOR);
// 对Insert语句的合法性进行判断
if (fields.length != 5) { // 要插入的列为5列
System.out.println("csv文件中有"+fields.length+"列,要插入的数据列数和表的数据列不相匹配!停止执行!");
System.out.println("问题出现在第"+rowCount+"行");
break;
}
for (int i = 1; i <= 5; i++) {
pst.setString(i, fields[i-1]);
// 使用if、switch等,可以根据需要调整顺序,某列是别的类型也可以改变pst.setxxx的内容
}
rowCount++;
// 添加批
pst.addBatch();
// 分段提交,每5W条数据提交一次
if (rowCount % rc == 0 && rowCount != 0) {
// 执行批量导入
pst.executeBatch();
con.commit();
// 清除积攒的sql
pst.clearBatch();
// con.setAutoCommit(false); // 开始事务
// pst = con.prepareStatement(insertSql);
System.out.println("已满" + rowCount + "条");
}
// 下一行
line_record = buf.readLine();
}
// 最后提交剩余的不足5W条的数据
pst.executeBatch();
// 清除原来的sql
// pst.clearBatch();
con.commit();
System.out.println("共写入行数:" + rowCount);
long sqlend = System.currentTimeMillis(); // 停止计时
System.out.println("执行时间为:" + (sqlend - sqlstart) + " ms");
buf.close();
pst.close();
con.setAutoCommit(true); //再把自动提交打开
con.close();
} catch (Throwable e) {
if (con != null) {
try {
// 异常回滚
System.out.println("出错在"+rowCount+"行");
con.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
throw new RuntimeException(e);
} finally {
if (pst != null) {
try {
pst.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (con != null) {
try {
System.out.println("出错在"+rowCount+"行");
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return flag;
}
// 获取连接
public static Connection getCon() {
Connection con = null;
try {
Class.forName(driver).newInstance();
con = DriverManager.getConnection(url, user, pwd);
if (con != null) {
System.out.println("你已连接到数据库:" + con.getCatalog());
}
} catch (Exception e) {
System.out.println("连接数据库失败!");
e.printStackTrace();
}
return con;
}
}
1 采用PreparedStatement.addBatch()实现批处理,由于发送的是预编译后的SQL语句,执行效率高。由于没有采取自动提交的方式,使用Connection.setAutoCommit(false); 就必须注意回滚和事务提交具体解释请查看大神的解释->http://blog.csdn.net/macwhirr123/article/details/45578181
2 采用线程的方式处理文件,使得程序更加灵活
运行
数据库结构
测试
上一篇: SQL大批量导入数据实例分析
下一篇: JS判断访问设备是移动设备还是pc