mybatis_流式查询 Cursor 和 foreach 批量插入

一、流式查询

关于流式查询的内容在这篇文章里面

https://mp.weixin.qq.com/s/LtXPdM9OOSlGypqCd5Asmw

流式查询 cursor 就是让查询的速度加快。其使用也很简单,使用

org.apache.ibatis.cursor.Cursor

就可以了,具体的使用如下,比如普通的查询

@Select("select * from book limit #{limit}")
List<BookEntity> listBooksNormal(@Param("limit") Integer limit);

使用流式查询的话就改成

@Select("select * from book limit #{limit}")
Cursor<BookEntity> listBooks(@Param("limit") Integer limit);

其查询的效率明显提升,测试查询3000条数据,两种方法的时间分别为
在这里插入图片描述
但是使用流式查询的话,有一点是需要注意的,因为mybatis的查询是自动会把数据库连接关闭的,而使用流式查询的话是需要保持数据库一直连接。
根据上文文章的内容有三点解决方案

第一种:SqlSessionFactory

try (
        SqlSession sqlSession = sqlSessionFactory.openSession();  // 1
        Cursor<Foo> cursor =
              sqlSession.getMapper(FooMapper.class).scan(limit)   // 2
    ) {
        cursor.forEach(foo -> { });
    }

第二种:TransactionTemplate

TransactionTemplate transactionTemplate =
            new TransactionTemplate(transactionManager);  // 1

    transactionTemplate.execute(status -> {               // 2
        try (Cursor<Foo> cursor = fooMapper.scan(limit)) {
            cursor.forEach(foo -> { });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    });

第三种:@Transactional

	@Transactional
    @Test
    void contextLoads() {
        Integer limit = 30000;

        LocalTime begin = LocalTime.now();
        List<BookEntity> bookEntities = bookService.listBooksNormal(limit);
        LocalTime end = LocalTime.now();
        Duration between = Duration.between(begin, end);
        System.out.println("-------------------------- 普通查询 " + between.toMillis() + "ms ------------------------------");

        // 流式查询
        LocalTime begin1 = LocalTime.now();
        Cursor<BookEntity> bookEntities1 = bookService.listBooks(limit);
        LocalTime end1 = LocalTime.now();
        Duration between1 = Duration.between(begin1, end1);
        System.out.println("-------------------------- 流式查询 " + between1.toMillis() + "ms ------------------------------");

    }

二、foreach 批量插入

在要使用流式查询的时候数据存入数据库。写了两种插入方法,第一种是一次插入一个,然后循环调用,这个是十分耗时的,因为一直调用操作数据库代码;第二种是批量插入,使用 foreach 语句插入,先把 sql 语句封装好,然后再调用操作数据库的语句。
第一种方法

System.out.println("----------------------普通插入--------------------------");
LocalTime begin = LocalTime.now();
for (int i1 = 0; i1 <= 10000; i1++) {
     bookService.addBook(bookEntity);
}
LocalTime end = LocalTime.now();
Duration between = Duration.between(begin, end);
System.out.println("-------------------------- " + between.toMillis() + "ms ------------------------------");

第二种方法

ArrayList<BookEntity> bookEntities = new ArrayList<>();
for (int i = 0; i <= 10000; i++) {
    bookEntities.add(bookEntity);
}
System.out.println("----------------------优化插入--------------------------");
LocalTime begin1 = LocalTime.now();
int i = bookService.addBooks(bookEntities);
LocalTime end1 = LocalTime.now();
Duration between1 = Duration.between(begin1, end1);
System.out.println("-------------------------- " + between1.toMillis() + "ms ------------------------------");

sql 代码

<insert id="addBooks" parameterType="java.util.List">
    INSERT INTO book (bookName,bookCounts,detail)
    VALUES
    <foreach collection="bookEntities" item="book" separator=",">
        (#{book.bookName},#{book.bookCounts},#{book.detail})
    </foreach>
</insert>

两种方法的插入时间分别为
在这里插入图片描述
测试数据插入一万条数据,时间的差别是十分明显的。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
非常抱歉,我理解错误了你的问题。以下是一个在Service层使用MyBatis流式查询的示例代码,包括手动管理事务和使用`cursor.forEach`方法遍历游标的过程: ```java @Service public class UserServiceImpl implements UserService { @Autowired private SqlSessionTemplate sqlSessionTemplate; @Override @Transactional public void processUsersByAgeGreaterThan(int age) { try (SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); try (Cursor<User> cursor = userMapper.findUsersByAgeGreaterThan(age)) { cursor.forEach(user -> { // 处理每个用户 // ... }); } session.commit(); } } } ``` 在这个例子中,我们在Service层手动管理了事务,并使用了`SqlSessionTemplate`来获取`SqlSession`实例。在`processUsersByAgeGreaterThan`方法中,我们使用`try-with-resources`语句打开了一个新的`SqlSession`实例,并从中获取了`UserMapper`接口的实例。然后,我们使用`cursor.forEach`方法遍历游标,对于每个用户都进行了处理。最后,我们在事务提交之前调用了`session.commit()`方法。 注意:要使用MyBatis流式查询,你需要在Mapper接口中声明一个返回类型为`Cursor<T>`的方法。在这个例子中,我们假设`UserMapper`中有一个名为`findUsersByAgeGreaterThan`的方法,它返回年龄大于指定值的用户。另外,我们需要在Service层手动管理事务,并在使用完`SqlSession`实例后手动提交事务。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值