相关代码片段如下,加锁后,会从数据库中取记录(记录中有计数器),修改计数器,唯一标识根据该计数器生成

public class SerialnumUtil {
    ...
    private static final Map<String, ReentrantLock> locks = new ConcurrentHashMap();

    @PostConstruct
    public void init() {
        // init locks 
    ...
    }

    public String generate(String sdtype) {
        Lock lock = locks.get(sdtype);
        try {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                ...
                return XXX;
            } else {
                throw new CustomMessageException("加锁失败");
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new CustomMessageException("创建CODE失败");
        } finally {
            if (null != lock) {
                lock.unlock();
            }
        }
    }
}
        

QUARTZ 任务调度方法中,会使用上述中 generate方法,生成一个标识符,在测试中发现多次调用会返回同一个标识符

1、将方法注释为独立事务 

@Transactional(propagation = Propagation.REQUIRES_NEW)

由于方法被事务方法调用,而该方法执行时间较长,如不将  generate 方法标注为新事务,容易在事务执行中,与另一事务运行中的事务同时调用 generate 方法,获取同一下记录,同时修改,最后生成同一个标识符

2、在 generate 方法中,在修改前再次查询记录,比较两记录修改时间是否一致,如不一致,等待,再次尝试

3、关闭 mybatis 缓存机制

 <select id="XXX" resultMap="XXX" flushCache="true">
   ???
 </select>

 

 

 

参考资料: 

一篇文章让你彻底了解Java可重入锁和不可重入锁

Java项目有中多个线程如何查找死锁

 

 

posted on 2022-05-19 16:55  啊哈咧  阅读(274)  评论(0编辑  收藏  举报