Vert.x 异步访问数据库 MySQL
Vert.x提供异步访问数据库的API,数据库操作是一个耗时操作,使用传统的同步模型,容易阻塞线程,导致整体性能下降,因此我们对于数据库操作,需要使用Vert.x提供的异步API。
Vert.x提供的API层级非常低,可以说是仅仅在原生JDBC基础上封装了一层异步接口。所有的对数据库操作都需要通过编写SQL来完成,参数的封装和结果的获取都需要手动的来实现,对于习惯使用ORM框架的开发者可能会非常的不习惯。
先来通过一个查询数据库的案例来演示如何使用Vert.x提供的异步API
基本操作
1.引入数据库依赖,我们需要引入两个包,一个是vertx-jdbc,另一个是要真正连接数据库的驱动包,这里以MySQL为例
1 <dependency> 2 <groupId>io.vertx</groupId> 3 <artifactId>vertx-jdbc-client</artifactId> 4 <version>3.6.0</version> 5 </depend 6 7 <dependency> 8 <groupId>mysql</groupId> 9 <artifactId>mysql-connector-java</artifactId> 10 <version>8.0.13</version> 11 </dependency>
2.抽象出一个DbUtils来方便获取数据库客户端,为了简单,直接就将配置写到代码里了
1 public class JdbcUtils { 2 3 // 用于操作数据库的客户端 4 private JDBCClient dbClient; 5 6 public JdbcUtils(Vertx vertx) { 7 8 // 构造数据库的连接信息 9 JsonObject dbConfig = new JsonObject(); 10 dbConfig.put("url", "jdbc:mysql://192.168.40.66:3306/test"); 11 dbConfig.put("driver_class", "com.mysql.jdbc.Driver"); 12 dbConfig.put("user", "xxxx"); 13 dbConfig.put("password", "xxxx"); 14 15 // 创建客户端 16 dbClient = JDBCClient.createShared(vertx, dbConfig); 17 } 18 19 // 提供一个公共方法来获取客户端 20 public JDBCClient getDbClient() { 21 return dbClient; 22 } 23 24 }
通过上面的工具类,可以快速的获取到客户端,看上面的代码也很简单,通过JsonObect构建一些基本的数据库连接信息,然后通过JDBCClient的createShard方法创建一个JDBCClient实例。
3.进行数据库的操作,以查询年龄大于18岁的用户为例
1 public class JdbcTestVerticle extends AbstractVerticle { 2 3 @Override 4 public void start() throws Exception { 5 6 // 获取到数据库连接的客户端 7 JDBCClient jdbcClient = new JdbcUtils(vertx).getDbClient(); 8 String sql = "select * from t_user where age > ?"; 9 // 构造参数 10 JsonArray params = new JsonArray().add(18); 11 // 执行查询 12 jdbcClient.queryWithParams(sql, params, qryRes->{ 13 if(qryRes.succeeded()) { 14 // 获取到查询的结果,Vert.x对ResultSet进行了封装 15 ResultSet resultSet = qryRes.result(); 16 // 把ResultSet转为List<JsonObject>形式 17 List<JsonObject> rows = resultSet.getRows(); 18 // 输出结果 19 System.out.println(rows); 20 } else { 21 System.out.println("查询数据库出错!"); 22 } 23 }); 24 25 } 26 27 public static void main(String[] args) { 28 Vertx vertx = Vertx.vertx(); 29 vertx.deployVerticle(new JdbcTestVerticle()); 30 } 31 }
JsonArray是一个数组,SQL中用到的参数可以通过构建一个JsonArray来赋值。
JsonObejct是一个Json对象,类似于阿里的fastjson中提供的JSONObject
这两个对象在Vert.x中非常常用,而且非常的好用,但一定要注意空指针的问题,这是非常让人头疼的。
优化
通过上面的三个步骤,就可成功的对数据库进行操作了,但还有些问题需要优化,比如数据库连接信息放到配置文件中,再比如使用数据库连接池等等。
* 使用配置文件
1 { 2 "default":{ 3 "url":"jdbc:mysql://localhost:3306/my_project", 4 "driver_class":"com.mysql.cj.jdbc.Driver", 5 "user":"root", 6 "password":"root" 7 }, 8 "prod":{ 9 "url":"jdbc:mysql://localhost:3306/my_project", 10 "driver_class":"com.mysql.cj.jdbc.Driver", 11 "user":"root", 12 "password":"root" 13 } 14 } 15 修改DbUtils工具类 16 17 public class JdbcUtils { 18 19 private JDBCClient dbClient; 20 private static JsonObject config ; 21 22 static { 23 byte[] buff = new byte[102400]; 24 try { 25 // 读取配置文件 26 InputStream ins = new FileInputStream("db.json"); 27 int i = IOUtils.read(ins, buff); 28 config = new JsonObject(new String(buff, 0, i)); 29 } catch (Exception e) { 30 System.out.println("读取配置文件失败"); 31 } 32 } 33 34 public JdbcUtils(Vertx vertx, String dsName) { 35 JsonObject dbConfig = config.getJsonObject(dsName); 36 if(dbConfig == null) { 37 throw new RuntimeException("没有找到指定的数据源"); 38 } 39 dbClient = JDBCClient.createShared(vertx, dbConfig); 40 } 41 42 public JdbcUtils(Vertx vertx) { 43 this(vertx, "default"); 44 } 45 46 public JDBCClient getDbClient() { 47 return dbClient; 48 } 49 50 }
这样就支持了多个数据源,而且数据库连接配置都放到了配置文件中。
连接池配置
数据连接池默认使用的C3P0,所以可以在db.json中进行配置C3P0连接池的参数就可以了,这里官网的地址为:https://vertx.io/docs/vertx-jdbc-client/java/
具体配置可以参考官网给出的配置,下面是一个简单的截图
遗憾的是,Vert.x给出的数据库连接池的支持并不多,如果我们想要使用比如阿里的Druid连接池,需要自己来实现DataSourceProvider。当然DataSourceProvider的实现并不复杂,但麻烦啊!后面我会给出一个关于druid的DataSourceProvider的实现。
事务
Vert.x从比较低的层面来控制事务,不像Spring一样可以使用声明式事务管理。要想在Vert.x中开启事务,和传统的JDBC管理事务的方式非常类似。首先要获得到连接,然后调用连接的setAutoCommit方法,关闭事务的自动提交,然后再手动的提交和回滚事务。
因为开启事务、提交事务、执行SQL都需要和数据库服务进行通信,因此在Vert.x中都是异步操作,按传统方式实现一个事务代码非常痛苦,看下面的一段开启事务的代码。写了一遍以后,绝对不愿意再写第二遍。
1. 获得连接
// 获得连接 jdbcClient.getConnection(con -> { if (con.succeeded()) { System.out.println("获取到数据库连接");// 获取到的连接对象 SQLConnection connection = con.result(); } });
2. 设置不自动提交事务
1 // 开启事务 2 connection.setAutoCommit(false, (v) -> { 3 if (v.succeeded()) { 4 5 } 6 });
3.dml操作
1 // 执行更新操作 2 connection.update("sql", upRes -> { 3 if(upRes.succeed()){ 4 5 } 6 });
4. 提交事务
1 // 提交事务 2 connection.commit(rx -> { 3 if (rx.succeeded()) { 4 // 事务提交成功 5 } 6 });
回滚事务
1 // 回滚事务 2 connection.rollback(rb -> { 3 if (rb.succeeded()) { 4 // 事务回滚成功 5 } 6 });
如果你觉得上面的还很简单,看看下面一个完整的例子吧,把这些嵌套在一起,你还觉得简单吗?
1 package stu.vertx.jdbc; 2 3 import io.vertx.core.AbstractVerticle; 4 import io.vertx.core.Vertx; 5 import io.vertx.ext.jdbc.JDBCClient; 6 import io.vertx.ext.sql.SQLConnection; 7 8 /** 9 * 获得数据库连接,执行查询,开启事务,执行更新操作 10 * 11 * @author <a href="https://blog.csdn.net/king_kgh>Kingh</a> 12 * @version 1.0 13 * @date 2019/4/3 9:19 14 */ 15 public class GetConnection extends AbstractVerticle { 16 17 @Override 18 public void start() throws Exception { 19 20 JDBCClient jdbcClient = new JdbcUtils(vertx).getDbClient(); 21 System.out.println("获取到数据库客户端"); 22 // 获取数据库连接 23 jdbcClient.getConnection(con -> { 24 if (con.succeeded()) { 25 System.out.println("获取到数据库连接"); 26 27 // 获取到的连接对象 28 SQLConnection connection = con.result(); 29 30 // 执行查询操作 31 connection.query("select * from t1", rs -> { 32 // 处理查询结果 33 if (rs.succeeded()) { 34 System.out.println(rs.result().getRows()); 35 } 36 }); 37 38 // 开启事务 39 connection.setAutoCommit(false, (v) -> { 40 if (v.succeeded()) { 41 // 事务开启成功 执行crud操作 42 connection.update("update t1 set name = '被修改了' where name = '111'", up -> { 43 44 if (up.succeeded()) { 45 // 再来一笔写操作 46 connection.update("insert into t1 values ('222','222222') ", up2 -> { 47 if (up2.succeeded()) { 48 // 提交事务 49 connection.commit(rx -> { 50 if (rx.succeeded()) { 51 // 事务提交成功 52 } 53 }); 54 } else { 55 connection.rollback(rb -> { 56 if (rb.succeeded()) { 57 // 事务回滚成功 58 } 59 }); 60 } 61 }); 62 } else { 63 connection.rollback(rb -> { 64 if (rb.succeeded()) { 65 // 事务回滚成功 66 } 67 }); 68 } 69 }); 70 71 } else { 72 System.out.println("开启事务失败"); 73 } 74 }); 75 } else { 76 System.out.println("获取数据库连接失败"); 77 } 78 }); 79 80 81 } 82 83 public static void main(String[] args) { 84 Vertx.vertx().deployVerticle(new GetConnection()); 85 } 86 }
View Code
RxJava解决多层回调嵌套问题
上面的代码仅仅是做了两个写操作,可以说是非常的痛苦了,一层一层的嵌套,根本没法维护。那么在真实的开发环境中,该如何管理事务呢,这就需要使用rxjava了,能够有效的减少多层嵌套带来的问题。使用rxjava首先是需要引入rxjava的依赖
1 <dependency> 2 <groupId>io.vertx</groupId> 3 <artifactId>vertx-rx-java</artifactId> 4 <version>3.7.0</version> 5 </dependency>
完成上面案例的同样代码如下
1 package stu.vertx.jdbc; 2 3 import io.vertx.core.*; 4 import io.vertx.core.json.JsonArray; 5 import io.vertx.ext.jdbc.JDBCClient; 6 import io.vertx.ext.sql.SQLConnection; 7 import rx.Single; 8 9 import java.util.UUID; 10 11 /** 12 * 15 */ 16 public class GetConnectionWithRxJava extends AbstractVerticle { 17 18 @Override 19 public void start() throws Exception { 20 21 // 获取JDBC客户端 22 JDBCClient jdbcClient = new JdbcUtils(vertx).getDbClient(); 23 24 getConnection(jdbcClient, con -> { 25 if (con.succeeded()) { 26 // 获取到与数据库的连接 27 SQLConnection connection = con.result(); 28 29 // 开启事务 30 rxOpenTx(connection) 31 // 执行写操作 32 .flatMap(this::rxExecuteUpdate1) 33 // 执行写操作 34 .flatMap(this::rxExecuteUpdate2) 35 .subscribe(ok -> { 36 // 提交事务 37 ok.commit(v -> { 38 }); 39 }, err -> { 40 // 回滚事务 41 connection.rollback(v -> { 42 }); 43 }); 44 } 45 }); 46 } 47 48 public Single<SQLConnection> rxOpenTx(SQLConnection connection) { 49 return Single.create(new io.vertx.rx.java.SingleOnSubscribeAdapter<>(fut -> openTx(connection, fut))); 50 } 51 52 public Single<SQLConnection> rxExecuteUpdate1(SQLConnection connection) { 53 return Single.create(new io.vertx.rx.java.SingleOnSubscribeAdapter<>(fut -> update1(connection, fut))); 54 } 55 56 public Single<SQLConnection> rxExecuteUpdate2(SQLConnection connection) { 57 return Single.create(new io.vertx.rx.java.SingleOnSubscribeAdapter<>(fut -> update2(connection, fut))); 58 } 59 60 public void getConnection(JDBCClient jdbcClient, Handler<AsyncResult<SQLConnection>> resultHandler) { 61 jdbcClient.getConnection(con -> { 62 if (con.succeeded()) { 63 resultHandler.handle(Future.succeededFuture(con.result())); 64 } else { 65 resultHandler.handle(Future.failedFuture(con.cause())); 66 } 67 }); 68 } 69 70 public void openTx(SQLConnection connection, Handler<AsyncResult<SQLConnection>> resultHandler) { 71 connection.setAutoCommit(false, o -> { 72 if (o.succeeded()) { 73 resultHandler.handle(Future.succeededFuture(connection)); 74 } else { 75 resultHandler.handle(Future.failedFuture(o.cause())); 76 } 77 }); 78 } 79 80 public void update1(SQLConnection connection, Handler<AsyncResult<SQLConnection>> resultHandler) { 81 connection.updateWithParams("insert into t1 values (?,?)", new JsonArray().add(UUID.randomUUID().toString()).add(UUID.randomUUID().toString()), in -> { 82 if (in.succeeded()) { 83 resultHandler.handle(Future.succeededFuture(connection)); 84 } else { 85 resultHandler.handle(Future.failedFuture(in.cause())); 86 } 87 }); 88 } 89 90 public void update2(SQLConnection connection, Handler<AsyncResult<SQLConnection>> resultHandler) { 91 connection.update("update t1 set name = '111' where passwd = '111'", in -> { 92 if (in.succeeded()) { 93 resultHandler.handle(Future.succeededFuture(connection)); 94 } else { 95 resultHandler.handle(Future.failedFuture(in.cause())); 96 } 97 }); 98 } 99 100 public static void main(String[] args) { 101 Vertx.vertx().deployVerticle(new GetConnectionWithRxJava()); 102 } 103 }
通过使用RxJava,没有那么深的嵌套层次,逻辑比较清晰。当然了,为了一个简单的操作,还是需要写很多的代码。
转载于:https://www.cnblogs.com/endv/p/11247947.html
Vert.x 异步访问数据库 MySQL相关推荐
- java 入侵 mysql_Java访问数据库Mysql
一.概述 本文主要介绍Java接连数据库的基本方法和步骤,并对其中的几个要点进行简要说明. 二.数据库访问步骤 在Java中连接数据库进行的访问主要有以下几个步骤: 加载数据库驱动 注册数据库驱动 建 ...
- Java连接数据库(JDBC)之三:java访问数据库MySQL实例
在加载驱动和使用Connection connect=DriverManager.getConnection语句时IDE会提示你使用try-catch语句防止发生异常. package cc.bb.a ...
- go 访问数据库mysql基础
数据结构定义 type User struct {ID int64 `db:"ID"`Name sql.NullString `db:"name"`Age in ...
- 转:在 .NET 中实现异步回调访问数据库
在 .NET 中实现异步回调访问数据库 时间:2009-11-17 19:52来源:网络收集 作者:佚名 点击: 334 次 技术论坛 某些场合下,在对数据库进行访问时,为了避免同步访问数据时所带来的 ...
- [Java 基础]-- java提供的访问数据库的接口(jdbc)
JDBC java提供的一套访问数据库接口 java--->操作数据库 JDBC发展历史:[了解] TYPE1:JDBC--odbc桥:间接访问数据库//odbc是c语言的jdbc TYPE2: ...
- 本地MySQL数据库要访问远程MySQL数据库的表中的数据的实现
转自: http://blog.csdn.net/jenminzhang/article/details/9872647 1.实现基本思路:借助 MySQL的 federated 存储引擎实现 fed ...
- mysql 命令行访问_Mysql 命令行模式访问操作mysql数据库操作
使用环境 在cmd模式下输入 mysql --version (查看mysql安装的版本). 完整的命令可以通过mysql --help来获取. 本测试使用的Mysql版本是mysql5, 本测试使用 ...
- 可遇不可求的BUG之采用MYSQL odbc 3.51访问数据库返回值缺失
一句话 巧妇难为无米之炊,驱动还是要及时更新啊... 闲话休说,上图: 1.数据库中存储的值为 "布尔玛" 2.用3.51版本的MYSQL ODBC 驱动访问MYSQL 5.0 数 ...
- mysqlclient==1.3.7对应mysql版本_Python通过MySQLdb访问操作MySQL数据库
前言 Python支持通过多种方式访问MySQL数据库.可能有些刚入门的朋友们对Python访问MySQL数据库还不是很熟悉,故计划对Python访问MySQL数据库的这几种方式分别作一介绍. 系列第 ...
- 如何通过命令终端访问本地/局域网/远程的MySQL数据库_访问数据库_连接数据库_登录数据库
文章目录 Windows系统下 访问本地MySQL数据库 访问远程主机的MySQL数据库 本地安装了MySQL数据库 本地没有安装MySQL Linux系统下 退出数据库登录 Windows系统下 访 ...
最新文章
- 动态可订制属性的 PropertyGrid(转载)
- .h 与.hpp文件的区别
- Java URL处理
- java访问控制度_菜鸡的Java笔记 - java 访问控制权限
- Java技巧分享:判断字符串是否为空常的三种方法
- '[linux下tomcat 配置
- java final 变量只读_java final的使用总结
- canopy算法流程_Canopy聚类算法(经典,看图就明白)
- 那些年我们一起写过的Python爬虫
- e站host地址_ip地址基础入门知识
- 虹软人脸识别 - 基于QT的桌面客户端与微信小程序及服务器设计
- 手机版浏览器f12_小科普 | 如何用浏览器的F12装逼?
- 家用投影机预埋布线图_家庭影院装修如何布线(装修前必看·附图)
- 查看变量内存的python内置函数是_这68个Python内置函数,建议你吃透
- Java 后端服务的跨域处理
- 文献调研——存算一体的一些基础知识
- 笔记本连接手机热点并共享网络给台式机
- 天命奇御单独破解补丁下载|天命奇御steam数字版单独破解补丁下载(附天命奇御反激活方法图文教学)
- 常见网络安全产品汇总(私信发送思维导图)
- QCC3040---Glossary