使用scalikejdbc操作数据库(一)加载配置参数并创建连接池

JDBC简介

JDBC是由SUN公司开发的一套开放标准的跨编程语言、跨数据库类型编程API。各数据库厂商根据这套规范开发自己数据库的驱动,通过驱动就可以操作自己的数据库。JDBC是接口,JDBC接口的驱动才是具体的实现类,没有驱动根本连接不上数据库。


JDBC操作数据库示意图

JDBC的基本组件和工作原理比较简单:核心组件就connection、statement(preparedstatement)两个对象。connection提供与数据库的连接以及数据处理的运行环境,statement是connection的一个属性,包含了可运行的SQL语句及对它们的各种运算方法

scalikejdbc加载配置

对于scala开发语言来说,scalikejdbc就是使用scala开发的一套基于JDBC去操作数据库的工具库。首先是scalikejdbc的配置,scalikeJDBC可以通过配置文件来设置连接池及全局系统参数。对配置文件的解析是通过TypesafeConfig工具库实现的。TypesafeConfig默认会去加载classpath下application.conf,application.json和application.properties文件。那么比较的简单的方式就是直接在默认加载的配置文件中写上对应数据库的链接配置

application.conf
# JDBC settings
db.default.driver="org.h2.Driver"
db.default.url="jdbc:h2:file:./db/default"
db.default.user="sa"
db.default.password=""
# Connection Pool settings
db.default.poolInitialSize=10
db.default.poolMaxSize=20
db.default.connectionTimeoutMillis=1000

# Connection Pool settings
db.default.poolInitialSize=5
db.default.poolMaxSize=7
db.default.poolConnectionTimeoutMillis=1000
db.default.poolValidationQuery="select 1 as one"
db.default.poolFactoryName="commons-dbcp2"

db.legacy.driver="org.h2.Driver"
db.legacy.url="jdbc:h2:file:./db/db2"
db.legacy.user="foo"
db.legacy.password="bar"

# MySQL example
db.default.driver="com.mysql.jdbc.Driver"
db.default.url="jdbc:mysql://localhost/scalikejdbc"

# PostgreSQL example
db.default.driver="org.postgresql.Driver"
db.default.url="jdbc:postgresql://localhost:5432/scalikejdbc"

初始化链接参数

DBs.setup()

def setup(dbName: Symbol = ConnectionPool.DEFAULT_NAME): Unit = {
    val JDBCSettings(url, user, password, driver) = readJDBCSettings(dbName)
    ...
  }

def readJDBCSettings(dbName: Symbol = ConnectionPool.DEFAULT_NAME): JDBCSettings = {
    val configMap = self.readAsMap(dbName)
    // https://github.com/scalikejdbc/scalikejdbc/issues/494#issuecomment-184015480
    // never forcing scalikejdbc-config users to load JDBC drivers in global
    val driver = configMap.getOrElse("driver", "")
    (for {
      url <- configMap.get("url")
    } yield {
      val user = configMap.get("user").orElse(configMap.get("username")).orNull[String]
      val password = configMap.get("password").orNull[String]
      JDBCSettings(url, user, password, driver)
    }) getOrElse {
      throw new ConfigurationException("Configuration error for database " + dbName + ". " + configMap.toString)
    }
  }

def readAsMap(dbName: Symbol = ConnectionPool.DEFAULT_NAME): Map[String, String] = try {
    val configMap: MutableMap[String, String] = MutableMap.empty

    {
      val dbConfig = config.getConfig(envPrefix + "db." + dbName.name)
      val iter = dbConfig.entrySet.iterator
      while (iter.hasNext) {
        val entry = iter.next()
        val key = entry.getKey
        if (attributeNames.contains(key)) {
          configMap(key) = config.getString(envPrefix + "db." + dbName.name + "." + key)
        }
      }
    }
    ...

通过源码可以发现读取配置的时候scalikejdbc在application.conf文件加载配置默认是读取以db.default开头的参数。我们也可以将default改为其他的名字xxx,加载方式就变为DBs.setup("xxx")。但是这种加载方式仍然是有限制的就是必须以db开头,这在我们实际的项目中大多的时候比如mysql的链接配置并不是以db开头的,这时候我们可以通过反射机制加载数据库的配置

def getMySQL(key: String) = {
    Map(
      "url" -> SubsConfig(s"app.mysql.${key}.url"),
      "driver" -> "com.mysql.jdbc.Driver",
      "user" -> SubsConfig(s"app.mysql.${key}.user"),
      "password" -> SubsConfig(s"app.mysql.${key}.password")
    )
  }
val db = getMySQL(key)
Class.forName(db("driver"))
ConnectionPool.singleton(db("url"), db("user"), db("password"))

上述方式中获取mysql配置的参数名就可以是任意指定的名称,并且通过ConnectionPool.singleton的方式生成一个数据库连接池。但是这种生成连接池默认的name是default。

def singleton(url: String, user: String, password: String,
    settings: CPSettings = ConnectionPoolSettings())(implicit factory: CPFactory = DEFAULT_CONNECTION_POOL_FACTORY): Unit = {
    add(DEFAULT_NAME, url, user, password, settings)(factory)
    log.debug("Registered singleton connection pool : " + get().toString())
  }

val DEFAULT_NAME: Symbol = 'default

如果项目中操作mysql的库只有一个,那么这种方式是没有问题的,但是如果一个程序中使用到两个不同的库时,在生成第二个库的连接池时就会将第一个连接池给覆盖,因为名字都是default。解决这个问题的方式就是我们直接使用ConnectionPool中的add方法

ConnectionPool.add(key, db("url"), db("user"), db("password"))

key就是区分两个库的名字。singleton方法就是直接调用了add方法,不过连接池默认传了default。到此,scalikejdbc操作数据库的连接池就创建完成了,后续我们就可以通过连接池操作数据库。

注:如果我们程序中出现了多次创建连接池的情况,就可以先判断要创建的连接池是否已经被创建,如果已经有了,就可以直接使用ConnectionPool.borrow方法获取需要的连接池

if (!ConnectionPool.isInitialized(key)) {
      ConnectionPool.add(key, db("url"), db("user"), db("password"))
    }
 ConnectionPool.borrow(key)

下一章我们就一起来学习scalikejdbc增删改查的方法

欢迎对技术感兴趣的小伙伴一起交流学习,批评指正^^

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容