参考来自:https://stackoverflow.com/questions/1109061/insert-on-duplicate-update-in-postgresql/1109198#1109198

功能需求:接口定义中包含字段update,当它为true时,批量插入中有记录造成唯一键重复时,不报异常,而是执行更新。

1.接口定义

 {
"resources":
[
{
"name":"*",
"display_name": "*",
"description": "*",
"service": "*"
},
....
],
"update":"true" }

2.代码

原本是通过报的异常 DuplicateKeyException,在catch语句里执行update。但是这样操作有一个问题,后面单独说。

             try {
resourceDao.insert(resource); } catch (DuplicateKeyException e) {
// if (StringUtils.equals(update,Constants.KEY_FALSE)) {
// throw new AuthServiceException(ErrorCode.RESOURCE_DUPLICATE_KEY, new Object[]{resource.getFdResName()}, e);
// }else if (StringUtils.equals(update,Constants.KEY_TRUE)){
// resourceDao.update(resource);
// }
throw new AuthServiceException(ErrorCode.RESOURCE_DUPLICATE_KEY, new Object[]{resource.getFdResName()}, e);
} catch (Exception e) {
throw new AuthServiceException(ErrorCode.RESOURCE_CREATE_FAILED, new Object[]{resource.getFdResName()}, e);
}

3.SQL语句

示例语句:

1 INSERT INTO the_table (id, column_1, column_2)
2 VALUES (1, 'A', 'X')3 ON CONFLICT (唯一键) DO UPDATE
4 SET column_1 ='A',
5 column_2 = 'X';

完整语句:

     <insert id="insert" parameterType="Resource" useGeneratedKeys="true" keyProperty="fdResid">
INSERT INTO t_resource
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="fdResName != null">
fd_res_name,
</if>
<if test="fdDisplayName != null">
fd_display_name,
</if>
<if test="fdResDesc != null">
fd_res_desc,
</if>
<if test="fdTenantId != null">
fd_tenantid,
</if>
<if test="fdService != null">
fd_service,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="fdResName != null">
#{fdResName,jdbcType=VARCHAR},
</if>
<if test="fdDisplayName != null">
#{fdDisplayName,jdbcType=VARCHAR},
</if>
<if test="fdResDesc != null">
#{fdResDesc,jdbcType=VARCHAR},
</if>
<if test="fdTenantId != null">
#{fdTenantId,jdbcType=INTEGER},
</if>
<if test="fdService != null">
#{fdService,jdbcType=VARCHAR},
</if>
</trim> <if test="fdUpdate == 'true'">
ON CONFLICT(fd_res_name, fd_tenantid, fd_service) DO UPDATE
<set>
<if test="fdDisplayName != null">fd_display_name = #{fdDisplayName},</if>
<if test="fdResDesc != null">fd_res_desc = #{fdResDesc},</if>
<if test="fdService != null">fd_service = #{fdService},</if>
<if test="fdModifyDate != null">
fd_modify_date = #{fdModifyDate,jdbcType=VARCHAR},
</if>
<if test="fdModifyPerson != null">
fd_modify_person = #{fdModifyPerson,jdbcType=VARCHAR},
</if>
</set>
</if>
</insert>

4.遇到的问题

之前提到过,之前的处理是通过所报异常信息来做的。如果重复了,在catch语句里执行update。

1              catch (DuplicateKeyException e) {
2 if (StringUtils.equals(update,Constants.KEY_FALSE)) {
3 throw new AuthServiceException(ErrorCode.RESOURCE_DUPLICATE_KEY, new Object[]{resource.getFdResName()}, e);
4 }else if (StringUtils.equals(update,Constants.KEY_TRUE)){
5 resourceDao.update(resource);
6 }
7 throw new AuthServiceException(ErrorCode.RESOURCE_DUPLICATE_KEY, new Object[]{resource.getFdResName()}, e);
8 }

但是在插入重复数据时,报了如下错误:

 Caused by: org.postgresql.util.PSQLException: ERROR: current transaction is aborted, commands ignored until end of transaction block

原因是这个类ServiceResource上标记了@Transactional(在没有事务管理的场景下,是可以像上面那样做的):

2017.7.7 postgreSQL在插入造成重复时执行更新-LMLPHP

           
05-27 12:06