【Mybatis知识点整理】--- foreach标签+批量插入的两种实现方式


本文源码地址: https://github.com/nieandsun/NRSC-STUDY


1 foreach标签

foreach标签有五个元素
collection — 要遍历的集合的名称,注意:该名称必须要用@Param注解进行标注
item — 遍历集合过程中每一个元素的临时名称,可填任意变量名
open — item前面要加的内容
close — item后面要加的内容
separator — 每个元素(这里的元素指的是一次循环中open,item,close对应的值组成的一个整体)之间使用的分隔符

示例如下:

 <select id="findAllUserByIdIn" resultType="TUser">
     SELECT * FROM t_user WHERE id IN
     <foreach collection="ids" item="item" open="(" close=")" separator=",">
         #{item}
     </foreach>
 </select>

注意: — 看如下截图,来自于阿里巴巴《java开发手册(华山版)》
在这里插入图片描述
前段时间工作中遇到一个问题,有个同事在使用foreach 进行in操作查询时,由于in后面集合元素数量过大,导致内存一直无法释放。

具体原因可能需要去阅读mybatis的源码 —》这里埋个点,我会在不久的将来通过阅读源码来寻找一下答案。


2 批量插入

2.1 使用foreach标签

mysql可以按照如下语句进行批量插入多条数据

INSERT INTO t_user (
	username,
	PASSWORD,
	gender,
	salary
)
VALUES
	('wangwu', '1111', 'F', 3900),
	('guoer', '2222', 'M', 4900)

因此我们可以按照如下格式利用foreach标签进行拼接sql语句:

<insert id="batchSaveTUser" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO t_user(username, password, gender, salary) VALUES
    <foreach collection="collection" item="item" separator=",">
        (#{item.username}, #{item.password}, #{item.gender}, #{item.salary})
    </foreach>
</insert>

2.2 关闭session自动提交的方式

大数据量插入或更新是主要耗时在session的频繁开启,
因此可以利用先关闭session的自动提交
"攒"一些命令然后进行session提交的方式进行数据的批量插入或更新等操作
JDBC规范里规定是可以这样做的,其实现方式如下:

package com.nrsc.mybatis.controller;

import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;

class UserControllerTest {
    static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/nrsc-mybatis?characterEncoding=utf-8&serverTimezone=GMT&useSSL=false";

    // Database credentials
    static final String USER = "root";
    static final String PASS = "123456";

    @Test
    public void updateDemo() {
        Connection conn = null;
        Statement stmt = null;
        try {
            // STEP 1: 注册mysql的驱动
            Class.forName(JDBC_DRIVER);

            // STEP 2: 获得一个连接
            System.out.println("Connecting to database...");
            conn = DriverManager.getConnection(DB_URL, USER, PASS);

            // STEP 3: 关闭自动提交
            conn.setAutoCommit(false);
            stmt = conn.createStatement();

            // STEP 4: 创建一个更新
            System.out.println("Creating statement...");
            String sql1 = "update t_user  set username= '帅帅' where id= '1' ";
            String sql2 = "insert into t_user ( username) values ('deer')";
            stmt.addBatch(sql1);
            stmt.addBatch(sql2);
            System.out.println(stmt.toString());//打印sql
            int[] executeBatch = stmt.executeBatch();
            System.out.println("此次修改影响数据库的行数为:" + Arrays.toString(executeBatch));

            // STEP 5: 手动提交数据 ---> 真正开始对数据库发出指令
            conn.commit();

            // STEP 6: 关闭连接
            stmt.close();
            conn.close();
        } catch (SQLException se) {
            // Handle errors for JDBC
            try {
                conn.rollback();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            se.printStackTrace();
        } catch (Exception e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            // finally block used to close resources
            try {
                if (stmt != null)
                    stmt.close();
            } catch (SQLException se2) {
            }// nothing we can do
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
    }
}

springboot + mybatis实现代码
主要分为如下六步:

 /***
  *大数据量插入主要耗时在session的频繁开启,
  * 因此可以先关闭session的自动提交----》"攒"一些命令然后进行session提交的方式进行数据的批量插入或更新等操作
  * @return
  */
 /***
  * (1)注入SqlSessionTemplate
  */
 @Autowired
 private SqlSessionTemplate sqlSessionTemplate;

 @GetMapping("batchSaveTUser2")
 public void batchSaveTUser2() {
     //(2)关闭session的自动提交
     SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
     //(3)获取到mapper对象
     TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);

     //(4)进行数据插入或更新等操作
     TUser user1 = new TUser();
     user1.setUsername("king11");
     user1.setPassword("1234567");
     user1.setGender("F");
     user1.setSalary(new BigDecimal(1800));
     //插入1
     int insert = mapper.insert(user1);

     TUser user2 = new TUser();
     user2.setUsername("james11");
     user2.setPassword("123456789011");
     user2.setGender("M");
     user2.setSalary(new BigDecimal(1800));

     //插入2
     int insert1 = mapper.insert(user2);

     //(5)提交session
     sqlSession.commit();
     //(6)关闭session连接
     sqlSession.close();
     System.out.println("------获取批量更新后数据的主键--------");
     System.err.println(user1.getId());
     System.err.println(user2.getId());
 }
发布了189 篇原创文章 · 获赞 187 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/102885479
今日推荐