- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Fluent Mybatis 批量更新的使用由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
背景描述 。
通常需要一次更新多条数据有两个方式 。
在业务代码中循环遍历,逐条更新 一次性更新所有数据, 采用批量sql方式,一次执行.
更准确的说是一条sql语句来更新所有数据,逐条更新的操作放到数据库端,在业务代码端展现的就是一次性更新所有数据.
这两种方式各有利弊,程序中for循环实现就不说了,这里主要介绍第二种方式在fluent mybatis中的实现,以及和mybatis实现的对比.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
class
UpdateBatchTest
extends
BaseTest {
@Autowired
private
StudentMapper mapper;
@Test
public
void
testBatchJavaEach() {
/** 构造多个更新 **/
List<IUpdate> updates =
this
.newListUpdater();
for
(IUpdate update : updates) {
mapper.updateBy(update);
}
}
/**
* 构造多个更新操作
*/
private
List<IUpdate> newListUpdater() {
StudentUpdate update1 =
new
StudentUpdate()
.update.userName().is(
"user name23"
).end()
.where.id().eq(23L).end();
StudentUpdate update2 =
new
StudentUpdate()
.update.userName().is(
"user name24"
).end()
.where.id().eq(24L).end();
return
Arrays.asList(update1, update2);
}
}
|
这种方式在大批量更新时, 最大的问题就是效率,逐条更新,每次都会连接数据库,然后更新,再释放连接资源.
通过mybatis提供的循环标签,一次构造多条update的sql,一次提交服务器进行执行.
1
2
3
4
5
6
7
8
9
10
11
|
<
update
id
=
"updateStudentBatch"
parameterType
=
"java.util.List"
>
<
update
id
=
"updateStudentBatch"
parameterType
=
"java.util.List"
>
<
foreach
collection
=
"list"
item
=
"item"
index
=
"index"
open
=
""
close
=
""
separator
=
";"
>
update student
<
set
>
user_name=#{item.userName}
</
set
>
where id = #{item.id}
</
foreach
>
</
update
>
</
update
>
|
定义Mapper 。
1
2
3
|
public
interface
StudentBatchMapper {
void
updateStudentBatch(List list);
}
|
执行测试验证 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
UpdateBatchTest
extends
BaseTest {
@Autowired
private
StudentBatchMapper batchMapper;
@Test
public
void
updateStudentBatch() {
List<StudentEntity> students = Arrays.asList(
new
StudentEntity().setId(23L).setUserName(
"user name23"
),
new
StudentEntity().setId(24L).setUserName(
"user name24"
));
batchMapper.updateStudentBatch(students);
/** 验证SQL参数 **/
db.table(ATM.table.student).query().eqDataMap(ATM.dataMap.student.table(
2
)
.id.values(23L, 24L)
.userName.values(
"user name23"
,
"user name24"
)
);
}
}
|
使用fluent mybatis进行批量更新很简单,只需要在#updateBy方法中传入 IUpdate数组即可 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
UpdateBatchTest
extends
BaseTest {
@Autowired
private
StudentMapper mapper;
@DisplayName
(
"批量更新同一张表"
)
@Test
public
void
testUpdateBatch_same() {
IUpdate[] updates =
this
.newListUpdater().toArray(
new
IUpdate[
0
]);
mapper.updateBy(updates);
/** 验证SQL语句 **/
db.sqlList().wantFirstSql().eq(
""
+
"UPDATE student SET gmt_modified = now(), user_name = ? WHERE id = ?; "
+
"UPDATE student SET gmt_modified = now(), user_name = ? WHERE id = ?"
, StringMode.SameAsSpace);
/** 验证SQL参数 **/
db.table(ATM.table.student).query().eqDataMap(ATM.dataMap.student.table(
2
)
.id.values(23L, 24L)
.userName.values(
"user name23"
,
"user name24"
)
);
}
}
|
要实现批量更新,首先得设置mysql支持批量操作,在jdbc url链接中附加&allowMultiQueries=true属性 。
例如:
1
|
jdbc:mysql://localhost:3306/testdb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
|
1
2
3
4
|
UPDATE
student
SET
gmt_modified = now(),
address =
case
id
when
1
then
'address 1'
when
2
then
'address 2'
when
3
then
'address 3'
end
WHERE
id
in
(1, 2, 3)
|
上面的sql语句使用mysql的case when then语法实现的批量更新3条记录,并且根据id的值不同,设置不同的address值.
如果使用mybatis的xml语法来实现,xml文件就需要表达为下面方式
xml文件 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<
update
id
=
"updateBatchByIds"
parameterType
=
"list"
>
update student
<
trim
prefix
=
"set"
suffixOverrides
=
","
>
<
trim
prefix
=
"address =case id"
suffix
=
"end,"
>
<
foreach
collection
=
"list"
item
=
"item"
index
=
"index"
>
<
if
test
=
"item.id!=null"
>
when #{item.id} then #{item.address}
</
if
>
</
foreach
>
</
trim
>
</
trim
>
<
trim
prefix
=
"age =case id"
suffix
=
"end,"
>
<
foreach
collection
=
"list"
item
=
"item"
index
=
"index"
>
<
if
test
=
"item.id!=null"
>
when #{item.id} then #{item.age}
</
if
>
</
foreach
>
</
trim
>
where id in
<
foreach
collection
=
"list"
item
=
"item"
index
=
"index"
separator
=
","
open
=
"("
close
=
")"
>
#{item.id}
</
foreach
>
</
update
>
|
定义Mapper 。
1
2
3
|
public
interface
StudentBatchMapper {
int
updateBatchByIds(List<StudentEntity> list);
}
|
验证 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
class
CaseFuncTest
extends
BaseTest {
@Autowired
private
StudentBatchMapper batchMapper;
@Test
public
void
test_mybatis_batch() {
batchMapper.updateBatchByIds(Arrays.asList(
new
StudentEntity().setId(1L).setAddress(
"address 1"
).setAge(
23
),
new
StudentEntity().setId(2L).setAddress(
"address 2"
).setAge(
24
),
new
StudentEntity().setId(3L).setAddress(
"address 3"
).setAge(
25
)
));
/** 验证执行的SQL语句 **/
db.sqlList().wantFirstSql().eq(
""
+
"update student "
+
"set address =case id when ? then ? when ? then ? when ? then ? end, "
+
"age =case id when ? then ? when ? then ? when ? then ? end "
+
"where id in ( ? , ? , ? )"
, StringMode.SameAsSpace);
}
}
|
使用Fluent Mybatis实现方式 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
class
CaseFuncTest
extends
BaseTest {
@Autowired
private
StudentMapper mapper;
@Test
public
void
test_fluentMybatisBatch()
throws
Exception {
final
String CaseWhen =
"case id "
+
"when 1 then ? "
+
"when 2 then ? "
+
"else ? end"
;
StudentUpdate update =
new
StudentUpdate()
.update.address().applyFunc(CaseWhen,
"address 1"
,
"address 2"
,
"address 3"
)
.set.age().applyFunc(CaseWhen,
23
,
24
,
25
)
.end()
.where.id().in(
new
int
[]{
1
,
2
,
3
}).end();
mapper.updateBy(update);
/** 验证执行的SQL语句 **/
db.sqlList().wantFirstSql()
.eq(
"UPDATE student "
+
"SET gmt_modified = now(), "
+
"address = case id when 1 then ? when 2 then ? else ? end, "
+
"age = case id when 1 then ? when 2 then ? else ? end "
+
"WHERE id IN (?, ?, ?)"
,
StringMode.SameAsSpace);
}
}
|
只需要在applyFunc中传入case when语句,和对应的参数(对应case when语句中的预编译占位符'?') 。
如果业务入口传入的是Entity List或者Map List,可以使用java8的stream功能处理成数组,示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public
class
CaseFuncTest
extends
BaseTest {
@Autowired
private
StudentMapper mapper;
@Test
public
void
test_fluentMybatisBatch2()
throws
Exception {
List<StudentEntity> students = Arrays.asList(
new
StudentEntity().setId(1L).setAddress(
"address 1"
).setAge(
23
),
new
StudentEntity().setId(2L).setAddress(
"address 2"
).setAge(
24
),
new
StudentEntity().setId(3L).setAddress(
"address 3"
).setAge(
25
));
final
String CaseWhen =
"case id "
+
"when 1 then ? "
+
"when 2 then ? "
+
"else ? end"
;
StudentUpdate update =
new
StudentUpdate()
.update.address().applyFunc(CaseWhen, getFields(students, StudentEntity::getAddress))
.set.age().applyFunc(CaseWhen, getFields(students, StudentEntity::getAge))
.end()
.where.id().in(getFields(students, StudentEntity::getId)).end();
mapper.updateBy(update);
// 验证SQL语句
db.sqlList().wantFirstSql()
.eq(
"UPDATE student "
+
"SET gmt_modified = now(), "
+
"address = case id when 1 then ? when 2 then ? else ? end, "
+
"age = case id when 1 then ? when 2 then ? else ? end "
+
"WHERE id IN (?, ?, ?)"
,
StringMode.SameAsSpace);
// 验证参数
db.sqlList().wantFirstPara()
.eqReflect(
new
Object[]{
"address 1"
,
"address 2"
,
"address 3"
,
23
,
24
,
25
, 1L, 2L, 3L});
}
private
Object[] getFields(List<StudentEntity> students, Function<StudentEntity, Object> getField) {
return
students.stream().map(getField).toArray(Object[]::
new
);
}
}
|
使用Fluent Mybatis无需额外编写xml文件和mapper(使用框架生成的Mapper文件就够了)。在业务逻辑上不至于因为有额外的xml文件,而产生割裂感.
上面的例子使用mybatis和fluent mybatis演示的如果通过不同方法批量更新同一张表的数据,在fluent mybatis的更新其实不限定于同一张表, 。
在#updateBy(IUpdate... updates)函数可以传入任意表更新. 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public
class
UpdateBatchTest
extends
BaseTest {
@Autowired
private
StudentMapper mapper;
@DisplayName
(
"批量更新不同表"
)
@Test
public
void
testUpdateBatch_different() {
StudentUpdate update1 =
new
StudentUpdate()
.update.userName().is(
"user name23"
).end()
.where.id().eq(23L).end();
HomeAddressUpdate update2 =
new
HomeAddressUpdate()
.update.address().is(
"address 24"
).end()
.where.id().eq(24L).end();
/** 执行不同表的批量更新 **/
mapper.updateBy(update1, update2);
/** 验证实际执行的预编译SQL语句**/
db.sqlList().wantFirstSql().eq(
""
+
"UPDATE student SET gmt_modified = now(), user_name = ? WHERE id = ?; "
+
"UPDATE home_address SET gmt_modified = now(), address = ? WHERE id = ?"
, StringMode.SameAsSpace);
db.table(ATM.table.student).query().eqDataMap(ATM.dataMap.student.table(
2
)
.id.values(23L, 24L)
.userName.values(
"user name23"
,
"user"
)
);
/** 验证实际执行预编译SQL入参值 **/
db.table(ATM.table.homeAddress).query().eqDataMap(ATM.dataMap.homeAddress.table(
2
)
.id.values(
23
,
24
)
.address.values(
"address"
,
"address 24"
)
);
}
}
|
示例更新了2张表: student 和 home_address 。
Fluent MyBatis地址 Fluent MyBatis文档 。
到此这篇关于Fluent Mybatis 批量更新的使用的文章就介绍到这了,更多相关Fluent Mybatis 批量更新内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://juejin.cn/post/6923914096467410958 。
最后此篇关于Fluent Mybatis 批量更新的使用的文章就讲到这里了,如果你想了解更多关于Fluent Mybatis 批量更新的使用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我查看了网站上的一些问题,但还没有完全弄清楚我做错了什么。我有一些这样的代码: var mongoose = require('mongoose'), db = mongoose.connect('m
基本上,根据 this bl.ocks,我试图在开始新序列之前让所有 block 都变为 0。我认为我需要的是以下顺序: 更新为0 退出到0 更新随机数 输入新号码 我尝试通过添加以下代码块来遵循上述
我试图通过使用随机数在循环中设置 JSlider 位置来模拟“赛马”的投注结果。我的问题是,当然,我无法在线程执行时更新 GUI,因此我的 JSlider 似乎没有在竞赛,它们从头到尾都在运行。我尝试
该功能非常简单: 变量:$table是正在更新的表$fields 是表中的字段,$values 从帖子生成并放入 $values 数组中而$where是表的索引字段的id值$indxfldnm 是索引
让我们想象一个环境:有一个数据库客户端和一个数据库服务器。数据库客户端可以是 Java 程序或其他程序等;数据库服务器可以是mysql、oracle等。 需求是在数据库服务器上的一个表中插入大量记录。
在我当前的应用程序中,我正在制作一个菜单结构,它可以递归地创建自己的子菜单。然而,由于这个原因,我发现很难也允许某种重新排序方法。大多数应用程序可能只是通过“排序”列进行排序,但是在这种情况下,尽管这
Provisioning Profile 有 key , key 链依赖于它。我想知道 key 什么时候会改变。 Key will change after renew Provisioning Pr
截至目前,我在\server\publications.js 中有我的 MongoDB“选择”,例如: Meteor.publish("jobLocations", function () { r
我读到 UI 应该始终在主线程上更新。但是,当谈到实现这些更新的首选方法时,我有点困惑。 我有各种函数可以执行一些条件检查,然后使用结果来确定如何更新 UI。我的问题是整个函数应该在主线程上运行吗?应
我在代理后面,我无法构建 Docker 镜像。 我试过 FROM ubuntu , FROM centos和 FROM alpine ,但是 apt-get update/yum update/apk
我构建了一个 Java 应用程序,它向外部授权客户端公开网络服务。 Web 服务使用带有证书身份验证的 WS-security。基本上我们充当自定义证书颁发机构 - 我们在我们的服务器上维护一个 ja
因此,我有时会在上传新版本时使用 app_offline.htm 使应用程序离线。 但是,当我上传较大的 dll 时,我收到黄色错误屏幕,指出无法加载 dll。 这似乎与我对 app_offline.
我刚刚下载了 VS Apache Cordova Tools Update 5,但遇到了 Node 和 NPM 的问题。我使用默认的空白 cordova 项目进行测试。 版本 如果我在 VS 项目中对
所以我有一个使用传单库实例化的 map 对象。 map 实例在单独的模板中创建并以这种方式路由:- var app = angular.module('myApp', ['ui', 'ngResour
我使用较早的 Java 6 u 3 获得的帧速率是新版本的两倍。很奇怪。谁能解释一下? 在 Core 2 Duo 1.83ghz 上,集成视频(仅使用一个内核)- 1500(较旧的 java)与 70
我正在使用 angular 1.2 ng-repeat 创建的 div 也包含 ng-click 点击时 ng-click 更新 $scope $scope 中的变化反射(reflect)在使用 $a
这些方法有什么区别 public final void moveCamera(CameraUpdate更新)和public final void animateCamera (CameraUpdate
我尝试了另一篇文章中某人评论中关于如何将树更改为列表的建议。但是,我在某处(或某物)有未声明的变量,所以我列表中的值是 [_G667, _G673, _G679],而不是 [5, 2, 6],这是正确
实现以下场景的最佳方法是什么? 我需要从java应用程序调用/查询包含数百万条记录的数据库表。然后,对于表中的每条记录,我的应用程序应该调用第三方 API 并获取状态字段作为响应。然后我的应用程序应该
只是在编写一些与 java 图形相关的代码,这是我今天的讲座中的非常简单的示例。不管怎样,互联网似乎说更新不会被系统触发器调用,例如调整框架大小等。在这个例子中,更新是由这样的触发器调用的(因此当我只
我是一名优秀的程序员,十分优秀!