id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc	due_date
142	比价系统定时任务卡死诡异问题	huangyucai		"
一、故障
	9月16日下午机房停电，之后服务器重启，比价系统全量同步数据的定时任务执行速度慢，直到卡死，最后报错：
第一种：

{{{
org.springframework.dao.CannotAcquireLockException: PreparedStatementCallback; SQL [INSERT INTO pp_product_type SET 

product_type_id=?,name=?,type=?,parent_id=?,pub_url=?,order_key=? ON DUPLICATE KEY UPDATE 

name=?,type=?,parent_id=?,pub_url=?,order_key=?]; Lock wait timeout exceeded; try restarting transaction; nested exception is 

java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction
}}}


第二种：

{{{
org.springframework.dao.DataAccessResourceFailureException: PreparedStatementCallback; SQL [INSERT INTO pp_product SET 

product_id=?,name=?,brand_id=?,type_id=?,price=?,pic_path=?,pub_url=?, 

brand_name=?,model_name=?,series_id=?,variance_id=?,price_config=?,order_key=?,create_date=?,hot_new=?,variance_count=?,artpic_coun

t=?, 

download_count=?,article_count=?,visit_count=?,comment_count=?,comment_commend_count=?,comment_uncommend_count=?,emall_o

wned=?, 

forum_path=?,item_1=?,item_2=?,item_3=?,item_4=?,item_5=?,version=?,review_count=?,last_count_order=?,eyp_price_count=?,kzd_count=?

, price_100=?,change_rate_100=?,price_show=?,short_name=?,warranty=?,compat=?,mid_pic_path=?,video_count=?,vip_flag=?,item_6=?, 

comment_score=?,comment_total_vote=?,index_pic_path=?,index6_pic_path=?,index7_pic_path=?,concept=?,price_str=?,change_rate_str=? 

ON DUPLICATE KEY UPDATE name=?,brand_id=?,type_id=?,price=?,pic_path=?,pub_url=?, 

brand_name=?,model_name=?,series_id=?,variance_id=?,price_config=?,order_key=?,create_date=?,hot_new=?,variance_count=?,artpic_coun

t=?, 

download_count=?,article_count=?,visit_count=?,comment_count=?,comment_commend_count=?,comment_uncommend_count=?,emall_o

wned=?, 

forum_path=?,item_1=?,item_2=?,item_3=?,item_4=?,item_5=?,version=?,review_count=?,last_count_order=?,eyp_price_count=?,kzd_count=?

, price_100=?,change_rate_100=?,price_show=?,short_name=?,warranty=?,compat=?,mid_pic_path=?,video_count=?,vip_flag=?,item_6=?, 

comment_score=?,comment_total_vote=?,index_pic_path=?,index6_pic_path=?,index7_pic_path=?,concept=?,price_str=?,change_rate_str=?]; 

No operations allowed after statement closed.; nested exception is java.sql.BatchUpdateException: No operations allowed after statement 

closed.
}}}


但测试环境里跑定时任务并没有发现这类问题

二、分析
1、首先怀疑有执行慢的SQL语句，同步数据的定时任务大部分使用mysql的“insert ... ON DUPLICATE KEY UPDATE...”这样的语句
于是改造，将SQL改成insert 和 update两条语句，在执行前判断存在记录，如果不存在则insert，否则update。但问题并没有解决。定时
任务依旧会卡死

2、从第一种异常看，有锁表的现象，事务重新启动，第二种异常，statement 等待时间长被关闭导批量更新异常。 猜测事务未提交所致
比价系统是使用spring的aop管理事务的，我们试图改用手动管理事务：
a、使用了spring的TransactionTemplate，即在spring配置文件中配置一个TransactionTemplate的bean

{{{
<bean id=""transactionTemplate""  class=""org.springframework.transaction.support.TransactionTemplate"">  
		<property name=""transactionManager"" ref=""transactionManager"" />
	</bean>
	 <tx:annotation-driven transaction-manager=""transactionManager""/>

}}}

b、对定时任务的service方法加上去掉事务管理的注解
    @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=false)

c、通过 transactionTemplate方式手动控制提交事务
      

{{{
 Object object = transactionTemplate.execute(new TransactionCallback() {  
            public Object doInTransaction(TransactionStatus status) {  
                try {  
                    // 数据库操作 
                } catch (Exception e) {  
                    status.setRollbackOnly();  
                    e.printStackTrace();  
                }  
                return null;  
            }  
        });  


}}}


测试发现速度依旧很慢，最后抛相同的异常
尝试把控制事务提交的代码改成如下：

{{{
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
					def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
					def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

					if (isExists > 0) {// 更新
						TransactionStatus status = transactionManager
								.getTransaction(def);
						try {
							simpleJdbcTemplate.update(updSql, getRecordMap(rs));
							transactionManager.commit(status);
						} catch (Exception e) {
							transactionManager.rollback(status);
							e.printStackTrace();
					}

}}}


异常依旧在
期间，请DBA检查并没有发现慢的语句，但偶尔发现会锁表

3、估计在执行定时任务时，使用的是spring的SimpleJdbcTemplate，事务可能未提交，于是调整直接用jdbc来执行数据库操作
数据源用配置jndi的数据源，方法代码如下

{{{
	Context ctx = new InitialContext();
	ctx = new InitialContext();
	DataSource ds =(DataSource)ctx.lookup(""java:comp/env/jdbc/priceparity"");
	return  ds.getConnection();
}}}


采用jdbc执行一次提交一次事务： 
conn.setAutoCommit(false);
//执行
conn.commit();
但是执行速度越来越慢，执行时间成2倍数增长，最后达到约120秒每次， 线程卡死，并抛出异常：

{{{
 Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during commit(). 

Transaction resolution unknown.
}}}


4、因为spring配置service包下的类均会开启事务， 写在service包下的类会受到影响，而且数据的链接用的是jndi的配置，配有一定的活动链接数，在执

行时间较长的任务时，Connection可能被重置或关闭。
鉴于此，我们将定时任务的业务类写在另外一个包job下，连接数据库直接用jdbc的方式：

{{{
Class.forName(""com.mysql.jdbc.Driver"").newInstance();
String url=""jdbc:mysql://192.168.75.100:3315/priceparity_new?user=priceparity_app&password=priceparity_app"";
return DriverManager.getConnection(url);

}}}
每次执行insert和update后都提交事务
执行产品信息同步任务，发现不会卡死，每次执行时间为约为0.2秒，速度依旧慢，产品数据总量越有28万，但是能完成执行，不会抛出异常
将同步爬虫数据的定时任务也按照这种方法改造，执行速度可以约5毫秒每条。

问题的根本原因暂时未找到，初步判定原因
1、jndi方式的数据库连接在长时间内会被关闭或者回收
2、spring事务管理的配置引起
3、mysql数据库端的问题。

"	故障	new	major		比价	比价1.0		定时任务		27/09/2013
