欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

记一次部署项目踩过的坑

程序员文章站 2022-07-13 08:51:25
...

7月初公司接到一个项目,很简单ssm的项目,其中有一块就是数据入库。

编写入库代码,我擅长的很啊,对不对,和磊哥怎么也算是混了一年,不会个入库,岂不是很丢人。

刷刷刷……

没错。很快这个脚本就如火如荼的用上了。

结果真是不尽如人意,是的,没错,报错了!!!

java.lang.OutOfMemoryError: Java heap space 堆内存异常,不得不说,bug真是程序员的好朋友,通过这一周的学习,我学习了堆内存溢出的原因,解决方案,如何调整jar包的内存大小等等等等。

且慢,尽管学习了这么多,但是问题还是没解决,这尼玛。原始代码如下:

/**
 * 数值预报
 * 
 * @author gaoyongqin
 *
 */
public class SzybDB {

	public static void intoDB(File inFile) {
		// 经度,纬度,温度,过去一小时降水
		// Lat,Lon,TEM,PRE_1h
		PreparedStatement prep = null;
		Connection con = C3P0Inner.getConnection();
		String foreignKeySql = "insert into data_szyb values";
		StringBuilder foreignKeyValue = new StringBuilder();

		int i = 0;
		String str = null;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
		BufferedReader br = null;
		String format = sdf.format(new Date());
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(inFile)));
			while ((str = br.readLine()) != null) {
				i++;
				// 该文件第一行直接就是数据,所以不用过滤掉表头
				foreignKeyValue.append(",").append("(").append("null").append(",'");
				String replace = str.replace(" ", "','");
				String name = inFile.getName();
				foreignKeyValue.append(replace).append("','").append(name.substring(0, name.indexOf(".")));
				foreignKeyValue.append("','").append(format).append("')");
				if (i % 5000 == 0) {
					try {
						foreignKeyValue.deleteCharAt(0);
						prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
								+ "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
								+ ",updateTime=VALUES(updateTime)");
						prep.executeUpdate();
					} catch (SQLException e) {
						e.printStackTrace();
					} 
					foreignKeyValue = new StringBuilder();
				}
			}
			if (foreignKeyValue != null && !"".equals(foreignKeyValue)) {
				try {
					foreignKeyValue.deleteCharAt(0);
					prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
							+ "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
							+ ",updateTime=VALUES(updateTime)");
					prep.executeUpdate();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,入库成功");
			} else {
				System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,无数据");
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {

			try {
				if (br != null) {
					br.close();
				}
				if (prep != null) {
					prep.close();
				}
				if (con != null) {
					con.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

丝毫不夸张,我找了我代码的原因找了一周,甚至于我一度认为我的代码没有任何的问题,肯定是jar包进程的内存开的不够大,我还请教了磊哥。迪哥,喜喜。磊哥还教我如何使用jmap等工具

nohup java -Djava.library.path=/home/qht/jdk1.7.0_79/jre/bin -Xms4096m -Xmx4096m -XX:+UseG1GC -jar pythonListen.jar zdyb &>log.log &
/home/qht/jdk1.7.0_79/bin/jmap -heap 30869
/home/qht/jdk1.7.0_79/bin/jmap -histo:live 30869

 

我调整了运行jar包的进程内存大小,自己得意的不行,安全的跑了一天的数据,第二天悲催的又堆内存溢出了,这下我不淡定了。感情没几天就要去内蒙部署项目了,现在还在这崩着呢!其中除了内存溢出,还有一个错误:

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 59,977 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.

链接超时了,我压根儿没把这两个错误联系在一起,这为我后面找了这个bug找了两周埋下了伏笔。讲真的,我又学会了如何去处理这个链接超时:

参考:https://www.cnblogs.com/chrischennx/p/7279215.html?utm_source=itdadao&utm_medium=referral

第一种:调节wait_timeout,

设置mysql超时:
mysql -uroot -p -h 127.0.0.1

set  global  interactive_timeout=31536000;
set  global  wait_timeout=31536000;

将wait_timeout设置成一年。

第二种:

为了避免空闲时间过长超过最大空闲时间而被断开,我们设置三个配置:

validationQuery: SELECT 1
testWhileIdle: true
timeBetweenEvictionRunsMillis: 28000

其中timeBetweenEvictionRunsMillis需要小于mysql的wait_timeout

但是这种方法无法避免重启的情况,不过一般数据库不会频繁重启,影响不大,如果非得频繁重启,可以通过设置testOnBorrow,即申请连接的时候先试一试连接是否可用,不过带来的影响就是性能降低,需要根据实际需求合理取舍。

其中因为我是用的c3p0链接的数据库,所以设置的参数有点不一样,但是想法是一样的。

参考:https://blog.csdn.net/mmake1994/article/details/86561940

 

好了,后面再说一下那个内存溢出吧!!!

后面其实我想通了,为什么内存溢出了,然后就是链接超时了,哦~~~~(你应该了解我的心情。)

那大约就应该是链接没有关闭???抱着这样的想法,我改了我的代码!

/**
 * 数值预报
 * 
 * @author gaoyongqin
 *
 */
public class SzybDB {

	public static void intoDB(File inFile) {
		// 经度,纬度,温度,过去一小时降水
		// Lat,Lon,TEM,PRE_1h
		PreparedStatement prep = null;
		Connection con = C3P0Inner.getConnection();
		String foreignKeySql = "insert into data_szyb values";
		StringBuilder foreignKeyValue = new StringBuilder();

		int i = 0;
		String str = null;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
		BufferedReader br = null;
		String format = sdf.format(new Date());
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(inFile)));
			while ((str = br.readLine()) != null) {
				i++;
				// 该文件第一行直接就是数据,所以不用过滤掉表头
				foreignKeyValue.append(",").append("(").append("null").append(",'");
				String replace = str.replace(" ", "','");
				String name = inFile.getName();
				foreignKeyValue.append(replace).append("','").append(name.substring(0, name.indexOf(".")));
				foreignKeyValue.append("','").append(format).append("')");
				if (i % 5000 == 0) {
					try {
						foreignKeyValue.deleteCharAt(0);
						prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
								+ "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
								+ ",updateTime=VALUES(updateTime)");
						prep.executeUpdate();
					} catch (SQLException e) {
						e.printStackTrace();
					} finally {
						try {
							if (prep != null) {
								prep.close();
							}
						} catch (SQLException e) {
							e.printStackTrace();
						}
					}
					foreignKeyValue = new StringBuilder();
				}
			}
			if (foreignKeyValue != null && !"".equals(foreignKeyValue)) {
				try {
					foreignKeyValue.deleteCharAt(0);
					prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
							+ "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
							+ ",updateTime=VALUES(updateTime)");
					prep.executeUpdate();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,入库成功");
			} else {
				System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,无数据");
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {

			try {
				if (br != null) {
					br.close();
				}
				if (prep != null) {
					prep.close();
				}
				if (con != null) {
					con.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

仔细对比代码,没错,我在每一次链接完数据库之后都会在finally里把prep链接关闭。然后结合着jmap查看,果然,正如我所料。一切都是那么的好,那么的优秀,哎呀,困扰我3周的问题就这样解决了,我真是心情大好,也不知道怎么了,自己也工作了这么久,还是这么的……菜!!我真是有点悲哀啊!

废话不多说,也算是学习到了一点点的东西吧,让我在这条路上是铺砖添瓦了!

打完,收工!