由于GF本身不支持处理ORM的事务嵌套,所以给业务微化封装带来不少麻烦。写代码也不再顺畅。

经过不断地尝试,我在自己使用的GF业务框架中解决了此问题。

首先,我将所有的DAO操作进行了一次封装。不再直接使用Dao单例实例。而是由一个方法来统一生成。这些方法会属于TransactionManage类

同时,让每一个Service继承自一个TransactionManage类,该类主要用于管理tx(这里为了保证tx统一性,用到了指针的指针)及提供事务方法Transaction。

这样,当我们需要开启事务时,只需要在service中调用父类的Transaction即可,在Transaction中会先判断是否存在tx对象,存在则直接调用回调函数(不再开启新事务),不存在则开启一个新的事务,并保存新事务的指针到txp(tx指针的指针)中。

而在api中,也有类似service的实现。只不过,会有一系列service类的封装函数。

这样,在整个调用过程中,就会如下:api → getXXXService() → getXXXDao() ,在每次调用时,会传递存在的tx对象指针。不管在哪一层开启了事务。均可判断是否存在上一级的TX,而通过此来判断是否需要开启新事务。

这里使用时,需要在api中,每次调用 GetServiceManage()来创建service管理对象。这个管理对象会在创建新的service时被传递下去。

这样调整后,Dao调用只是加了一层封装。本质上还是在封装中决策是否调用Dao.TX方法还是直接返回Dao.XXXDao。如下:


func (this BaseManage) TokenDao() *internal.TokenDao {
    if tx := this.TX(); tx == nil {
        return Token.TokenDao
    } else {
        return Token.TX(tx)
    }
}


而这个BaseMange是dao.BaseMange,是manage.TransactionManage的子类。故尔,其拥有 tx管理及开启事务的方法封装。

service由原来的单例改为了实时创建。创建后的service对象会放于serviceInstanceManage中管理起来,这样二次使用时,不会重复创建。




func NewServiceManage() *ServiceManage {
    o := new(ServiceManage)
    o.trans.TXP(new(*gdb.TX))
    o.ServiceInstancesManage.TransactionManage = &o.trans
    return o
}



//用于service
type BaseManage struct {
    dao.BaseManage
    service *ServiceInstancesManage
}

func (this *BaseManage) Init() { //构造函数,空方法,占位

}

func (this *BaseManage) Destroy() { //析构函数,空方法,占位

}

type ServiceInstancesManage struct {
    *manage.TransactionManage

    accessTokenService   *accessTokenService
    //其它service 


}

func (this *ServiceInstancesManage) AccessTokenService() *accessTokenService {
    sp := &this.accessTokenService
    if *sp == nil {
        *sp = new(accessTokenService)
        (*sp).service = this
        (*sp).Init()
    }
    (*sp).TXP(this.TXP())
    return *sp
}





同时,serviceInstanceManage也是manage.TransactionManage的子类。在使用时,应该在api中调用NewServiceManage()生成管理对象,之后就可以在管理对象中调用需要使用的service方法(这里为AccessTokenService() )。而该AccessTokenService继承自service.BaseMange从而继承自dao.BaseManage,当在service内需要调用其它service时,需要可以如此调用:this.service.AccessTokenService()..... 这样整个事务就会被传递。


经测试,事务嵌套已经实现。不过这里可能存在内存泄露,还需要进一步完善代码。


当然,具体的代码有很多细节需要处理。这里只是说了一个大概。只是引个思路。也希望作者能有更佳的解决方案。