`

借助数据库行级锁实现每天001,002这样的自增序号

阅读更多
-- 流水号自增表创建
DROP TABLE IF EXISTS code_date_sequence;
CREATE TABLE code_date_sequence (
  code_date VARCHAR(255) not null comment '日期字符串yyMMdd格式',
  code_type varchar(255) not NULL COMMENT '业务类型 通常是生成业务序号的前缀',
  sequence_no BIGINT not NULL COMMENT '序列号',
  UNIQUE KEY PK_date_code (code_date,code_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='序列号增长表';

-- 查询函数创建
DROP FUNCTION IF EXISTS getCodeDateNumber;
CREATE  FUNCTION getCodeDateNumber(codeType VARCHAR(255),codeDate VARCHAR(255),startValue INTEGER(11)) RETURNS bigint(20)
BEGIN
	if startValue is  null then
    set startValue = 1;
  end if;
	set @sn = startValue;
	INSERT INTO code_date_sequence (code_date,code_type,sequence_no) 
	VALUES (codeDate,codeType,startValue) ON DUPLICATE KEY UPDATE sequence_no=@sn:=sequence_no+1;
    RETURN(@sn);
END;

 

@Service
public class GeneratorBiz implements IGeneratorBiz {
	private static final Logger logger = LoggerFactory.getLogger(GeneratorBiz.class);
	
	private static final String prefix0 = "00";
	
	@Resource
	private CodeDateMybatisDao codeDateMybatisDao;
	
	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public String generatorStandardCode (String standardType) {
		String codeDate = DateUtil.format(new Date(), DateUtil.DATE_TIME_FORMAT_YMD);
		int suffixLength = 3;
		String result = null;
		String number = generatorSerialNumber(codeDate, standardType);
		if (StringUtils.isNotBlank(number)) {
			result = StringUtils.right(prefix0+number, suffixLength);
			if(number.length()>suffixLength){
				result = number;
			}
			result = standardType + codeDate + result;
		}
		
		return result;
	}
	
	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public String generatorTaskCode (String standardCode, String warehouseCode) {
		String codeDate = DateUtil.format(new Date(), "MMdd");
		int suffixLength = 2;
		String result = null;
		String codeType = standardCode + "-" +  warehouseCode;
		String number = generatorSerialNumber(codeDate, codeType);
		if (StringUtils.isNotBlank(number)) {
			result = StringUtils.right(prefix0+number, suffixLength);
			if(number.length()>suffixLength){
				result = number;
			}
			result = codeType + "-" + codeDate + "-" + result;
		}
		
		return result;
	}
	
	private String generatorSerialNumber(String codeDate, String codeType) {
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("codeDate", codeDate);
		map.put("codeType", codeType);
		codeDateMybatisDao.insertOnDuplicate(map);
		Integer number = codeDateMybatisDao.getCodeDateNumber(map);
		logger.info(DateUtil.format(new Date()) + ",codeDate:" + codeDate + ",codeType:" + codeType  + ",number" + number + ",threadId" + Thread.currentThread().getId());
		return number != null ? number.toString() : null;
	}

 

@MyBatisRepository
public interface CodeDateMybatisDao {
	public Integer getCodeDateNumber(Map<String,Object> paramMap);
	public void insertOnDuplicate(Map<String,Object> paramMap);
}

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace必须指向Dao接口 -->
<mapper namespace="com.sf.wop.qms.dao.mybatis.CodeDateMybatisDao">

	<!-- 查询生成流水 -->
	<select id="getCodeDateNumber" parameterType="map" resultType="Integer">
		select sequence_no from tb_qms_code_date_sequence 
		where (code_date,code_type) in ((#{codeDate},#{codeType}))
	</select>
	
	<!-- 使用行级锁保证拿到的序号唯一 -->
	<insert id="insertOnDuplicate" parameterType="map">
		INSERT INTO tb_qms_code_date_sequence (code_date,code_type,sequence_no) 
		VALUES (#{codeDate},#{codeType},1) ON DUPLICATE KEY UPDATE sequence_no=sequence_no+1
	</insert>

</mapper> 

 

分享到:
评论

相关推荐

    行级锁的实例

    行级锁的实例

    MySQL中的行级锁、表级锁、页级锁

    MySQL数据库在处理并发操作时,为了保证数据的一致性和完整性,使用了不同的锁机制,包括行级锁、表级锁和页级锁。这三种锁的粒度不同,各有优缺点,适用于不同的场景。 行级锁是MySQL中最细粒度的锁,仅锁定操作的...

    MySQL中的行级锁,表级锁,页级锁1

    MySQL中的锁机制主要分为行级锁、表级锁和页级锁,这三种锁的粒度不同,分别适用于不同的并发场景。 行级锁是MySQL中最细粒度的锁,只针对当前操作的行进行锁定。行级锁分为共享锁(读锁)和排他锁(写锁),它能...

    各种锁汇总,乐观锁、悲观锁、分布式锁、可重入锁、互斥锁、读写锁、分段锁、类锁、行级锁等

    本文将深入探讨标题和描述中提及的各种锁,包括乐观锁、悲观锁、分布式锁、可重入锁、互斥锁、读写锁、分段锁、类锁以及行级锁。 1. **乐观锁**:乐观锁假设多线程环境中的冲突较少,所以在读取数据时不加锁,只有...

    数据库中锁机制的学习

    数据库系统通常采用两种锁的粒度:行级锁和表级锁。行级锁只锁定操作的数据行,提高了并发性,但在处理大量数据时可能导致锁竞争激烈。相反,表级锁一次性锁定整个表,降低了并发性能,但减少了锁的管理开销。 在...

    MySQL 全局锁、表级锁、行级锁

    在多用户环境中,为了保证数据的一致性和完整性,MySQL 提供了多种锁定机制,包括全局锁、表级锁和行级锁。这些锁机制是数据库事务处理中的核心组成部分,下面我们将详细探讨这些锁的特性和应用场景。 1. **全局锁...

    Oracle数据库的锁类型

    Oracle数据库的锁机制是其实现高性能、高可用性和高安全性的基石之一。通过对DML锁、DDL锁以及内部锁和闩锁的理解,可以更好地设计和优化数据库应用程序,以应对复杂的业务场景和高并发访问需求。掌握Oracle数据库的...

    oracle数据库锁使用

    例如,S锁与S锁、RS锁与RS锁、RX锁与RX锁之间是兼容的,但S锁与X锁、RS锁与X锁、RX锁与X锁之间不兼容。这些规则有助于开发者设计出高效且安全的并发处理策略。 在处理并发问题时,应谨慎使用锁,避免出现死锁情况,...

    数据库的锁.pdf

    数据库锁是一种确保数据库数据一致性和完整性的机制,尤其在多用户同时对数据进行读写操作时,锁能够避免数据访问冲突。锁机制是数据库管理系统(DBMS)中的核心功能之一,它需要高效且复杂地管理并发访问,以避免...

    Oracle数据库锁的研究.pdf

    在Oracle数据库中,锁的实现是轻量级的,它将锁作为数据块的属性直接存储在数据块头部,这部分称为ITL(Intent To Lock),用于记录事务在数据块上的活动信息,以确保事务的一致性。Oracle数据库并不像某些系统那样...

    MySQL行级锁、表级锁、页级锁详细介绍

    MySQL的锁定机制是数据库管理中不可或缺的一部分,它用于控制多个并发事务对数据的访问,确保数据的一致性和完整性。...在设计数据库事务和查询时,应考虑锁的粒度和潜在的并发问题,以实现最佳的系统性能。

    MS SQL Server数据库事务锁机制分析

    当一个事务中涉及的锁数量达到一定的阈值(锁升级门限)时,系统会自动将行级锁和页面锁升级为表级锁,以减少锁的数量,提高系统性能。这个过程是自动的,用户通常无需手动干预。 锁在SQL Server中有多种模式,每种...

    Oracle行级锁的特殊用法简析

    总之,Oracle的行级锁是数据库并发控制的重要工具,通过细致地配置和使用,可以实现高效且安全的数据访问。理解并掌握SELECT...FOR UPDATE语句及其相关选项,可以帮助开发人员更好地控制并发,提高数据库应用的性能...

    数据库,各种锁的概述

    ### 数据库锁机制详解 #### 一、数据库锁的基本概念 在并发环境下,数据库系统面临着多种潜在的数据一致性问题。为了确保数据的正确性与一致性,数据库管理系统(DBMS)引入了锁机制作为并发控制的核心手段。 ###...

    事务的四大隔离级别、数据库中的共享锁与排他锁、MySQL 的行级锁与表级锁

    数据库相关的笔记

    oracle数据库中锁、序列、索引管理.docx

    锁的粒度决定了锁的作用范围,分为行级锁(TX锁)、表级锁(TM锁)和数据库级锁。行级锁,如TX锁,可以细分为X锁,只允许一个事务对特定行进行独占式访问。表级锁有共享锁(RS、RX)和排他锁(S、SRX、X),共享锁...

    值得学习的MySQL行级锁、表级锁、页级锁详细介绍

    值得学习的MySQL行级锁、表级锁、页级锁详细介绍

    Oracle 数据库针对表主键列并发导致行级锁简单演示

    本文内容 •软件环境 •简单演示 Oracle 数据库并发导致行级锁 本文简单演示针对表主键并发导致的行级锁。并发是两个以上的用户对同样的数据进行修改(包括插入、删除和修改)。锁的产生是因为并发。没有并发,就...

Global site tag (gtag.js) - Google Analytics