Scala使用Mongo4cats连接MongoDB不生效且无异常抛出问题求助
问题根因
- IO 实例未被实际执行
Cats Effect 的IO是惰性计算结构,仅构造IO实例不会触发任何实际的数据库操作、网络请求逻辑,你当前的代码只声明了操作流程,没有显式触发运行,所以无论连接串是否正确,程序都不会有实际动作也不会抛出异常。 - 连接串认证配置和本地 MongoDB 不匹配
你本地通过mongo-shell可以无密码直接访问服务,说明本地 MongoDB 未开启身份认证,你的代码连接串中携带的root:secret账号不存在,就算逻辑运行也会出现认证失败。 - 密封类 ADT 编解码潜在问题
PaymentMethod是密封 trait 结构,默认的 circe 自动推导可能无法正确处理多态序列化/反序列化,运行时容易抛出编解码错误。
解决方法
1. 替换主类继承关系,使用IOApp管理生命周期
Cats Effect 提供的IOApp会自动执行IO逻辑、管理程序生命周期,不需要手动调用unsafe方法,修改主类代码如下:
import cats.effect.{ExitCode, IO, IOApp, Resource} import mongo4cats.client._ import io.circe.generic.auto._ import mongo4cats.bson.ObjectId import mongo4cats.circe._ import java.time.Instant // 替换原来的普通App为IOApp object Main extends IOApp { val creditCard = CreditCard("John Bloggs", "1111222233334444", "1021", 919) val paypal = Paypal("hello.world@test.com") val payment1 = Payment(ObjectId(), BigDecimal(2.5), paypal, Instant.parse("2021-04-05T12:00:00Z")) val payment2 = Payment(ObjectId(), BigDecimal(9.99), creditCard, Instant.parse("2021-04-12T12:00:00Z")) // 本地未开认证去掉账号密码即可 val mongoClient: Resource[IO, MongoClient[IO]] = MongoClient.fromConnectionString[IO]("mongodb://127.0.0.1:27017") // 实现IOApp要求的run方法 override def run(args: List[String]): IO[ExitCode] = { mongoClient.use { client => for { db <- client.getDatabase("testdb") coll <- db.getCollectionWithCodec[Payment]("payments") _ <- coll.insertOne(payment1) _ <- coll.insertMany(List(payment2)) _ <- IO.println("数据插入完成") } yield ExitCode.Success } } }
2. 修复密封类编解码
如果运行后出现PaymentMethod相关的序列化错误,在模型定义文件中补充显式的编解码配置即可:
import io.circe.{Codec, Decoder, Encoder} import io.circe.generic.extras.Configuration import mongo4cats.bson.ObjectId import java.time.Instant // 增加circe多态配置 implicit val circeConfig: Configuration = Configuration.default.withDiscriminator("paymentType") sealed trait PaymentMethod implicit val paymentMethodCodec: Codec[PaymentMethod] = io.circe.generic.extras.semiauto.deriveConfiguredCodec[PaymentMethod] final case class Paypal(email: String) extends PaymentMethod final case class CreditCard( name: String, number: String, expiry: String, cvv: Int ) extends PaymentMethod final case class Payment( id: ObjectId, amount: BigDecimal, method: PaymentMethod, date: Instant )
内容的提问来源于stack exchange,提问作者sharingiscaring
相关产品推荐
相关产品推荐

