业务中多条sql语句一起执行十分常见。今天我们介绍三种方式来完成批量操作sql语句。
在原生的JDBC中Statement,PreparedStatement可以通过addBatch() 添加多条sql语句,并通过executeBatch() 执行多条sql。
下面只是关于批量操作sql的代码(完整使用JDBC操作数据库的流程可以参考使用JDBC连接数据库)
//使用JDBC实现批量操作sql语句
@Test
public void TestBatch() throws Exception {
//数据库的配置
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true";
String username = "root";
Connection coon = null;
Statement stm = null;
// 1. 加载连接驱动
Class.forName(driver);
//2. 获取数据库连接
coon = DriverManager.getConnection(url,username,"");
//3.获取sql执行对象
stm = coon.createStatement();
//4.编写要批量执行的sql语句
String sql1 = "insert into user1(name,pwd) values('b','bbb')";
String sql2 = "insert into user1(name,pwd) values('c','ccc')";
stm.addBatch(sql1);
stm.addBatch(sql2);
//5.执行要批量执行的sql语句(返回值为每条sql语句影响的行数)
int[] ints = stm.executeBatch();
for (int anInt : ints) {
System.out.println("影响的行数为:"+anInt);
}
//6.关闭连接
stm.close();
coon.close();
}
说明:这里会省略掉mybatis连接数据库的操作,只是对forEach形式批量操作sql作说明。
[1] 编写数据库表user1对应的实体类
User.class (这里使用了lombok插件)
package com.gs.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
[2] 编写接口方法 insertUser
UserMapper.class
package com.gs.mapper;
import com.gs.pojo.User;
import java.util.List;
public interface UserMapper {
/*批量sql操作*/
public int insertUser(List<User> list);
}
[3] 编写xml文件
sql语句执行的原型
inssert into user1 values(xx,xx),(xxx,xxxx)
UserMapper.xml
<1> collection表示传入来的是一个List数组,item表示遍历的实体项,separator表示中间以 , 进行分割
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gs.mapper.UserMapper">
<insert id="insertUser" useGeneratedKeys="true" >
insert into user1(name,pwd)
values
<foreach collection="list" separator="," item="user">
(
#{user.name},
#{user.pwd}
)
</foreach>
</insert>
</mapper>
[4] 编写测试方法
[1] MybatisUtil是自己编写的获取SqlSession 的工具类
[2] 通过list把两个对象添加后进行传参执行。
@Test
public void insertUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = new User();
user1.setName("ww");
user1.setPwd("ww");
User user2 = new User();
user2.setName("zl");
user2.setPwd("zl");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
int i = mapper.insertUser(list);
sqlSession.close();
}
控制台相关的日志文件:
可以看到它只开启一次连接,把两个User对象拼装成了一条sql语句后执行
补充说明:下面是关于自己编写的获取SqlSession的工具类(可自行跳过)
MybatisUtil.class
package com.gs.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @Auther: Gs
* @Date: 2020/6/27
* @Description: com.gs.utils
* @version: 1.0
*/
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//我们编写的mybatis核心配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//获得sqlSessionFactory 对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取sqlSession对象
public static SqlSession getSqlSession(){
//这里可以实现自动提交
return sqlSessionFactory.openSession(true);
}
}
官方上对于执行器有如下述说(要完成业务我们可以使用BATCH形式)
[1] 更改sqlSession的执行器(这里我以上面的工具类为例子)
在获取sqlSession的方法中,通过ExecutorType改变执行器。
//获取sqlSession对象
public static SqlSession getSqlSession(){
//开启批量操作
return sqlSessionFactory.openSession(ExecutorType.BATCH,true);
}
[2] 编写接口方法
/*ExecutorType层面上的批量操作*/
public int insertUser2(User user);
[3] 编写xml文件
<insert id="insertUser2" useGeneratedKeys="true" parameterType="user">
insert into user1
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="name!=null">name,</if>
<if test="pwd!=null">pwd,</if>
</trim>
<trim prefix="value(" suffix=")" suffixOverrides=",">
<if test="name!=null">#{name},</if>
<if test="pwd!=null">#{pwd},</if>
</trim>
</insert>
[4] 编写测试方法
@Test
public void insertUser2(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = new User();
user1.setName("ww1");
//user1.setPwd("ww2");
mapper.insertUser2(user1);
User user2 = new User();
user2.setName("zl");
user2.setPwd("zl");
mapper.insertUser2(user2);
sqlSession.commit();
sqlSession.close();
}
控制台的日志
解释:这里我们可以看出它执行了两条sql语句后才关闭连接(若进行相关的debug调试,你会发现只有两个User对象都插入后数据库才有相应的值出现)
补充说明:除了上面的方式外,我们还可以直接在xml映射的配置文件中直接写多条sql语句在一个方法中进行实现。不过我们在编写数据库连接的url时得加上支持多条sql操作的参数 allowMultiQueries=true