`
pcpig
  • 浏览: 90931 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

spring+ibatis批处理解决

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

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

配置
<bean id="log.sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="configLocation"
			value="classpath:config/db/ibatis/log-sqlmap-config.xml" />
		<property name="dataSource" ref="log.dataSource" />
	</bean>
	
	<bean id="log.transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="log.dataSource" />
	</bean>

	<!-- enable transaction demarcation with annotations -->
	<tx:annotation-driven />

	<!-- DAO配置 -->
	<bean id="logDAO" class="com.X.LogDAO">
		<property name="sqlMapClient" ref="log.sqlMapClient" />
	</bean>


java代码:
/***
	 * ibatis的批处理必须放在事务内,此处事务的作用只是起着开启批处理的作用, 实际上每个sql一个事务
	 * 目的:使用批处理,而不使用事务,故选择此方法
	 * 
	 */
	public void batchSave(Queue<BaseLog> 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<BaseLog> 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配置文件,方便前端监控,事务和批处理的情况
	<logger name="java.sql">
		<level value="debug" />
	</logger>

	<logger name="org.springframework.orm">
		<level value="debug" />
	</logger>
	
	<logger name="org.springframework.jdbc">
		<level value="debug" />
	</logger>


数据库端,采用mysql的话可以mysqlbinlog查看二进制日志查看事务提交情况,bingin...commit代表一个事务
分享到:
评论
1 楼 pcpig 2013-04-06  
上面第一种方法有问题,第二种方法才是正确的。
第一种方法,上线后很快就导致数据库连接被关闭,抛出如下异常
--- Check the statement or the result map.  
--- Cause: java.sql.SQLException: Connection has already been closed.
        at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:107)
        at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.insert(SqlMapExecutorDelegate.java:393)
        at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.insert(SqlMapSessionImpl.java:82)
        at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.insert(SqlMapClientImpl.java:58)


而第二种方法,上线后表现很不错,不仅运行很正常,而且性能也比第一种好。

ps:保留错误的方法,权当给大家提个醒。另外事务没有想象中那么耗性能,凡事还是要亲自动手尝试一下才有确切的体会。

相关推荐

    ibatis 完美例子 一对多 批处理 事务 和 spring struts2集成

    本文将深入探讨如何利用Ibatis实现一对多关系、批处理、事务管理和与Spring及Struts2的集成。 首先,让我们来看一下“一对多”关系。在数据库设计中,一对多关系很常见,比如一个用户可以有多个订单。在Ibatis中,...

    ibatis批处理.doc

    尽管Spring已经配置了事务管理,但在实际使用iBATIS批处理时,仍需要在代码中显式地开启和提交事务。这是因为iBATIS的批处理需要在一个事务内执行,才能确保所有操作作为一个整体执行。例如,下面的代码展示了如何在...

    ibatis的两种方式实现批处理.doc

    iBatis批处理实现方式浅析 iBatis是一个功能强大的持久层框架,提供了多种方式来实现批处理操作。批处理是指将多个SQL语句组合成一个批处理单元,然后将其执行到数据库中,以提高数据库操作的效率。在iBatis中,...

    SpringBatch批处理 刘相编

    基本篇重点讲述了数据批处理的核心概念、典型的作业配置、作业步配置,以及Spring Batch框架中经典的三步走策略:数据读、数据处理和数据写,详尽地介绍了如何对CVS格式文件、JSON格式文件、XML文件、数据库和JMS...

    Spring iBatis Learning Notes

    2. **批处理操作**:对于大量数据的操作,Spring JDBC支持提供了批处理的功能,可以极大地提高效率。 3. **参数绑定**:使用Spring JDBC支持时,可以直接绑定Java对象作为SQL语句的参数,无需手动转换类型。 #### ...

    ibatis批量处理

    除了上面提到的方法,还可以采用Spring的模板模式来处理iBatis的批处理操作。这种方式允许你在一个事务内执行多个操作,并将具体的逻辑封装在一个回调函数中。 示例代码如下: ```java public void create(List...

    axis2 ibatis spring简单资料

    8. **Hibernate 配置**:虽然主要讨论的是 Axis2、iBatis 和 Spring,但文件中还提到了 Hibernate 的配置,如 dialect(数据库方言)、jdbc 的批处理大小和获取数据的大小、是否显示 SQL 语句以及自动更新数据库结构...

    iBATIS&Spring合奏(一)--DAO

    9. **性能优化**:讨论如何通过缓存、批处理等手段优化iBATIS和Spring的性能。 10. **总结与展望**:总结整合iBATIS和Spring的优势,以及可能遇到的问题,为读者提供进一步学习和实践的建议。 虽然压缩包文件名...

    ibatis api,ibatis文档,ibatis说明文档

    Ibatis文档是学习和解决问题的重要资源,它包含了详细的API参考、配置指南、最佳实践和常见问题解答。通过阅读文档,你可以了解如何配置Ibatis、创建Mapper接口和XML映射文件,以及如何处理复杂的查询和关联。 在...

    iBATIS-SqlMaps中文教程集合

    在“iBATIS-SqlMaps中文教程集合”中,你将找到四本深入浅出的教程,这些教程涵盖了iBATIS的基础使用、高级特性和实战案例,帮助开发者快速掌握并熟练运用iBATIS解决项目中的实际问题。 1. **基础篇** - iBATIS...

    ibatis jar包.zip

    8. **与其他框架集成**:iBATIS可以很好地与Spring框架集成,提供更完整的应用程序上下文管理和AOP(面向切面编程)支持。 9. **性能优化**:通过预编译SQL语句、批处理等技术,iBATIS能够有效地提高数据库操作的性能...

    ibatis资料(官方文档)

    Spring的MyBatis-Spring模块提供了对Ibatis的全面支持,包括事务管理。 通过阅读和理解Ibatis的官方文档,开发者可以掌握如何有效地使用Ibatis来构建高效、可维护的数据访问层。这份文档详细解释了每个组件的功能和...

    ibatis 中文手册

    Ibatis 可以很好地与 Spring 框架集成,通过 Spring 的事务管理、AOP 代理等特性,进一步简化开发工作。 综上所述,Ibatis 中文手册涵盖了 Ibatis 的基本概念、核心功能以及最佳实践,是学习和掌握这一框架不可或缺...

    iBATIS_DAO-2.2.0.638

    iBATIS DAO是Java开发中的一个关键组件,它在企业级应用中被广泛...同时,由于iBATIS与Spring框架的良好整合,使得在Spring环境下使用iBATIS变得更加便捷,可以实现依赖注入和AOP切面编程,进一步提升开发的灵活性。

    ibatis框架源码剖析光盘资料

    同时,它支持Spring的事务管理,可以无缝集成到Spring应用中。 总的来说,ibatis框架源码的学习不仅可以帮助我们理解其工作原理,提升开发效率,还能为我们提供一种思考问题的角度,理解数据访问层的设计模式。通过...

    ibatis的3个jar包.rar

    在使用Ibatis时,开发者可以根据项目的规模和需求选择不同的集成方式,如Spring框架中的Ibatis整合,实现更高级的事务管理和依赖注入。 总的来说,这三者构成了Ibatis的基本运行环境,对于理解Ibatis的工作原理和...

    iBatis 轻量级持久层架构

    在Spring框架中嵌入iBatis,可以利用Spring的依赖注入(DI)和面向切面编程(AOP)能力,简化数据访问层的管理。集成iBatis的主要步骤包括配置SqlSessionFactoryBean,定义DataSource,以及将DAO接口与XML映射文件...

    ibatis N+1问题

    总之,理解和解决"Ibatis N+1问题"对于优化数据库性能至关重要。开发人员应当在设计和编码阶段就考虑到这个问题,以确保系统的高效运行。通过学习和实践,我们可以更好地掌握MyBatis的使用,提升我们的开发技能。

    spring面试题.doc

    7. **Spring与Ibatis整合**:整合过程通常涉及配置Spring的XML文件,定义SqlSessionFactory,配置数据源,以及配置Mapper接口和XML映射文件。 8. **声明式事务管理**:Spring通过`&lt;tx:annotation-driven&gt;`标签启用...

Global site tag (gtag.js) - Google Analytics