MyBatis实现MySql的批量插入,以及flushCache、useCache的配置

  • 上次遇到一个插入效率的问题,同一个事务下,插入1000条数据,主键为递增序列,下面演示:

1、新增两张表

  • 记录序列表
CREATE TABLE `sequence`  (
 `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `current_value` int(11) NOT NULL,
 `increment_value` int(11) NOT NULL DEFAULT 1,
 PRIMARY KEY (`name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
  • 测试插入记录表
CREATE TABLE `test_batch`  (
  `ID` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `NAME` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `GMT_CREATE` timestamp(0) NULL DEFAULT NULL,
  PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  • 自定义MySql的主键增长,通过函数来写:
CREATE DEFINER=`goms`@`%` FUNCTION `currval`(seq_name VARCHAR(50)) RETURNS int(11)
BEGIN
	 DECLARE VALUE INTEGER;
	  SET VALUE = 0;
	  SELECT current_value INTO VALUE
	  FROM sequence
	  WHERE NAME = seq_name;
	  RETURN VALUE;
    END
CREATE DEFINER=`goms`@`%` FUNCTION `nextval`(seq_name VARCHAR(50)) RETURNS int(11)
BEGIN
	   UPDATE  sequence
	   SET  current_value = CASE current_value WHEN 999999999 THEN 100000000 ELSE current_value + increment_value END
	   WHERE NAME = seq_name;
	   RETURN currval(seq_name);
END

2、搭建测试项目

  • 在此不多说,这是我平时写demo的一个项目
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3、基础代码

public interface GomsSequenceMapper {
	long getSeq4ID();
}
<?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="org.tools.dao.test.GomsSequenceMapper">

<!-- flushCache="true" useCache="false" -->
	<select id="getSeq4ID" resultType="java.lang.Long" >
		SELECT nextval('SEQ_ID');
	</select>
</mapper>
public interface TestBatchMapper {
  int insertSelective(TestBatch record);
  void insertBatch(List<TestBatch> list);
}
public class TestBatch {
    private String id;

    private String name;

    private Date gmtCreate;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id == null ? null : id.trim();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public Date getGmtCreate() {
        return gmtCreate;
    }

    public void setGmtCreate(Date gmtCreate) {
        this.gmtCreate = gmtCreate;
    }
}
<?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="org.tools.dao.test.TestBatchMapper" >
  <resultMap id="BaseResultMap" type="org.tools.domain.order.dto.TestBatch" >
    <id column="ID" property="id" jdbcType="VARCHAR" />
    <result column="NAME" property="name" jdbcType="VARCHAR" />
    <result column="GMT_CREATE" property="gmtCreate" jdbcType="TIMESTAMP" />
  </resultMap>

 <insert id="insertSelective" parameterType="org.tools.domain.order.dto.TestBatch" >
    insert into test_batch
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        ID,
      </if>
      <if test="name != null" >
        NAME,
      </if>
      <if test="gmtCreate != null" >
        GMT_CREATE,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=VARCHAR},
      </if>
      <if test="name != null" >
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="gmtCreate != null" >
        #{gmtCreate,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>

<!-- 批量插入数据 -->
	<insert id="insertBatch" parameterType="java.util.List" >
		insert into test_batch (ID, NAME, GMT_CREATE)
		values 
	    <foreach collection="list" item="item" index="" separator=",">   
			(#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, NOW())
	    </foreach>
	</insert>
 
</mapper>

4、进入主题

@Service
public class TestBatchInsert {

	@Autowired
	private GomsSequenceMapper gomsSequenceDAO;
	
	@Autowired
	private TestBatchMapper testBatchMapper;

	final class Interval{
		public long start;
		public long end;
		public long interval;
	}
	

	@Transactional
	public void test1() {
		try {
			Interval timeout = new Interval();
			timeout.start = System.currentTimeMillis();
			System.err.println(new Date(timeout.start));
			for (int i = 0 ; i < 100; i++) {
				long id = gomsSequenceDAO.getSeq4ID();
				
				TestBatch test = new TestBatch();
				test.setId(id+"");
				test.setName(id+"----");
				
				testBatchMapper.insertSelective(test);
			}
			timeout.end = System.currentTimeMillis();
			timeout.interval = timeout.end-timeout.start;
			System.err.println(String.valueOf(timeout.interval));
			System.err.println(new Date(timeout.end));
		} catch (Exception e) {
			e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
	}

@Transactional
	public void test2() {
		try {
			Interval timeout = new Interval();
			timeout.start = System.currentTimeMillis();
			System.err.println(new Date(timeout.start));
			List<TestBatch> lists = new ArrayList<TestBatch>();
			
			for (int i = 0 ; i < 100; i++) {
				long id = gomsSequenceDAO.getSeq4ID();
				
				TestBatch test = new TestBatch();
				test.setId(id+"");
				test.setName(id+"----");
				
				lists.add(test);
			}
			testBatchMapper.insertBatch(lists);
			timeout.end = System.currentTimeMillis();
			timeout.interval = timeout.end-timeout.start;
			System.err.println(String.valueOf(timeout.interval));
			System.err.println(new Date(timeout.end));
		} catch (Exception e) {
			e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
	}
}

- 执行junittest:
在这里插入图片描述
执行test1,大家注意这个是注释的:
在这里插入图片描述
在这里插入图片描述
Tue Oct 15 15:36:31 CST 2019
168
Tue Oct 15 15:36:31 CST 2019
- 执行test2:
在这里插入图片描述
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException就是违反数据库完整性约束

  • 在MyBatis中有flushCache、useCache这两个配置属性,分为下面几种情况:
    (1)当为select语句时:
    flushCache默认为false,表示任何时候语句被调用,都不会去清空本地缓存和二级缓存。
    useCache默认为true,表示会将本条语句的结果进行二级缓存。
    (2)当为insert、update、delete语句时:
    flushCache默认为true,表示任何时候语句被调用,都会导致本地缓存和二级缓存被清空。
    useCache属性在该情况下没有。
  • 我们来改下xml,不缓存,flushCache=“true”, useCache=“false”
    在这里插入图片描述
    在这里插入图片描述
    Tue Oct 15 15:35:29 CST 2019
    126
    Tue Oct 15 15:35:29 CST 2019
  • 结果很明显,一条一条插入使用了168ms,而批量插入用了126ms。
  • 关注公众号"双城人",搬砖过程遇到的问题,大家一起探讨,资源共享
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于MybatisMySQL批量插入批量更新,可以使用以下方法: 1. 批量插入 使用MyBatis的foreach标签,可以很方便地实现批量插入操作。示例如下: ```xml <insert id="batchInsert" parameterType="java.util.List"> insert into my_table (col1, col2, col3) values <foreach collection="list" item="item" separator=","> (#{item.col1}, #{item.col2}, #{item.col3}) </foreach> </insert> ``` 其中,parameterType指定参数类型为List,collection属性指定要插入的List对象,item指定List中的元素,separator指定分隔符。 在Java代码中,调用该方法时,将List对象作为参数传入即可。 2. 批量更新 对于批量更新,可以使用MySQL的replace into语句来实现。示例如下: ```xml <update id="batchUpdate" parameterType="java.util.List"> <foreach collection="list" item="item" separator=";"> replace into my_table (id, col1, col2, col3) values (#{item.id}, #{item.col1}, #{item.col2}, #{item.col3}) </foreach> </update> ``` 其中,replace into语句会先尝试插入记录,如果记录已存在,则更新记录。参数类型和调用方式与批量插入相同。 3. 存在即更新 如果只想更新已存在的记录,可以使用MySQL的on duplicate key update语句。示例如下: ```xml <update id="updateIfExists" parameterType="com.example.MyEntity"> insert into my_table (id, col1, col2, col3) values (#{id}, #{col1}, #{col2}, #{col3}) on duplicate key update col1 = values(col1), col2 = values(col2), col3 = values(col3) </update> ``` 其中,id字段为主键。如果该记录已存在,则更新col1、col2、col3字段;否则插入新记录。参数类型为MyEntity,调用方式为传入一个MyEntity对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值