Last active
August 23, 2017 13:06
-
-
Save pfmiles/2bd93ad4a8bf7a341106159276946b46 to your computer and use it in GitHub Desktop.
mysql行级锁原子插入模板,结合ibatis
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 注意这里需要用 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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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