使用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增删改查的方法

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342