Skip to content

Instantly share code, notes, and snippets.

@pfmiles
Last active August 23, 2017 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfmiles/2bd93ad4a8bf7a341106159276946b46 to your computer and use it in GitHub Desktop.
Save pfmiles/2bd93ad4a8bf7a341106159276946b46 to your computer and use it in GitHub Desktop.
mysql行级锁原子插入模板,结合ibatis
<!-- 注意这里需要用 isNotEmpty 保证更新目标的关键字段不能被更新为null,这里的insert仅仅为了实现selectForUpdate的行级锁而做,其中目标字段在数据库中必须为nullable -->
<insert id="asa.AsaDdMediaDAO.insertOrUpdate" parameterClass="AsaDdMediaDO">
insert into
asa_dd_media(gmt_create,
gmt_modified, url, type, media_id) values (
now(), now(), #url#, #type#, #mediaId#)
ON
DUPLICATE KEY
UPDATE gmt_modified = now(), type = #type#
<isNotEmpty prepend="," property="mediaId">
media_id = #mediaId#
</isNotEmpty>
</insert>
@Override
public String findOrBuildMediaIdInSerialTransaction(String url, String type,
Supplier<String> mediaIdSupplier) throws Exception {
if (StringUtils.isBlank(url) || StringUtils.isBlank(type))
return null;
return this.adsTransactionTemplate.execute(status -> {
try {
// 1.查找指定url在库中是否存在、且对应imageId也存在
AsaDdMediaDO data = findByUrl(url);
String mediaId = null;
if (data != null && StringUtils.isNotBlank(data.getMediaId())) {
// 2.若存在则直接返回对应mediaId
mediaId = data.getMediaId();
} else {
// 3.若不存在则调用mediaIdSupplier得到mediaId,并使用insertOrUpdate将url与mediaId关联到库里,最后返回mediaId
// 3.1 先insertOrUpdate进去一个不包含imageId的记录,注意这里需要利用ibatis的isNotEmpty才更新的动态特性以保护其它竞争进程写入的数据不被破坏
data = new AsaDdMediaDO();
data.setType(type);
data.setUrl(url);
this.insertOrUpdate(data);
// 3.2 select for update刚才的记录,导致该行加锁
data = this.findByUrlForUpdate(url);
// 3.3 若上一步select for update查出的imageId已经存在,则直接返回,若不存在,则执行mediaIdSupplier逻辑创建并更新到库中,最后返回新imageId
if (data != null && StringUtils.isNotBlank(data.getMediaId())) {
mediaId = data.getMediaId();
} else {
mediaId = mediaIdSupplier.get();
if (StringUtils.isNotBlank(mediaId)) {
data.setMediaId(mediaId);
this.insertOrUpdate(data);
}
}
}
return mediaId;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment