spring+ibatis批处理解决

阅读更多
为了实现日志批处理提交,这几天详细研究了ibatis的事务和批处理。

直接上代码,然后说结论吧。spring版本3.1 + ibatis2.3.4

配置

		
		
	
	
	
		
	

	
	

	
	
		
	


java代码:
/***
	 * ibatis的批处理必须放在事务内,此处事务的作用只是起着开启批处理的作用, 实际上每个sql一个事务
	 * 目的:使用批处理,而不使用事务,故选择此方法
	 * 
	 */
	public void batchSave(Queue logQueue) {
		if (logQueue == null)
			return;
		long startTime = System.currentTimeMillis();
		int queueSize = logQueue.size();
		if (queueSize == 0)
			return;

		SqlMapClientTemplate sqlMapClientTemplate = getSqlMapClientTemplate();
		SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();
		try {
			sqlMapClient.startTransaction();
			sqlMapClient.startBatch();

			int insertNum = 0;
			for (int i = 0; i < queueSize; i++) {
				BaseLog log = logQueue.poll();
				if (log == null)
					break;
				insertNum++;
				String saveMethod = "insert" + log.getClass().getSimpleName();
				sqlMapClient.insert(saveMethod, log);
				if (insertNum % BATCH_SIZE == 0) {
					sqlMapClient.executeBatch();

					sqlMapClient.startBatch();
				}
			}

			sqlMapClient.executeBatch();
			sqlMapClient.commitTransaction();
			long logTime = System.currentTimeMillis() - startTime;
			logger.info("[记录日志] [大小:" + insertNum + "] [时间:" + logTime
					+ "] [succ]");
		} catch (SQLException e) {
			logger.error("[记录日志] [fail]", e);
		} finally {
			try {
				sqlMapClient.endTransaction();
			} catch (SQLException e) {
				logger.error("[EndLogTransaction] [error]", e);
			}
		}
	}

	/**
	 * spring首选批处理提交方式,失败的话,会自动回滚
	 * 
	 * @param logQueue
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Transactional(value = "log.transactionManager")
	public void batchSaveX(final Queue logQueue) {
		// 执行回调
		getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
			// 实现回调接口
			public Object doInSqlMapClient(SqlMapExecutor executor)
					throws SQLException {
				int queueSize = logQueue.size();
				if (queueSize == 0)
					return 0;

				long startTime = System.currentTimeMillis();
				int count = 0, total = 0;
				// 开始批处理
				executor.startBatch();
				for (int i = 0; i < queueSize; i++) {
					BaseLog baseLog = logQueue.poll();
					// 插入操作
					String saveMethod = "insert"
							+ baseLog.getClass().getSimpleName();
					executor.insert(saveMethod, baseLog);
					count++;
					if (count % BATCH_SIZE == 0) {
						total += executor.executeBatch();
						executor.startBatch();
					}

				}
				// 执行批处理
				total += executor.executeBatch();

				long logTime = System.currentTimeMillis() - startTime;
				logger.info("[记录日志2] [大小:" + total + "] [时间:" + logTime
						+ "] [succ]");
				return new Integer(total);
			}
		});
	}


总结: 上面第一种方式中的事务,只起着开启批处理的作用,没有其他作用。另外网上有人推荐在第一种方法上添加@Transational来开启事务,这种方法能开启事务,的确能打开事务,但是没批处理,主要是spring接管的事务会话,不能自己操作的sqlMapClient很好的衔接起来。同时事务侵入代码+不能回滚,所以要是采用事务的话,还是不要采用这种方法。要
采用事务的话,最好采用上面第二方法。

log4j配置文件,方便前端监控,事务和批处理的情况
	
		
	

	
		
	
	
	
		
	


数据库端,采用mysql的话可以mysqlbinlog查看二进制日志查看事务提交情况,bingin...commit代表一个事务

你可能感兴趣的:(spring+ibaits,事务,批处理)