typeorm(sqlite3)-事务并发

1,278 阅读2分钟

背景

先简单说下背景,在一个IM软件需求上需要同步大量消息/会话/好友等信息,为了大量同步语句重复进行事务开启导致的性能消耗,手动开启了多个事务进行批量同步。
在开启事务后虽然性能消耗减少很多,但也因为开启事务出现了很多问题,本文主要是记录下手动开启事务后遇到的一些问题和思考;

事务并发

由于同步的表较多,需要开启多个事务,当我尝试开启多个事务时,typeorm出现错误提示;

TransactionAlreadyStartedError: Transaction already started for the given connection, commit current transaction before starting a new one.

看起来是不允许多个事务并发,找了下相关issue:
1、typeorm conncetion pool: issue, issue;
1、typeorm transaction queue: issue;
3、can not start a transaction within a transaction: issue;

得到以下结论:
1、sqlite数据库支持多连接,但不管是多连接或者是单个连接内,仅支持一个写操作(默认serializable隔离级别),如果业务上并发写操作,sqlite会上锁并有队列控制执行顺序;文档
2、sqlite3 driver 不支持多连接(连接池);
3、typeorm 不支持多transaction并发;

由于在我们当前架构(需要在用户登录后同步用户信息,包括消息,通信录,会话等)下,必须手动开启transaction优化性能。目前只有两种解决方案:
1、只存在transaction,在transaction下同步多个表信息;
2、我们自己实现一个队列来控制transaction执行顺序;

因为不同信息由不同服务获取,很难控制在一个transaction下执行,也很难由于执行时长带来的问题。所以只能通过队列来实现;

// 因为多个地方使用,所以选择class实现单例模式挂载到全局对象中
class AsyncEventQueue {
    constructor() {
        this.eventArray = {
            pending: false,
            eventQueue: []
        }
    }
    addQueueEvent(event) {
        this.eventArray.eventQueue.push(event)
        if(!this.eventArray.pending) {
            this.excuteEvent(event)
        }
    }
    async excuteEvent(event) {
        try{
            this.eventArray.pending = true
            await event()
        }catch(err){
            log.info(`队列任务失败,errMsg: ${err}`)
        } finally {
            this.eventArray.eventQueue.shift()
            this.eventArray.pending = false
            if(this.eventArray.eventQueue.length) {
                this.excuteEvent(this.eventArray.eventQueue[0])
            }
        }
    }
    clearQueue() {
        log.info(`清空队列`)
        this.eventArray = {
            pending: false,
            eventQueue: []
        }
    }
}

驱动(driver)

不知道大家有没有奇怪过一个问题,当我们使用orm框架的时候,还需要额外安装一个"驱动",e.g. mysql
简单看一下源码,主要提供以下功能:
1、实现mysql规范的私有协议,创建数据库连接;
2、创建连接池;
3、实现native sql语句查询;
也就是说我们在orm写查询时候,是在orm先translate为native sql,再通过驱动请求数据库实现crud的;

sql语句转换是在orm框架,连接池/连接是在驱动,分清楚这个职责有利于我们在遇到问题时候分析是哪里出现的问题;