开发四年只会写业务代码,分布式高并发都不会还做程序员?->>>
背景:有几个结构相同的文章表,每个表数据不足10万,其中的 文章内容字段 保存文章的 HTML 代码。由于文章中有很多图片,所以 文章内容字段 里面有很多的<img> 标签。
数据库:Mysql
数据量:几个表总共加起来的文章数在20万左右,文章内容字段 平均每个字段包括10个 <IMG> 标签。
意图:取出所有的文章表内容字段里面的图片 URL,保存到单独一张表中。
思路:执行Mysql分页查询,每次取出100条数据,分析其中的content字段,用正则匹配出所有的<img>标签的 src 属性,然后插入到另外一个表中。
环境:Win7 64 bit
运行:指定了1G内存
java -Xms256m -Xmx1024m -XX:-UseGCOverheadLimit com.example.tools.ImgsTable
问题:指定50条记录分页查询的时候,总共的数据插入到50万条左右的时候就内存溢出了。报在了MD5方法。指定200条记录分页查询的时候,同样是数据插入到50万条左右的时候就内存溢出了。异常报在了prepareStatement。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at sun.nio.cs.ext.GBK.newEncoder(GBK.java:36)
at java.lang.StringCoding$StringEncoder.<init>(StringCoding.java:215)
at java.lang.StringCoding$StringEncoder.<init>(StringCoding.java:207)
at java.lang.StringCoding.encode(StringCoding.java:266)
at java.lang.StringCoding.encode(StringCoding.java:284)
at java.lang.String.getBytes(String.java:986)
at com.ytt.tools.ImgsTable.md5(ImgsTable.java:29)
at com.ytt.tools.ImgsTable.main(ImgsTable.java:102)
完整程序代码:
注:其中ConnectionPool 是个连接池
package com.example.tools;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ImgsTable {
private final static String IMGROOT = "IMGS/";
private final static String PATH_SEP = "/";
private final static int page_size = 50;
//主方法入口
public static void main(String[] args) {
//匹配img标签的src
Pattern p = Pattern
.compile("<IMG.....");
//几个表
List<String> tables = new ArrayList<String>();
tables.add("post01");
tables.add("post02");
tables.add("post03");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
try {
//循环操作几个表
for (int ti = 0; ti < tables.size(); ti++) {
String tablename = tables.get(ti);
String now = dateFormat.format(new Date());
//每次取出50条记录
String sql = "select dt_id,dt_channel,dt_content from "
+ tablename
+ " where dt_status is null order by dt_id limit ?,?";
int page = 0;
boolean continueWork = true;
while (continueWork) {
Connection conn = ConnetionPool.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, page * page_size);
ps.setInt(2, page_size);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
continueWork = false;
break;
}
rs.beforeFirst();
//开始事务
conn.setAutoCommit(false);
while (rs.next()) {
String content = rs.getString("dt_content");
String dt_channel = rs.getString("dt_channel");
int id = rs.getInt("dt_id");
Matcher m = p.matcher(content);
while (m.find()) {
String imgUrl = m.group(1);
if (imgUrl.length() <= 248) {
String md5Url = md5(imgUrl);
String img_localpath = IMGROOT + tablename
+ PATH_SEP + dt_channel + PATH_SEP + id
+ PATH_SEP + md5Url + "."
+ getExtensionName(imgUrl);
String iSql = "insert into imgs(img_url,img_md5,img_localpath,img_halt,img_stable,img_schannel,img_skey,img_addtime) values(?,?,?,?,?,?,?,?)";
now = dateFormat.format(new Date());
try {
ps = conn.prepareStatement(iSql);
ps.setString(8, now);
if (img_localpath.length() <= 120) {
ps.execute();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
//提交事务
conn.commit();
rs.close();
rs = null;
ps.close();
ps = null;
conn.close();
conn = null;
page++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
不知道我的代码问题出在了哪里?为什么分明我每次是只取出50条记录出来操作,但是内存使用量还是不断增长,到增长到1G的时候,持续一段时间,就会报错,最终的数据处理量只能达到50万左右。
请问,是我的变量定义有问题吗?或者其他问题??
求高手解答!