servicecomb-pack icon indicating copy to clipboard operation
servicecomb-pack copied to clipboard

向TxEvent表中插入时,为什么将surrogateId初始化为-1?

Open pengyu0929 opened this issue 6 years ago • 7 comments
trafficstars

pengyu0929 avatar Jun 12 '19 08:06 pengyu0929

当alpha接收到omega的消息时,会将消息解析为TxEvent,在初始化时为什么将surrogateId设置为-1,这就导致只执行EntityManager.merge(),将entity交给EntityManager管理,之后都将entity和EntityManager缓存中的数据和表中的数据进行比较,这样严重影响了性能。 我的理解是:alpha接收到消息就应该执行EntityManager.persist(),直接保存。 我想知道你们这样做的目的是什么?

pengyu0929 avatar Jun 12 '19 08:06 pengyu0929

不知道你提到的是不是这个 https://github.com/apache/servicecomb-pack/blob/a54af97a65c52800b6ae684aac29b65eea600209/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/SpringTxEventRepository.java#L43。
surrogateid应该是系统分配的, EntityManager merge这块我不太清楚,能详细解释一下吗?

WillemJiang avatar Jun 12 '19 11:06 WillemJiang

@WillemJiang 是的,就是在执行save方法时,传进来的参数event中surrogateId=-1,这个值得设置实在上一步handle方法中通过调用TxEvent的构造函数初始化的,这就导致在使用jpa的SimpleJpaRepository的save方法时只会执行里边的merge方法。在save方法中会判断entity是否是新创建的(判断的条件是主键是否为null),因为此时entity的主键已经设置为-1了,所以只会执行merge方法(之后会将entity交给EntityManager管理)。 第一种情况:TxEvent主键使用自增 当surrogateId=-1时,我是用mysql没有问题,但是在使用oracle时会覆盖之前插入的记录,总之表中只会保存一条记录。 关于这个现象,我的猜测是: 在alpha接收到SagaStartEvent时,会将它插入数据库并且保存在EntityManager的缓存中,在之后进来的TxStartEvent(surrogateId=-1)执行merge(),merge()会在缓存和数据库中判断是否具有相同id的entity,只有满足一个,就会更新数据库和缓存。 第二种情况:TxEvent主键使用序列(指定我创建的序列) 当surrogateId=-1时,在使用oracle时只会保存第一次请求的SagaStartEvent,之后的TxStartEvent等等都没有插入,而且我发现在merge之后主键并没有回写,还是-1,这就导致保存在EntityManager缓存中的entity的主键为-1,下次在调用时merge时就会和EntityManager缓存中的entity主键一致,此时merge就会更新主键-1的记录,但是数据库没有,所以第一次插入的SagaStartEvent没有被覆盖(触发器使主键自增了)。 对于这两种情况,我把在调用TxEvent构造函数的-1设置为null,这样就会执行persist()(直接插入,不会进行对比),在修改的过程中我发现,eclipseLink支持在主键策略为IDENTITY时,也支持oracle,条件是你必须在数据库中创建一个它的默认序列(SEQ_GEN_IDENTITY),当然也可以使用自定义的序列,只需要在后面加上@SequenceGenerator,不必修改strategy的值。这样就解决上面的情况。

解决之后,我非常疑惑你们在new TxEvent时为什么要设置surrogateId=-1,而不是null。 -1时就会调用merge方法进行对比,影响了性能,而且没必要啊。 我现在就想知道你们为什么要用-1????

关于EntityManager https://blog.csdn.net/j080624/article/details/78751411

pengyu0929 avatar Jun 13 '19 01:06 pengyu0929

TxEvent 创建了之后是不会修改surrogateId的,之前的-1可能是随意填的一个值, 应该没有特殊意义。 欢迎就这个问题提交Patch, 你提到的默认序列是需要更新数据设置吧!

还有根据你的描述,你这边应该创建了oracle的数据库构造脚本,这部分的工作能提一个PR分享一下吗?

WillemJiang avatar Jun 13 '19 02:06 WillemJiang

-1 影响在save()中判断entity的状态是否为新创建的,导致之后alpha接收到的消息全部都执行merge(),而merge()是你需要update重复记录的情况下才会执行的。而我对alpha的理解是,它仅仅是用来保存、查询event,并向omega发送command的,不应该存在update的情况,所以alpha接收到event就应该执行persist(),而不是merge(),但是这个-1影响了这个过程。 还有就是如果使用oracle,在将-1改为null之后,最简单的方式是让使用者在数据库中创建eclipseLink默认的序列就行了,无需做其他更改。 我建议你们将这个-1改为null。

pengyu0929 avatar Jun 13 '19 03:06 pengyu0929

现在需要验证一下其他的数据库是否支持null的的情况。我建了一个JIRA SCB-1317跟踪这个问题, 一会推一个修改上来跑一下测试。

WillemJiang avatar Jun 13 '19 04:06 WillemJiang

@WillemJiang 如果使用oracle需要创建eclipseLink的默认序列SEQ_GEN_IDENTITY,其他无需更改

pengyu0929 avatar Jun 13 '19 05:06 pengyu0929