JDBC client
这个客户端允许你在Vertx应用中使用异步API与JDBC数据库相交互.
JDBCClient
接口定义了异步方式的JDBC API
Creating a the client
下面的几种方式介绍了如何创建一个客户端:
Using default shared data source
在大多数情景中,你可能需要在不同的客户端实例(client instances)中共享同一个data source
.
例如,你想要通过部署多个verticle
实例来拓展应用的规模,然而每个verticle
都共享相同的datasource
,这样你就避免了多个datasource pool
了。
如下:
1 | JDBCClient client = JDBCClient.createShared(vertx, config); |
当第一次调用JDBCClient.createShared
的时候,确实会根据传进的配置创建出data source
. 但是当接下来再次调用这个方法的时候,也会创建一个新的客户端,但是它却没有创建新的data source
,因此第二次传进的配置也没有生效.
Specifying a data source name
在创建JDBCClient
实例的时候也可以指定data source
的名字
1 | JDBCClient client = JDBCClient.createShared(vertx, config, "MyDataSource"); |
如果使用相同的Vertx
实例和相同的data source
名字创建出不同的客户端,那这些客户端会使用相同的data source
.
使用这种创建方式你可以在不同的客户端上使用不同的datasource
, 例如和不同的数据库进行交互.
Creating a client with a non shared data source
虽然在大部分情况下不同的客户端实例需要共享相同的data source
,但是有时候也可能客户端需要一个非共享的data source
, 你可以使用JDBCClient.createNonShared
方法.
1 | JDBCClient client = JDBCClient.createNonShared(vertx, config); |
这种方式和调用JDBCClient.createShared
时传递一个唯一的data source
名字达到相同的效果.
Specifying a data source
如果你想使用一个已经存在的data source
, 那么你也可以直接使用那个data source
创建一个客户端.
1 | JDBCClient client = JDBCClient.create(vertx, dataSource); |
Closing the client
你可以在整个verticle
生命周期之内都持有客户端的引用,但是一旦你使用完该客户端你就应该主动关闭它.
由于data source
内部持有一个引用计数器,每当客户端关闭一次,data source
内部的技术器就会减1,当计数器为0的时候,data source
就会关闭自己.
Getting a connection
当你成功创建出客户端之后,你可以使用getConnection
方法来获得一个连接.
当连接池中有了可用连接之后,handler
会获得一个可用连接
1 | client.getConnection(res -> { |
获得的连接是一个SQLConnection
实例, SQLConnection
接口更多的是被Vert.x sql service
使用.
Configuration
当我们创建客户端时,向其传递了一个配置,该配置包含下面属性:
provider_class
: 用于管理数据库连接的类名. 默认的类名是io.vertx.ext.jdbc.spi.impl.C3P0DataSourceProvider
, 但是如果你想要使用其他连接池,那么你可以使用你自己的实现覆盖该属性.
因为我们使用了C3P0
的连接池,因此我们还可以使用下列属性
url
: 数据库的JDBC连接URL地址driver_class
: JDBCdirver
名称user
: 数据库名称password
: 数据库密码max_pool_size
: 连接池最大数量(默认是15)initial_pool_size
: 连接池初始大小(默认是3)min_pool_size
: 连接池最小值max_statements
: 缓存prepared statements
的最大值(默认是0)max_statements_per_connection
: 每个连接缓存prepared statements
的最大值(默认是0)max_idle_time
: 该值表示一个闲置连接多少秒后会被关闭(默认是0, 从不关闭).
如果你还想要配置其他C3P0
的配置,那么你可以在classpath
上添加一个c3p0.properties
文件
下面给出了一个配置示例:
1 | JsonObject config = new JsonObject() |
Vert.x MySQL - PostgreSQL client
MySQL / PostgreSQL
客户端为Vert.x应用提供了一个与MySQL / PostgreSQL
数据库交互的接口.
它使用Mauricio Linhares
开源驱动与MySQL / PostgreSQL
数据库进行非阻塞交互.
Creating a the client
下面给出了几种创建方式:
Using default shared pool
在大多数情况下,我们需要在多个客户端实例中共享同一个连接池
例如你通过部署多个verticle
实例的方式进行程序拓展,但是可以每个verticle
可以共享同一个连接池.
1 | JsonObject mySQLClientConfig = new JsonObject().put("host", "mymysqldb.mycompany"); |
MySQLClient.createShared
或者PostgreSQLClient.createShared
会根据指定的配置创建一个连接池. 随后再调用这俩个方式时会使用同一个连接池,同时新的配置不会被采用.
Specifying a pool name
你也可以像下面这样指定一个连接池的名字.
1 | JsonObject mySQLClientConfig = new JsonObject().put("host", "mymysqldb.mycompany"); |
如果不同的客户端使用相同的Vertx
实例和相同的连接池名字,那么他们将使用同一个连接池.
使用这种创建方式你可以在不同的客户端上使用不同的datasource
, 例如和不同的数据库进行交互.
Creating a client with a non shared data source
虽然在大部分情况下不同的客户端实例需要共享相同的data source
,但是有时候也可能客户端需要一个非共享的data source
, 你可以使用MySQLClient.createNonShared
或者PostgreSQLClient.createNonShared
方法.
1 | JsonObject mySQLClientConfig = new JsonObject().put("host", "mymysqldb.mycompany"); |
这种方式和调用MySQLClient.createNonShared
或者PostgreSQLClient.createNonShared
时传递一个唯一的data source
名字达到相同的效果.
Closing the client
你可以在整个verticle
生命周期之内都持有客户端的引用,但是一旦你使用完该客户端你就应该调用close
关闭它.
Getting a connection
当你成功创建出客户端之后,你可以使用getConnection
方法来获得一个连接.
当连接池中有了可用连接之后,handler
会获得一个可用连接
1 | client.getConnection(res -> { |
连接是SQLConnection
的一个实例, SQLConnection
是一个被Sql
客户端使用的公共接口.
需要注意的是
date
和timestamps
类型. 无论何时从数据库中获取date
时, 客户端会将它转换成ISO 8601
形式的字符串(yyyy-MM-ddTHH:mm:ss.SSS
).Mysql
会忽略毫秒数.
Configuration
PostgreSql
和MySql
使用了下面相同的配置:
1 | { |
host
: 数据库主机地址(默认是localhost
)port
: 数据库端口(PostgreSQL
默认是5432.MySQL
默认是3306)maxPoolSize
: 连接池保持开启的最大数量,默认是10.username
: 连接数据库使用的用户名.(PostgreSQL
的默认值是postgres
,MySQL
的默认值是root
)password
: 连接数据库使用的密码(默认没有设置密码).database
: 连接的数据库名称.(默认值是test
)
Common SQL interface
通用SQL
接口是用来和VertxSQL
服务交互的.
通过指定的SQL服务接口我们可以获取一个指定的连接.
The SQL Connection
我们使用SQLConnection
表示与一个数据库的连接.
Auto-commit
当连接的auto commit
被设置为true
. 这意味着每个操作都会在连接自己的事务中被高效地执行.
如果你想要在一个单独的事务中执行多个操作,你应该使用setAutoCommit
方法将auto commit
被设置为false
.
当操作完成之后,我们设置的handler
会自动地被调用.
1 | connection.setAutoCommit(false, res -> { |
Executing queries
我们使用query
来执行查询操作
query
方法的参数是原生SQL
语句, 我们不必使用针对不同的数据库使用不同的SQL
方言.
当查询完成之后,我们设置的handler
会自动地被调用. query
的结果使用ResultSet
表示.
1 | connection.query("SELECT ID, FNAME, LNAME, SHOE_SIZE from PEOPLE", res -> { |
ResultSet
实例中的getColumnNames
方法可以获得可用列名, getResults
可以获得查询真实的结果.
实际上,查询的结果是一个JsonArray
的List
实例,每一个元素都代表一行结果.
1 | List<String> columnNames = resultSet.getColumnNames(); |
另外你还可以使用getRows
获取一个Json
对象实例的List
, 这种方式简化了刚才的方式,但是有一点需要注意的是,SQL
结果可能包含重复的列名, 如果你的情景是这种情况,你应该使用getResults
.
下面给出了一种使用getRows
获取结果的示例:
1 | List<JsonObject> rows = resultSet.getRows(); |
Prepared statement queries
我们可以使用queryWithParams
来执行prepared statement
查询.
下例中,演示了使用方法:
1 | String query = "SELECT ID, FNAME, LNAME, SHOE_SIZE from PEOPLE WHERE LNAME=? AND SHOE_SIZE > ?"; |
Executing INSERT, UPDATE or DELETE
我们可以直接使用update
方法进行数据更新操作.
同样update
方法的参数同样是原生SQL
语句,不必使用SQL
方言.
当更新完成之后,我们会获得一个更新结果UpdateResult
。
我们可以调用更新结果的getUpdated
方法获得有多少行发生了改变, 而且如果更新时生成了一些key,那么我们可以通过getKeys
获得
1 | List<String> columnNames = resultSet.getColumnNames(); |
Prepared statement updates
如果想要执行prepared statement
更新操作,我们可以使用updateWithParams
.
如下例:
1 | String update = "UPDATE PEOPLE SET SHOE_SIZE = 10 WHERE LNAME=?"; |
Executing other operations
如果想要执行其他数据库操作,例如创建数据库,你可以使用execute
方法.
同样execute
执行的语句也是原生SQL
语句.当操作执行完之后,我们设置的handler
会被调用.
1 | String sql = "CREATE TABLE PEOPLE (ID int generated by default as identity (start with 1 increment by 1) not null," + |
Using transactions
如果想要使用事务,那么首先要调用setAutoCommit
将auto-commit
设置为false
.
接下来你就可以进行事务操作, 例如提交时使用commit
, 回滚时使用rollback
.
一旦commit/rollback
完成之后, 我们设置的handler
会被调用, 然后下一个事务会自动开始.
1 | connection.commit(res -> { |
Closing connections
当你执行完全部的操作之后,你应该使用close
将连接资源还给连接池.