简体   繁体   中英

How to create a Scala Jdbc program using Option to handle null while returning connection?

I am trying to write a scala-jdbc program which will run an analyze statement on tables present on our database. To do that, I wrote the code as below.

object Trip {
    def main(args: Array[String]): Unit = {
        val gs = new GetStats(args(0))
        gs.run_analyze()
    }
}
-----------------------------------------------------------------
class GetStats {
    var tables = ""
    def this(tables:String){
        this
        this.tables = tables
    }
    def run_analyze():Unit = {
        val tabList = tables.split(",")
        val gpc = new GpConnection()
        val con = gpc.getGpCon()
        val statement = con.get.createStatement()
        try {
            for(t<-tabList){
                val rs = statement.execute(s"analyze ${t}")
                if(rs.equals(true)) println(s"Analyzed ${t}")
                else println(s"Analyze failed ${t}")
            }
        } catch {
            case pse:PSQLException => pse.printStackTrace()
            case e:Exception       => e.printStackTrace()
        }
    }
}
-----------------------------------------------------------------
class GpConnection {
    var gpCon: Option[Connection] = None
    def getGpCon():Option[Connection] = {
        val url      = "jdbc:postgresql://.."
        val driver   = "org.postgresql.Driver"
        val username = "user"
        val password = "1239876"
        Class.forName(driver)
            if(gpCon==None || gpCon.get.isClosed) {
            gpCon = DriverManager.getConnection(url, username, password).asInstanceOf[Option[Connection]]
            gpCon
        } else gpCon
    }    
}

I create a jar file on my idea (IntelliJ) and submit the jar as below.

scala -cp /home/username/jars/postgresql-42.1.4.jar analyzetables_2.11-0.1.jar schema.table

When I submit the jar file, I see the exception ClassCastException as given below.

java.lang.ClassCastException: org.postgresql.jdbc.PgConnection cannot be cast to scala.Option
    at com.db.manager.GpConnection.getGpCon(GpConnection.scala:15)
    at com.gp.analyze.GetStats.run_analyze(GetStats.scala:19)
    at com.runstats.Trip$.main(Trip.scala:8)
    at com.runstats.Trip.main(Trip.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at scala.reflect.internal.util.ScalaClassLoader.$anonfun$run$2(ScalaClassLoader.scala:98)
    at scala.reflect.internal.util.ScalaClassLoader.asContext$(ScalaClassLoader.scala:32)
    at scala.reflect.internal.util.ScalaClassLoader.asContext(ScalaClassLoader.scala:30)
    at scala.reflect.internal.util.ScalaClassLoader.run$(ScalaClassLoader.scala:98)
    at scala.reflect.internal.util.ScalaClassLoader.run(ScalaClassLoader.scala:90)
    at scala.tools.nsc.CommonRunner.run$(ObjectRunner.scala:22)

The exception says that connection cannot be casted to scala.option but if I don't use Option, I cannot use null to initialize the connection object & I see NullPointerException when I run the code. Could anyone let me know what is the mistake I am making here and how can I fix it ?

You can use an uninitialized var as:

var gpCon: Connection = _

But since you are using scala.util.Option which is a better thing to do, do it in a functional way and don't write imperative Java code in Scala, like:

// a singleton object (Scala provided)
object GpConnection {
    private var gpCon: Option[Connection] = None

    // returns a Connection (no option - as we need it!)
    def getOrCreateCon(): Connection = gpCon match {
        case conOpt if conOpt.isEmpty || conOpt.get.isClosed =>
            // connection not present or is closed
            val url      = "jdbc:postgresql://.."
            val driver   = "org.postgresql.Driver"
            val username = "user"
            val password = "1239876"

            // may throw an exception - you can even handle this
            Class.forName(driver)

            // may throw an exception - you can even handle this
            gpCon = Option(DriverManager.getConnection(url, username, password).asInstanceOf[Connection])
            gpCon.getOrElse(throw new RuntimeException("Cannot create connection"))
        case Some(con) => con
    }    
}

use it like:

val con = GpConnection.getOrCreateCon

asInstanceOf[] doesn't work that way. It won't just create an Option[] for you.

val x:Option[Int] = 5.asInstanceOf[Option[Int]]  //not gonna happen

You have to create the Option[] explicitly.

val x:Option[Int] = Option(5)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM