1 Mybatis中的三種sql執行器
https://mybatis.org/mybatis-3/zh/configuration.html#settings
設置名 | 描述 | 有效值 | 默認值 |
---|---|---|---|
defaultExecutorType | 配置默認的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(PreparedStatement); BATCH 執行器不僅重用語句還會執行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
@Test
public void test_() {
//SIMPLE REUSE BATCH
Arrays.stream(ExecutorType.values()).forEach((item) -> {
System.out.print(item + " ");
});
}
2 測試三種sql執行器
public class UserMapperTest {
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void initSqlSessionFactory() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
}
//清空表中數據, 同時重置自增序列從0開始
public void clearTable() {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.getMapper(UserMapper.class).clear();
}
/**
* @param list 插入的User集合
* @param type ExecutorType
* @param autoCommit 是否自動提交
*/
public void insertUser(List<User> list, ExecutorType type, boolean autoCommit) {
//每次測試前清空表
clearTable();
SqlSession sqlSession = sqlSessionFactory.openSession(type, autoCommit);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
long start = System.currentTimeMillis();
try {
list.stream().forEach((user -> mapper.insert(user)));
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
} finally {
sqlSession.close();
}
long end = System.currentTimeMillis();
System.out.println("【"+type+"耗時】: " + (end - start) + "(ms)");
}
@Test
public void testInsertUser() {
// 初始化50000個對象
List<User> list = new ArrayList<>();
for (int i = 0; i < 50000; i++) {
list.add(new User(i, i + "", "男", new Date(), "重慶萬州", "123456"));
}
//測試
//BATCH: 批量執行器, 對相同sql進行一次預編譯, 然後設置參數, 最後統一執行操作
insertUser(list, ExecutorType.BATCH, false);//【BATCH耗時】: 59105(ms)
//SIMPLE: 默認的執行器, 對每條sql進行預編譯->設置參數->執行等操作
insertUser(list, ExecutorType.SIMPLE, false);//【SIMPLE耗時】: 118136(ms)
//REUSE: REUSE 執行器會重用預處理語句(prepared statements)
insertUser(list, ExecutorType.REUSE, false);//【REUSE耗時】: 114406(ms)
}
public class JDBCTest {
/**
* 獲取Connection
*/
public static Connection getConn() throws SQLException {
String url = "jdbc:mysql://127.0.0.1:6033/mybatis_bash_db?serverTimezone=UTC";
String user = "root";
String password = "123456";
return DriverManager.getConnection(url, user, password);
}
/**
* 清空表
*/
public void clearTable() throws SQLException {
Statement statement = getConn().createStatement();
String sql = "truncate table mybatis_bash_db.user";
statement.executeUpdate(sql);
}
public void test_1(int count) throws SQLException {
Connection conn = getConn();
Statement statement = conn.createStatement();
for (int i = 1; i <= count; i++) {
String sql = "insert into mybatis_bash_db.user(id, username) " +
"values (" + i + ",'蔡徐坤')";
int res = statement.executeUpdate(sql);
}
}
public void test_2(int count) throws SQLException {
Connection conn = getConn();
String sql = "insert into mybatis_bash_db.user(id, username) " +
"values (?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
for (int i = 1; i <= count; i++) {
pstmt.setInt(1, i);
pstmt.setString(2, "喬碧蘿");
int res = pstmt.executeUpdate();
}
}
public void test_3(int count) throws SQLException {
String sql = "insert into mybatis_bash_db.user(id, username) " +
"values (1,'蔡徐坤')";
Connection conn = getConn();
PreparedStatement pstmt = conn.prepareStatement("insert into mybatis_bash_db.user(id, username) " +
"values (?,?)");
for (int i = 1; i <= count; i++) {
pstmt.setInt(1, i);
pstmt.setString(2, "盧本偉");
pstmt.addBatch();
}
int[] resArr = pstmt.executeBatch();
}
@Test
public void test() throws SQLException {
int count = 5000;
clearTable();
long start = System.currentTimeMillis();
test_1(count);
//test_2(count);
//test_3(count);
long end = System.currentTimeMillis();
System.out.println("耗時: " + (end - start) + "(ms)");
}
2.1 SIMPLE方式
從執行日誌可以看出, 每次插入操作,都會執行編譯,設置參數,執行sql操作。
DEBUG [main] ==> Preparing: insert into mybatis_bash_db.user(id, username, sex, birthday, address, password) values (?, ?, ?, ?, ?, ?)
DEBUG [main] ==> Parameters: 0(Integer), 0(String), 男(String), 2020-04-01 11:18:16.44(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
DEBUG [main] ==> Preparing: insert into mybatis_bash_db.user(id, username, sex, birthday, address, password) values (?, ?, ?, ?, ?, ?)
DEBUG [main] ==> Parameters: 1(Integer), 1(String), 男(String), 2020-04-01 11:18:16.44(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
DEBUG [main] ==> Preparing: insert into mybatis_bash_db.user(id, username, sex, birthday, address, password) values (?, ?, ?, ?, ?, ?)
DEBUG [main] ==> Parameters: 2(Integer), 2(String), 男(String), 2020-04-01 11:18:16.44(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
DEBUG [main] ==> Preparing: insert into mybatis_bash_db.user(id, username, sex, birthday, address, password) values (?, ?, ?, ?, ?, ?)
DEBUG [main] ==> Parameters: 3(Integer), 3(String), 男(String), 2020-04-01 11:18:16.44(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
...
2.2 REUSE方式
從執行日誌可以看出,只有第一次插入操作,執行了sql編譯步驟,對其它插入操作執行了設置參數,執行sql的操作。
DEBUG [main] ==> Preparing: insert into mybatis_bash_db.user(id, username, sex, birthday, address, password) values (?, ?, ?, ?, ?, ?)
DEBUG [main] ==> Parameters: 0(Integer), 0(String), 男(String), 2020-04-01 11:23:58.522(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
DEBUG [main] ==> Parameters: 1(Integer), 1(String), 男(String), 2020-04-01 11:23:58.522(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
DEBUG [main] ==> Parameters: 2(Integer), 2(String), 男(String), 2020-04-01 11:23:58.522(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
DEBUG [main] ==> Parameters: 3(Integer), 3(String), 男(String), 2020-04-01 11:23:58.522(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] <== Updates: 1
...
2.3 BATCH
從執行日誌可以看出,只對第一次插入操作執行了sql編譯操作,對其它插入操作僅執行了設置參數操作,最後統一執行。
DEBUG [main] ==> Preparing: insert into mybatis_bash_db.user(id, username, sex, birthday, address, password) values (?, ?, ?, ?, ?, ?)
DEBUG [main] ==> Parameters: 0(Integer), 0(String), 男(String), 2020-04-01 11:26:24.683(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] ==> Parameters: 1(Integer), 1(String), 男(String), 2020-04-01 11:26:24.683(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] ==> Parameters: 2(Integer), 2(String), 男(String), 2020-04-01 11:26:24.683(Timestamp), 重慶萬州(String), 123456(String)
DEBUG [main] ==> Parameters: 3(Integer), 3(String), 男(String), 2020-04-01 11:26:24.683(Timestamp), 重慶萬州(String), 123456(String)
...
docker run -d --rm --name mybatis_db -p 6033:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0.18
jdbc:mysql://127.0.0.1:6033?serverTimezone=UTC
CREATE DATABASE mybatis_bash_db;
USE mybatis_bash_db;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`(
`id` int(11) NOT NULL,
`username` varchar(20) DEFAULT NULL,
`sex` varchar(6) DEFAULT NULL,
`birthday` date DEFAULT NULL,
`address` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
);
src/main/resources/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://127.0.0.1:6033/mybatis_bash_db?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.executor.mapper"/>
</mappers>
</configuration>
src/main/resources/log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%5p [%t] %m%n"/>
</layout>
</appender>
<logger name="com.executor.mapper">
<level value="DEBUG"/>
</logger>
<root>
<level value="ERROR"/>
<appender-ref ref="STDOUT"/>
</root>
</log4j:configuration>
src/main/resources/com/executor/mapper/UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.executor.mapper.UserMapper">
<resultMap type="com.executor.domain.User" id="UserMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="username" column="username" jdbcType="VARCHAR"/>
<result property="sex" column="sex" jdbcType="VARCHAR"/>
<result property="birthday" column="birthday" jdbcType="TIMESTAMP"/>
<result property="address" column="address" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
</resultMap>
<!-- 清空表中數據, 同時重置自增序列從0開始 -->
<delete id="clear">
truncate table mybatis_bash_db.user
</delete>
<!--查詢單個-->
<select id="queryById" resultMap="UserMap">
select id,
username,
sex,
birthday,
address,
password
from mybatis_bash_db.user
where id = #{id}
</select>
<!--新增所有列-->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
insert into mybatis_bash_db.user(id, username, sex, birthday, address, password)
values (#{id}, #{username}, #{sex}, #{birthday}, #{address}, #{password})
</insert>
</mapper>
com.executor.domain.User
@Data
public class User implements Serializable {
private static final long serialVersionUID = 414848905562793591L;
private Integer id;
private String username;
private String sex;
private Date birthday;
private String address;
private String password;
public User() {
}
public User(Integer id, String username, String sex, Date birthday, String address, String password) {
this.id = id;
this.username = username;
this.sex = sex;
this.birthday = birthday;
this.address = address;
this.password = password;
}
}
com.executor.mapper.UserMapper
public interface UserMapper {
/**
* 清空表
*/
void clear();
/**
* 通過ID查詢單條數據
* @param id 主鍵
* @return 實例對象
*/
User queryById(Integer id);
/**
* 新增數據
* @param user 實例對象
* @return 影響行數
*/
int insert(User user);
}
pom.xml
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
com.executor.mapper.UserMapperTest
public class UserMapperTest {
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void initSqlSessionFactory() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
}
//清空表中數據, 同時重置自增序列從0開始
public void clearTable() {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.getMapper(UserMapper.class).clear();
}
@Test
public void testEnvIsOk() {
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.insert(new User(1, "蔡徐坤", "男", new Date(), "重慶萬州", "123456"));
System.out.println(res);
System.out.println(mapper.queryById(1));
mapper.clear();
}
/**
* @param list 插入的User集合
* @param type ExecutorType
* @param autoCommit 是否自動提交
*/
public void testSave(List<User> list, ExecutorType type, boolean autoCommit) {
clearTable();
SqlSession sqlSession = sqlSessionFactory.openSession(type, autoCommit);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
long start = System.currentTimeMillis();
try {
list.stream().forEach((user -> mapper.insert(user)));
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.rollback();
}
long end = System.currentTimeMillis();
System.out.println("耗時: " + (end - start) + "(ms)");
}
@Test
public void test_() {
// 初始化10000個對象
List<User> list = new ArrayList<>();
for (int i = 0; i < 2; i++) {
list.add(new User(i, i + "", "男", new Date(), "重慶萬州", "123456"));
}
//測試
System.out.println("BATCH");
testSave(list, ExecutorType.BATCH, false);
System.out.println("SIMPLE");
testSave(list, ExecutorType.SIMPLE, false);
System.out.println("REUSE");
testSave(list, ExecutorType.REUSE, false);
}
}