Mybatis批量操做與JDBC批量操做效率測試

Mybatis-spring配置文件java

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
	
	<!-- datasource -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
		init-method="init" destroy-method="close">
		<property name="url" value="${admin.datasource.url}" />
		<property name="username" value="${admin.datasource.username}" />
		<property name="password" value="${datasource.password}" />
		<property name="maxActive" value="${admin.datasource.maxActive}" />
		<property name="maxWait" value="${admin.datasource.maxWait}" />
		<property name="initialSize" value="1" />
		<property name="minIdle" value="1" />
		<property name="timeBetweenEvictionRunsMillis" value="3000" />
		<property name="minEvictableIdleTimeMillis" value="300000" />
		<property name="validationQuery" value="SELECT 'x'" />
		<property name="testWhileIdle" value="true" />
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
		<!-- <property name="poolPreparedStatements" value="false" /> -->
		<property name="maxPoolPreparedStatementPerConnectionSize"
			value="500" />
	</bean>
	<!-- sqlSessionFactory,mybatis -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!-- 生成的全部Mapper -->
		<property name="configLocation" value="classpath:application-entity.xml" />
		<!-- 自定義Mapper.xml -->
		<property name="mapperLocations">
			<list>
				<value>classpath:batchtest/*.xml</value>
			</list>
		</property>
		<!-- 掃描model包 -->
		<property name="typeAliasesPackage"
			value="com.momix.dbao.dao.entity,com.momix.heda.model.entity" />
		<property name="plugins"><!--分頁插件 -->
			<array>
				<bean class="com.github.pagehelper.PageHelper">
					<property name="properties">
						<value>
							dialect=mysql
							reasonable=true
						</value>
					</property>
				</bean>
			</array>
		</property>
	</bean>

	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory" />
	</bean>
	
	<!-- scann mapper -->
	<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.momix.dbao.dao.mapper,com.momix.heda.dao" />
		<property name="properties">
			<value>
				mappers=com.momix.dbao.dao.core.MyBatisBaseMapper
			</value>
		</property>
	</bean>
	
	<!-- transaction -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="get*" propagation="SUPPORTS" />
			<tx:method name="find*" propagation="SUPPORTS" />
			<tx:method name="create*" propagation="REQUIRED" read-only="false"
				rollback-for="java.lang.Exception" />
			<tx:method name="del*" propagation="REQUIRED" read-only="false"
				rollback-for="java.lang.Exception" />
			<tx:method name="update*" propagation="REQUIRED" read-only="false"
				rollback-for="java.lang.Exception" />
			<tx:method name="*" propagation="REQUIRED" read-only="false"
				rollback-for="java.lang.Exception" />
		</tx:attributes>
	</tx:advice>
	<aop:config proxy-target-class="true" expose-proxy="true">
		<aop:pointcut id="dbao"
			expression="execution(* com.momix.dbao.service..*(..))" />
		<aop:advisor pointcut-ref="dbao" advice-ref="txAdvice" />
	</aop:config>

	<!-- scan service -->
	<context:component-scan base-package="com.momix.dbao.service,com.momix.heda.service,com.momix.basedao,com.momix.dbao.dao.sqlxml">
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Controller" />
	</context:component-scan>
</beans>


Mybatis3批量插入
mysql


配置文件Sql語句:git

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.momix.dbao.dao.mapper.sqlxml.BatchTestMapper">
	 
	 <!-- 批量新增Sql -->
	 <insert id="batchInsert" parameterType="java.util.List">
	 	insert into batch_test (name,sex,birthday,mobile) values
	 	<foreach collection="list" item="item" index="index" separator="," >  
         	(#{item.name},#{item.sex},#{item.birthday},#{item.mobile}) 
   		</foreach>
	 </insert>
	 
	 <!-- 批量修改Sql -->
	 <update id="batchUpdate" parameterType="java.util.List">
	 	<foreach collection="list" item="item" index="index" open="" close="" separator=";">
			update batch_test set 
		 		name = #{item.name},sex = #{item.sex},birthday = #{item.birthday},mobile = #{item.mobile}
		 	where id = #{item.id}
	   </foreach>
	 </update>
	 
	 <select id="getCount" resultType="Integer">
	 	select count(*) from batch_test
	 </select>
	 
	 <delete id="deleteData">
	 	delete from batch_test
	 </delete>
</mapper>

Mapper方法:
github

package com.momix.dbao.dao.mapper.sqlxml;

import java.util.List;

import com.momix.dbao.dao.core.MyBatisBaseMapper;
import com.momix.dbao.dao.entity.sqlxml.BatchTest;

public interface BatchTestMapper extends MyBatisBaseMapper<BatchTest> {

	/**
	 * 批量插入方法
	 * 
	 * @param params
	 *            插入集合
	 */
	void batchInsert(List<BatchTest> params);

	/**
	 * 批量修改方法
	 * 
	 * @param params
	 *            修改集合
	 */
	void batchUpdate(List<BatchTest> params);

	/**
	 * 刪除數據
	 * 
	 * @return 刪除行數
	 */
	int deleteData();

	/**
	 * 獲取數據庫全部行數
	 */
	int getCount();

}


