Play 2.6 访问SQL数据库

访问SQL数据库

Note: JDBC是一种阻塞操作。你不能直接在controller中运行JDBC查询语句。详见配置CustomExecutionContext章节

配置JDBC连接池

Play提供插件来管理连接池,你可以根据需要配置多个数据库。
为了启动数据库插件,需要添加以下依赖:

libraryDependencies += javaJdbc

然后需要字application.conf中配置连接池。出于方便考虑默认JDBC数据源必须叫做default

# Default database configuration
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"

如果需要添加别的数据源

# Orders database
db.orders.driver=org.h2.Driver
db.orders.url="jdbc:h2:mem:orders"

# Customers database
db.customers.driver=org.h2.Driver
db.customers.url="jdbc:h2:mem:customers"
H2
# Default database configuration using H2 database engine in an in-memory mode
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"

# Default database configuration using H2 database engine in a persistent mode
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:/path/to/db-file"
SQLite
# Default database configuration using SQLite database engine
db.default.driver=org.sqlite.JDBC
db.default.url="jdbc:sqlite:/path/to/db-file"
PostgreSQL
# Default database configuration using PostgreSQL database engine
db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://database.example.com/playdb"
MySql
# Default database configuration using MySQL database engine
# Connect to playdb as playdbuser
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/playdb"
db.default.username=playdbuser
db.default.password="a strong password"

获取JDBC数据源

play.db包提供了获取default数据的方法,主要是通过play.db.DataBase类

/*
 * Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com>
 */
package javaguide.sql;

import javax.inject.*;

import play.db.*;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

@Singleton
class JavaApplicationDatabase {

    private Database db;
    private DatabaseExecutionContext executionContext;

    @Inject
    public JavaApplicationDatabase(Database db, DatabaseExecutionContext context) {
        this.db = db;
        this.executionContext = executionContext;
    }

   public CompletionStage<Integer> updateSomething() {
       return CompletableFuture.supplyAsync(() -> {
           return db.withConnection(connection -> {
               // do whatever you need with the db connection
               return 1;
           });
       }, executionContext);
   }
}

对于其他的数据库

/*
 * Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com>
 */
package javaguide.sql;

import javax.inject.Inject;
import javax.inject.Singleton;

import play.mvc.Controller;
import play.db.NamedDatabase;
import play.db.Database;

// inject "orders" database instead of "default"
@javax.inject.Singleton
class JavaNamedDatabase {
    private Database db;
    private DatabaseExecutionContext executionContext;

    @Inject
    public JavaNamedDatabase(@NamedDatabase("orders") Database db, DatabaseExecutionContext executionContext) {
        this.db = db;
        this.executionContext = executionContext;
    }

    // do whatever you need with the db using supplyAsync(() -> { ... }, executionContext);
}

配置CustomExecutionContext

在使用JDBC时必须要使用一个自定义的执行上下文,来保证Play的线程池专注与页面处理以及自己的功能。可以使用Play的CustomExecutionContext来为JDBC操作配置一个执行上下文。可以在 JavaAsyncThreadPools来获取更多细节。

https://github.com/playframework/play-java-jpa-example/ 提供了一个例子,例子中展示了 JPAPersonRepository将所有的JDBC操作封装进了DatabaseExecutionContext中

由于线程池的大小对JDNC连接池有影响,在使用thred pool executor是,你需要一个可变大小的线程池来匹配连接池。根据[HikariCP]https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing)的建议,你需要将JDNC连接池的大小设置为物理核心数量的两倍再加上磁盘的数据。如果你又一个4核CPU加一个硬盘,你需要将连接池的大小设为9

# db connections = ((physical_core_count * 2) + effective_spindle_count)
fixedConnectionPool = 9

database.dispatcher {
  executor = "thread-pool-executor"
  throughput = 1
  thread-pool-executor {
    fixed-pool-size = ${fixedConnectionPool}
  }
}

获取JDBC连接

/*
 * Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com>
 */
package javaguide.sql;

import java.sql.Connection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import javax.inject.Inject;

import play.mvc.Controller;
import play.db.NamedDatabase;
import play.db.Database;

class JavaJdbcConnection {
    private Database db;
    private DatabaseExecutionContext executionContext;

    @Inject
    public JavaJdbcConnection(Database db, DatabaseExecutionContext executionContext) {
        this.db = db;
        this.executionContext = executionContext;
    }

    public CompletionStage<Void> updateSomething() {
        return CompletableFuture.runAsync(() -> {
            // get jdbc connection
            Connection connection = db.getConnection();

            // do whatever you need with the db connection
            return;
        }, executionContext);
    }

}

需要注意的是你要在代码的某个地方调用closs()方法。

通过JNDI暴露数据源

有些库需要通过JNDI来获取Datasource引用,可以在application.conf中进行如下配置

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.jndiName=DefaultDS

如何配置SQL log

不是所有的连接池都提供SQL语句的日志。HikariCP建议我们使用数据库提供商的log功能:

Log Statement Text / Slow Query Logging

就像是语句的缓存,大多数数据库提供商都支持SQL日志。其中的一些还能提供慢查询日志。我们认为这是一个开发阶段的特性。对于那些不支持的数据,jdbcdslog-exp是一个很好的选择

出于以上的原因,Play使用jdbcdslog-exp来启用SQL语句输出的支持,可以通过logSql来配置

# Default database configuration using PostgreSQL database engine
db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://database.example.com/playdb"
db.default.logSql=true

然后根据jdbcdslog-exp的手册(该连接需要科学上网)来配置日志级别。大体上,需要将root设置为info,然后确定jdbcdslog-exp输出哪些内容(连接,语句和结果集)。下面是一个例子

<!--
  ~ Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com>
  -->
<!-- The default logback configuration that Play uses if no other configuration is provided -->
<configuration>

  <conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${application.home:-.}/logs/application.log</file>
     <encoder>
       <pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
     </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
    </encoder>
  </appender>

  <appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="FILE" />
  </appender>

  <appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="STDOUT" />
  </appender>

  <logger name="play" level="INFO" />
  <logger name="application" level="DEBUG" />

  <!-- https://hibernate.atlassian.net/browse/HV-1323 -->
  <logger name="org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator" level="ERROR" />

  <logger name="org.jdbcdslog.ConnectionLogger" level="OFF"  /> <!-- Won' log connections -->
  <logger name="org.jdbcdslog.StatementLogger"  level="INFO" /> <!-- Will log all statements -->
  <logger name="org.jdbcdslog.ResultSetLogger"  level="OFF"  /> <!-- Won' log result sets -->

  <root level="WARN">
    <appender-ref ref="ASYNCFILE" />
    <appender-ref ref="ASYNCSTDOUT" />
  </root>

</configuration>
Note: 这些配置仅适用于开发环境。

配置JDBC驱动

如果使用MySql5,

libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.41"

选择和配置连接池

Play提供了两种连接池,HikariCP和BoneCP。默认的是HikariCP,可以进行修改

play.db.pool=bonecp

所有可配置的选择在 reference.conf(写在application.conf中应该也是可以的)

测试

查看Testing With Databases

启用Play数据库提升

根据文档查看Play数据库提升的用途及用法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值