Kotlin实现Mongodb自增主键ID

【shrimpcolo http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。】

背景

Mongodb本身是没有类似mysql那种_id自增功能的,Mongodb使用ObjectId作为自己的_id, Java中表现的是字符串。

ObjectId 示例
5a785ed5 07267d 4168 ac8957

其中:
1. 5a785ed5 时间戳
2. 07267d 主机的唯一标识符
3. 4168 同一机器不同的mongodb进程
4. ac8957 自动增加的计数器

但是,有时候又想实现这样的自增功能怎么办? 办法总是比问题多。

【shrimpcolo http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。】

实现原理

用一个collection保存 需要自增的collection 序列,然后每次使用的时候都去查询,获取当前最新的数字,然后 +1。
那么具体的方式 就会分为2种。函数调用 & 注解

Java实现

Java的实现网络上很多,参考如下。

1. spring-data-mongodb之自增ID实现

onBeforeConvert 需要注意,spring data mongodb版本不同会有不一样的方法
使用注解方式

2. Spring data-mongodb ID自增长注解实现

同样的注意 onBeforeSave 根据spring data mongodb版本不同而定
使用注解方式

3. Spring Data MongoDB – Auto Sequence ID example

时间是2014年的,使用的是 方法调用的方式,而不是注解方式。

4. MongoDB进阶(九)Java中实现MongoDB自增主键ID

这篇博客 先讲解了ObjectId 以及含义,然后使用注解方式实现自增, 实现方式跟上述几个相似

【shrimpcolo http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。】

Kotlin实现

相关依赖

spring-5.0.4
spring-boot-2.0-release
spring-boot-mongodb-3.6
kotlin-1.2.30

【shrimpcolo http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。】

Kotlin 注解定义

/**
 * 自定义自增长ID注解
 *
 */
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation class AutoID01

Mongodb保存自增序列的集合类

@Document(collection = "sys_sequence")
class SequenceId (
        @Id
        val id: String = ObjectId().toHexString(),

        @Field("seq_id")
        val seqId: Long = 0L,

        @Field("coll_name")
        val collName: String = ""
)

MongoEvent监听类

@Component
class SaveEventListener01 : AbstractMongoEventListener<Any>() {
    @Autowired
    private val mongo: MongoTemplate? = null

    override fun onBeforeSave(event: BeforeSaveEvent<Any>) {
        val source = event.source
        ReflectionUtils.doWithFields(source.javaClass) { field ->
            println("===> onBeforeSave 11 ")
            ReflectionUtils.makeAccessible(field)
            // 如果字段添加了我们自定义的AutoValue注解
            if (field.isAnnotationPresent(AutoID01::class.java) && field.get(source) is Number
                    && field.getLong(source) == 0L) {
                // field.get(source) instanceof Number &&
                // field.getLong(source)==0
                // 判断注解的字段是否为number类型且值是否等于0.如果大于0说明有ID不需要生成ID
                // 设置自增ID
                println("===> onBeforeSave 22")
                field.set(source, getNextId(source.javaClass.simpleName))
            }
        }
    }

    override fun onBeforeConvert(event: BeforeConvertEvent<Any>) {
        val source = event.source
        if (source != null) {
            println("===> onBeforeConvert 11 ")
            ReflectionUtils.doWithFields(source.javaClass) { field ->
                ReflectionUtils.makeAccessible(field)
                // 如果字段添加了我们自定义的AutoValue注解
                println("===> onBeforeConvert 2222 ")
                if (field.isAnnotationPresent(AutoID01::class.java) && field.get(source) is Number
                        && field.getLong(source) == 0L) {
                    // field.get(source) instanceof Number &&
                    // field.getLong(source)==0
                    // 判断注解的字段是否为number类型且值是否等于0.如果大于0说明有ID不需要生成ID
                    // 设置自增ID
                    field.set(source, getNextId(source.javaClass.simpleName))
                    println("集合的ID为=======================  $source")
                }
            }
        }
    }

    /**
     * 获取下一个自增ID
     *
     * @param collName
     * 集合(这里用类名,就唯一性来说最好还是存放长类名)名称
     * @return 序列值
     */
    private fun getNextId(collName: String): Long {
        val query = Query(Criteria.where("coll_name").`is`(collName))
        println("===> getNextId, collName = $collName")

        val update = Update()
        update.inc("seq_id", 1)
        val options = FindAndModifyOptions()
        options.upsert(true)
        options.returnNew(true)
        val seq = mongo!!.findAndModify(query, update, options, SequenceId::class.java)

        println("===> getNextId, seqId = $seq")

        return seq.seqId
    }
}

【shrimpcolo http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。】

其他问题

以上是完整实现,注意上面都是kt 而不是java,原本直接使用java现有的方式,在本地代码测试都没有问题,但是将代码 gradlew build 成jar包,放在 云端环境,居然出现了问题,无法创建对应的 sys_sequence 集合,导致数据无法写入mongodb。 索性,全部使用kotlin实现,才解决。

onBeforeSave & onBeforeConvert 都有执行到,但是在代码中onBeforeConvert 精确执行成功,估计跟 spring-data 版本有关。

【shrimpcolo http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值