測試代碼:spring

採用TestNG進行測試sql

package com.momix.test.batch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import com.momix.dbao.dao.dto.sqlxml.BatchTestDTO;
import com.momix.dbao.dao.entity.sqlxml.BatchTest;
import com.momix.dbao.dao.mapper.sqlxml.BatchTestMapper;
import com.momix.dbao.service.test.TestOneService;

@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class BatchTestMain extends AbstractTestNGSpringContextTests {

	@Autowired
	private TestOneService testOneService;

	@Autowired
	private BatchTestMapper batchTestMapper;

	private List<BatchTest> paramsMapper;

	// 每次測試插入行數
	int size = 0;
	// 全部測試案例
	List<Integer> sizes = new ArrayList<Integer>();

	@BeforeTest
	public void initData() {
		sizes.add(100);
		sizes.add(300);
		sizes.add(500);
		sizes.add(800);
		sizes.add(1000);
		sizes.add(1500);
		sizes.add(2000);
		sizes.add(3000);
		sizes.add(5000);
		sizes.add(8000);
		sizes.add(10000);
		sizes.add(30000);
		sizes.add(50000);
		sizes.add(100000);
	}


	public void printData(List<Map<String, Long>> infos) {
		System.out
				.println("***********************************************************************");
		for (int i = 0; i < infos.size(); i++) {
			Map<String, Long> info = infos.get(i);
			System.out.println("測試插入行數 : " + info.get("a") + "   實際插入行數: "
					+ info.get("b") + "  刪除行數 : " + info.get("d") + "  耗時 : "
					+ info.get("c"));
		}
		System.out
				.println("***********************************************************************");
	}

	@Test(enabled = true)
	public void testBatchInsertMapper() {
		List<Map<String, Long>> infos = new ArrayList<Map<String, Long>>();
		try {
			long start = 0l;
			long end = 0l;
			int b = 0;
			int d = 0;
			Map<String, Long> info = null;
			for (int i = 0; i < sizes.size(); i++) {
				info = new HashMap<String, Long>();
				// 當前插入行數
				size = sizes.get(i);
				// 當前測試插入數據
				paramsMapper = this.getDataMapper();
				System.out.println(paramsMapper.size());
				// 開始時間
				start = System.currentTimeMillis();
				// 批量插入開始
				testOneService.batchTestInsertMapper(paramsMapper);
				// 結束時間
				end = System.currentTimeMillis();

				b = batchTestMapper.getCount();

				d = batchTestMapper.deleteData();

				info.put("a", (long) size); // 應當插入行數
				info.put("b", (long) b);// 實際插入行數
				info.put("c", (end - start)); // 耗時
				info.put("d", (long) d); // 刪除行數

				infos.add(info);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		
		printData(infos);
	}

	private List<BatchTest> getDataMapper() {
		List<BatchTest> tests = new ArrayList<BatchTest>();

		BatchTest test = null;
		for (int i = 0; i < size; i++) {
			test = new BatchTest();
			test.setName(String.valueOf(i));
			test.setSex(0);
			tests.add(test);
		}

		return tests;
	}

}


經過org.mybatis.spring.SqlSessionTemplate進行批量操做,分步提交數據庫


Sql配置文件express

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.momix.dbao.dao.dto.sqlxml.BathcTest">
	 
	 <!-- 批量新增Sql -->
	 <insert id="batchInsertBatchTest" useGeneratedKeys="true" keyProperty="id" parameterType="com.momix.dbao.dao.dto.sqlxml.BatchTestDTO">
	 	insert into batch_test (name,sex,birthday,mobile)
	 		values (#{name},#{sex},#{birthday},#{mobile})
	 </insert>
	 
	 <!-- 批量修改Sql -->
	 <insert id="batchUpdateBatchTest" parameterType="com.momix.dbao.dao.dto.sqlxml.BatchTestDTO">
	 	update batch_test set 
	 		name = #{name},sex = #{sex},birthday = #{birthday},mobile = #{mobile}
	 	where id = #{id}
	 </insert>
	 
</mapper>


底層代碼:apache

BaseDao代碼緩存

package com.momix.basedao;

import java.util.List;

import javax.annotation.Resource;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;

public abstract class BaseDao<O> {

	@Resource
	private SqlSessionTemplate sqlSessionTemplate;
	
	/**
	 * 獲取當前xml的namespace
	 * @return String
	 */
	protected abstract String getNameSpace();

	/**
	 * 批量修改 分步提交
	 * 
	 * @param statementName
	 *            ID
	 * @param data
	 *            數據集合
	 */
	protected void batchUpdate(String statementName, List<O> data) {
		// 當前方法沒有用Spring事務
		SqlSession session = sqlSessionTemplate.getSqlSessionFactory()
				.openSession();
		try {
			int size = data.size();
			for (int i = 0; i < size; i++) {
				O param = data.get(i);
				session.update(getNameSpace() + "." + statementName, param);
				if (size % 100 == 0) {
					// 每200條提交
					session.commit();
					// 清楚緩存,防止溢出
					session.clearCache();
				}
			}
		} catch (Exception e) {
			// 出現異常,回滾尚未提交的數據
			session.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}

	}

	/**
	 * 批量插入 分步提交
	 * 
	 * @param statementName
	 *            ID
	 * @param data
	 *            數據集合
	 */
	protected void batchInsert(String statementName, List<O> data) {
		// 當前方法沒有用Spring事務
		SqlSession session = sqlSessionTemplate.getSqlSessionFactory()
				.openSession();
		try {
			int size = data.size();
			for (int i = 0; i < size; i++) {
				O param = data.get(i);
				session.update(getNameSpace() + "." + statementName, param);
				if (size % 100 == 0) {
					// 每200條提交
					session.commit();
					// 清楚緩存,防止溢出
					session.clearCache();
				}
			}
		} catch (Exception e) {
			// 出現異常,回滾尚未提交的數據
			session.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}
}


Dao代碼:

package com.momix.dbao.dao.sqlxml;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.momix.basedao.BaseDao;
import com.momix.dbao.dao.dto.sqlxml.BatchTestDTO;

@Repository
public class BatchTestDao extends BaseDao<BatchTestDTO> {

	@Override
	protected String getNameSpace() {
		return "com.momix.dbao.dao.dto.sqlxml.BathcTest";
	}

	public void batchInsert(List<BatchTestDTO> params) {
		super.batchInsert("batchInsertBatchTest", params);
	}

	public void batchUpdate(List<BatchTestDTO> params) {
		super.batchUpdate("batchUpdateBatchTest", params);
	}

}


測試代碼:

package com.momix.test.batch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import com.momix.dbao.dao.dto.sqlxml.BatchTestDTO;
import com.momix.dbao.dao.entity.sqlxml.BatchTest;
import com.momix.dbao.dao.mapper.sqlxml.BatchTestMapper;
import com.momix.dbao.service.test.TestOneService;

@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class BatchTestMain extends AbstractTestNGSpringContextTests {

	@Autowired
	private TestOneService testOneService;

	@Autowired
	private BatchTestMapper batchTestMapper;

	private List<BatchTestDTO> paramsDao;

	// 每次測試插入行數
	int size = 0;
	// 全部測試案例
	List<Integer> sizes = new ArrayList<Integer>();

	@BeforeTest
	public void initData() {
		sizes.add(100);
		sizes.add(300);
		sizes.add(500);
		sizes.add(800);
		sizes.add(1000);
		sizes.add(1500);
		sizes.add(2000);
		sizes.add(3000);
		sizes.add(5000);
		sizes.add(8000);
		sizes.add(10000);
		sizes.add(30000);
		sizes.add(50000);
		sizes.add(100000);
	}

	@Test(enabled = false)
	public void testBatchInsertDao() {
		long start = 0l;
		long end = 0l;
		int b = 0;
		int d = 0;
		List<Map<String, Long>> infos = new ArrayList<Map<String, Long>>();
		Map<String, Long> info = null;
		for (int i = 0; i < sizes.size(); i++) {
			info = new HashMap<String, Long>();
			// 當前插入行數
			size = sizes.get(i);
			// 當前測試插入數據
			paramsDao = this.getDataDao();
			// 開始時間
			start = System.currentTimeMillis();
			// 批量插入開始
			testOneService.batchTestInsertDao(paramsDao);
			// 結束時間
			end = System.currentTimeMillis();

			b = batchTestMapper.getCount();

			d = batchTestMapper.deleteData();

			info.put("a", (long) size); // 應當插入行數
			info.put("b", (long) b);// 實際插入行數
			info.put("c", (end - start)); // 耗時
			info.put("d", (long) d); // 刪除行數

			infos.add(info);
		}

		printData(infos);
	}

	public void printData(List<Map<String, Long>> infos) {
		System.out
				.println("***********************************************************************");
		for (int i = 0; i < infos.size(); i++) {
			Map<String, Long> info = infos.get(i);
			System.out.println("測試插入行數 : " + info.get("a") + "   實際插入行數: "
					+ info.get("b") + "  刪除行數 : " + info.get("d") + "  耗時 : "
					+ info.get("c"));
		}
		System.out
				.println("***********************************************************************");
	}

	private List<BatchTestDTO> getDataDao() {
		List<BatchTestDTO> tests = new ArrayList<BatchTestDTO>();

		BatchTestDTO test = null;
		for (int i = 0; i < size; i++) {
			test = new BatchTestDTO();
			test.setName(String.valueOf(i));
			test.setSex(0);
			tests.add(test);
		}

		return tests;
	}
}


測試結果:

wKioL1dp8nDQ-sQHAABl13-iRvs249.png

總結:

  1. 經過jdbc循環分步提交,耗時較長,但比較穩定。

  2. 經過Mybatis用foreach進行批量操做,耗時較短,但數據量過大會出現異常

  3. 選擇哪一種方式,只能視業務場景而定。

相關文章
相關標籤/搜索