Mybatis批量操作解析

来源:游家吧
bumble最新官方版 v5.376.0

聊天交友 / 56.6m

查看

在项目中,批量操作是常见的需求,尤其是在处理大量数据时,如批量新增商户或批量修改商户信息。直接在java代码中通过循环发送sql到数据库执行是不切实际的,因为这意味着要与数据库建立数万次会话,即使在同一个连接中,也会存在重复编译和执行sql的开销。例如,循环插入10000条数据可能需要3秒钟。

在MyBatis中,可以轻松执行批量操作。只需提供包含多个数据对象的List、Set、Map或数组,然后使用动态SQL标签生成相应的SQL代码。这样可以显著提高效率,同时简化开发过程。

批量插入十分简便,只需在values后添加所需数据。在Mapper文件内使用foreach标签来拼接值段:

<insert id="insertBlogList" parametertype="java.util.List"> insert into blog (bid, name, author_id) values <foreach collection="list" index="index" item="blogs" separator=","> ( #{blogs.bid},#{blogs.name},#{blogs.authorId} ) </foreach> </insert>登录后复制

在Java代码中,直接传入一个List类型的参数:

/** * MyBatis 动态SQL批量插入 * @throws IOException */ @Test public void testInsert() throws IOException { long start = System.currentTimeMillis(); int count = 12000; List<Blog> list = new ArrayList<Blog>(); for (int i=2000; i<count+2000; i++) { Blog blog = new Blog(); blog.setBid(i); blog.setName("blog_" + i); blog.setAuthorId(i); list.add(blog); } blogMapper.insertBlogList(list); long end = System.currentTimeMillis(); System.out.println("耗时:" + (end - start) + " ms"); }登录后复制

只需几毫秒即可完成一万个记录的插入操作。相比频繁执行单独的SQL语句,动态SQL批量处理显著提升了数据导入速度。这种方法在减少与数据库的交互次数以及防止事务管理和开闭过程中不必要的延迟上表现尤为突出。

批量更新的语法是通过case when来匹配id相关的字段值。

在Mapper文件中,最关键的是case when和where的配置,需要注意open属性和separator属性。

<update id="updateBlogList"> update blog set name = <foreach close="end" collection="list" index="index" item="blogs" open="case bid" separator=" "> when #{blogs.bid} then #{blogs.name} </foreach> ,author_id = <foreach close="end" collection="list" index="index" item="blogs" open="case bid" separator=" "> when #{blogs.bid} then #{blogs.authorId} </foreach> where bid in <foreach close=")" collection="list" item="item" open="(" separator=","> #{item.bid,jdbcType=INTEGER} </foreach> </update>登录后复制

在Java代码中,传入一个List类型的参数:

/** * MyBatis 动态SQL批量更新 * @throws IOException */ @Test public void updateBlogList() throws IOException { long start = System.currentTimeMillis(); int count = 12000; List<Blog> list = new ArrayList<Blog>(); for (int i=2000; i<count+2000; i++) { Blog blog = new Blog(); blog.setBid(i); blog.setName("updated_blog_" + i); blog.setAuthorId(i+100); list.add(blog); } blogMapper.updateBlogList(list); long end = System.currentTimeMillis(); System.out.println("耗时:" + (end - start) + " ms"); }登录后复制

批量删除的语法与批量更新类似:

<delete id="deleteByList" parametertype="java.util.List"> delete from blog where bid in <foreach close=")" collection="list" item="item" open="(" separator=","> #{item.bid,jdbcType=INTEGER} </foreach> </delete>登录后复制

在Java代码中,传入一个List类型的参数:

/** * 动态SQL批量删除 * @throws IOException */ @Test public void testDelete() throws IOException { SqlSession session = sqlSessionFactory.openSession(); try { BlogMapper mapper = session.getMapper(BlogMapper.class); List<Blog> list = new ArrayList<Blog>(); Blog blog1 = new Blog(); blog1.setBid(666); list.add(blog1); Blog blog2 = new Blog(); blog2.setBid(777); list.add(blog2); mapper.deleteByList(list); } finally { session.close(); } }登录后复制

当然,MyBatis的动态标签批量操作也存在一些缺点。例如,当数据量特别庞大时,拼接出的SQL语句可能会变得异常长。MySQL服务端对接收的数据包有大小限制,默认为B。为了处理这种问题,需要调整默认配置或手动控制SQL条数来解决。

在我们的全局配置文件中,可以配置默认的Executor类型(默认是SIMPLE)。其中有一种BatchExecutor。

一共有三种Executor类型:

要区分三种类型的数据库执行器的区别,请查看`doUpdate`方法: SimpleExecutor:每次更新或查询时,都会开启一个新的Statement对象,并立即关闭它。 ReuseExecutor:当进行更新或查询操作时,会根据SQL语句查找预存在的Statement对象。如果存在,则使用;否则,创建新的Statement对象并用完后不再关闭它。简而言之,就是多次复用同一个Statement对象。 BatchExecutor:对于批量更新(不包含查询),将所有SQL语句添加到批处理中,在一次调用executeBatch时一次性执行这些sql。它会缓存多个Statement对象,每个在addBatch之后等待单独的executeBatch方法来完成。这一特性与JDBC的批处理方式相同。总之,这三种Executor类型分别通过开启、复用和批量执行来优化数据库操作性能。

`executeUpdate`处理单个SQL语句,而`executeBatch`批量处理多条SQL语句(取决于配置),并调用`addBatch`和`executeBatch`方法执行批量操作。`BatchExecutor`是JDBC底层实现中用于对`PreparedStatement.addBatch`和`executeBatch`进行封装的组件。

以上就是Mybatis批量操作解析的详细内容,更多请关注其它相关文章!

精品推荐