本文源码地址: 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());
}