欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Play 2.6 访问SQL数据库

程序员文章站 2022-05-17 20:05:24
...

访问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数据库提升的用途及用法。

相关标签: java play 2.6