使用sharding做分库分表,使用jpa,发生的save不报错,数据库缺插不进去数据的问题

  先讲讲问题的诞生,我们项目起初没有引进 sharding分库,而是在项目上线前,才做的分库分表。也就是之前的业务都写好的,所以知道业务代码没有任何问题。

  然后引入 sharding 的相关的依赖以后,分库分表的先关配置都做好,可以保证没有任何的问题以后。

  当然了,sharding不支持一些sql,比如 distinct,比如 聚合函数需要起一个别名。这些问题都排查过了。

  问题出现在,跑 test 测试类的时候,发现程序也不报错,但是数据库里边没有数据进去。奇怪就奇怪在 启动项目,通过postmen 调用controller 的形式, 就能插进去数据。这足以说明数据库没问题。sharding配置没问题,程序代码也没问题。

  定时任务里边调用 service ,也不行,就和 test 一样,打印sql,发现没有insert语句。这就很奇怪了,咋好好的跑测试类,就没有 insert语句了呢?

 

# # 起初的毫无头绪

  就觉得这个问题很神奇。缺没有任何排查的思路,可能还是太年轻了。

 

# # 接下来看看我的解题思路

  我觉得虽然问题有可能不是通一个问题,但是解决问题的思路都相似,这就是经验,这就是方法论。

  不报错,只有数据库插不进去数据的现象,却没有任何报错信息。这怎么办?我相信,只拿着这个现象去搜,决绝有一大堆不想干的帖子出来干扰你。

   我的搜索词条是: 使用jpa,save无法插入数据库数据数据。

  果然,有很多的帖子,但是都和我的不相关,因为他们都是单纯的环境没部好,因为我之前的 save没问题,只是在使用sharding以后才有问题。保存不进去值的问题,我看了网上几乎所有的帖子,谷歌到了 2010年的帖子,都是在说 save不进去值的问题。 没有一个是和我相关的答案。

  所以花了很多时间,几乎看到想吐。很多就是问题描述不清楚。

 

# # 如此奇怪的现象,走投无路,我只能用排除法

 既然这个问题是引入 sharidng以后才出现的,是不是sharding版本的问题?于是,我重新搭了环境,换成了高版本的 sharding 的依赖。之前的数据库是 PG,我换成了mysql,发现,竟然没问题,test的 save能保存进去数据。然后把项目的依赖也进行了升级。发现还是不好使。

  然后,还是用排除法,我又重新搭建了项目。在父工程下,创建了一个子项目,然后所有的依赖都用原来的。就是纯净的环境,最简单的测试,一个实体类,因为用的 JPA,所以只用一个 repository,然后 一层 service,一个测试类。就和原来的套路一样,结果发现,test能插进去数据。

  问题又回到了诡异状态,为什么项目就不能跑。重新搭建的就可以?还是一头雾水。

 

# # 我把 save 改成了 saveAndFlush 

  于是开始报错了,报一个没有事务的错误:描述如下:

org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress

  你去搜这个问题,一定告诉你的是,让你添加 @Transactional 注解。我明明加过了,启动项目,调用controller就不报错,跑测试类就出错。

  因为实在没思路了,只能盯着报错的去一层一层的看了。为啥我启动项目就可以,跑测试类就报错呢?

  我找DBA帮忙看看,她也是看到 select语句,没有任何 insert 语句。让他帮我盯着事务看一看,没有看到。

  这就奇怪了,我明明加了事务的, 却报没有事务的错。错肯定不会好端端的报出来的。在这种奇怪的情况下,我的直觉就是 事务的问题。究竟是怎么产生的,我还是没头绪。一直觉得不是自己的错。

 

# # 我开始排查事务管理器

 也查看了很多文章,事务相关的问题。这个思路是来源于 save保存不进去数据,这问题进行谷歌,很多人,都说事务回滚什么的。根据我的情况,我排查觉得,是不是到了这里,事务已经提交了,所以只有 select 没有 insert。是不是事务提交了,可是又为什么会提交了呢?

  为什么回报没有事务的错误呢? 然后看到文章,有查看事务管理器的,我就拿着报错的项目,和不报错的项目对比。发现事务管理器用的不相同。根据上边的排除,不是依赖的错误,不是代码的错误,不是数据库的错误。差异看到的就只有这个事务管理器了。我就想着更换一下事务管理器,正确的项目用的是 jpa 的事务管理器,我出问题的是用的 dataSource 的事务管理器。springboot 默认注入的。

  于是就切换:具体情况我这篇文章

  切换以后,问题还真解决了。

 

# # 为啥同样的环境,用的却不是同一个事务管理器呢

  我也查了文章:可以看看这篇文章:http://c.biancheng.net/view/4644.html

  我只引入了 jpa 的starter,但是却没有用 jpa 的事务管理器,这个还要在项目里边排查。看看究竟是怎么回事。后续再更新出来。

 

# # 总结

   前几天还遇到过一个奇怪的现象,就是控制台报错,不一定准。即使明明给你准确的一行,也不一定准,还是要单独拿出来测试的。

  遇到问题,特别是奇怪的问题。都是要硬着头皮解决的。重新搭环境,搞出来正确的,再去对比,有时候也是很好用的方案。

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章