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.h 2.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操作配置一個執行上下文。可以在 JavaAsync 和ThreadPools來獲取更多細節。
由於執行緒池的大小對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中應該也是可以的)
測試
啟用Play資料庫提升
根據文件檢視Play資料庫提升的用途及用法。