shiny工程化实践之数据库

dplyr:翻译R到SQL

  • 基本数学运算: +, -, *, /, %%, ^

  • 数学函数: abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceiling, cos, cosh, cot, coth, exp, floor, log, log10, round, sign, sin, sinh, sqrt, tan, tanh

  • 逻辑判断: <, <=, !=, >=, >, ==, %in%

  • 异或判断: &, &&, |, ||, !, xor

  • 聚合函数: mean, sum, min, max, sd, var

支持常见的 SparkHiveMySQL作为计算引擎。

使用 explain 函数可以查看到对应的SQL翻译:

explain(your_dplyr_manipulation_chain)

pool:连接池管理

为什么在操作数据库上不是直接使用DBI,而是要多加一层pool呢?答案很简单,因为使用pool可以做连接池的管理,复用链接提升性能。pool为使用者提供了一个伪链接,如果是一条之前请求过的SQL,那么pool会将之前请求过的数据直接返回而无需等待。

Shiny中,pool会在所有session都结束的时候自动地回收资源而不需要其他操作。

这里是shiny官方blog上的一个例子:


library(shiny)
library(DBI)
library(pool)

pool <- dbPool(
  drv = RMySQL::MySQL(),
  dbname = "shinydemo",
  host = "shiny-demo.csa7qlmguqrf.us-east-1.rds.amazonaws.com",
  username = "guest",
  password = "guest"
)

ui <- fluidPage(
  textInput("ID", "Enter your ID:", "5"),
  tableOutput("tbl"),
  numericInput("nrows", "How many cities to show?", 10),
  plotOutput("popPlot")
)

server <- function(input, output, session) {
  output$tbl <- renderTable({
    sql <- "SELECT * FROM City WHERE ID = ?id;"
    query <- sqlInterpolate(pool, sql, id = input$ID)
    dbGetQuery(pool, query)
  })
  output$popPlot <- renderPlot({
    query <- paste0("SELECT * FROM City LIMIT ",
                    as.integer(input$nrows)[1], ";")
    df <- dbGetQuery(pool, query)
    pop <- df$Population
    names(pop) <- df$Name
    barplot(pop)
  })
}

shinyApp(ui, server)

数据库操作之事务

原来的显示事务操作

conn <- poolCheckout(pool)

dbWithTransaction(conn, {
  dbGetQuery(conn, A)
  dbGetQuery(conn, B)
})

poolReturn(conn)

现在的隐式事务操作

dbWithTransaction(pool, {
  dbGetQuery(pool, A)
  dbGetQuery(pool, B)
})

输入异常处理

因为有了req函数,我们可以在响应式代码块中轻松应对下面几类相似地空值判断:

  1. FALSE

  2. NULL

  3. ""

  4. 空的原子向量

  5. 仅仅包含缺失值的原子向量

  6. try-error 类的对象中出现包含的 FALSE 的逻辑向量 (可见于 ?base::try)

  7. 是否点击了 actionButton

下面是shiny 官方博客中的一个例子

library(shiny)

ui <- fluidPage(
  selectInput("datasetName", "Dataset", c("", "pressure", "cars")),
  plotOutput("plot"),
  tableOutput("table")
)

server <- function(input, output, session) {
  dataset <- reactive({
    # Make sure requirements are met
    req(input$datasetName)

    get(input$datasetName, "package:datasets", inherits = FALSE)
  })

  output$plot <- renderPlot({
    plot(dataset())
  })

  output$table <- renderTable({
    head(dataset(), 10)
  })
}

shinyApp(ui, server)

参考资料

阅读 3.3k

推荐阅读
FinanceR
用户专栏

循环写作,持续更新,形成闭环,贵在坚持

1011 人关注
61 篇文章
专栏主页