Reactive MySQL Client

Reactive MySQL客户端是MySQL的客户端,其API专注于可伸缩性和低开销。

产品特点

  • 事件驱动
  • 轻巧的
  • 内置连接池
  • 准备查询缓存
  • 游标支持
  • 行流
  • RxJava 1和RxJava 2
  • 直接存储到对象,没有不必要的副本
  • 完整的数据类型支持
  • 存储过程支持
  • TLS / SSL支持
  • MySQL实用程序命令支持
  • 使用MySQL和MariaDB
  • 丰富的排序规则和字符集支持
  • Unix域套接字

用法

添加依赖Reactive MySQL Client

  • Maven(在您的中pom.xml):
<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-mysql-client</artifactId>
</dependency>
  • Gradle(在您的build.gradle文件中):
dependencies {
 compile 'io.vertx:vertx-mysql-client:4.0.1-SNAPSHOT'
}

连接MySQL做一个简单的查询

 MySQLConnectOptions connectOptions = new MySQLConnectOptions()
      .setPort(3306)
      .setHost("127.0.0.1")
      .setDatabase("myschool")
      .setUser("root")
      .setPassword("123456");

    // Pool options
    PoolOptions poolOptions = new PoolOptions()
      .setMaxSize(5);

	// 连接池
    MySQLPool pool = MySQLPool.pool(vertx, connectOptions, poolOptions);

    // A simple query
    pool.query("SELECT * FROM student WHERE id='1'")
      .execute(ar -> {
        if (ar.succeeded()) {
          RowSet<Row> result = ar.result();
          System.out.println("Got " + result.size() + " rows ");
        } else {
          System.out.println("Failure: " + ar.cause().getMessage());
        }
        // Now close the pool
        client.close();
      });

官方文挡调用的是static MySQLPool pool(MySQLConnectOptions connectOptions, PoolOptions poolOptions)创建连接的方法不可行,所以使用static MySQLPool pool(Vertx vertx, MySQLConnectOptions connectOptions, PoolOptions poolOptions)具体原因还没有查到

不再需要连接池时,需要释放它:

pool.close();

也可以使用URl连接MySQL

mysql://dbuser:secretpassword@database.server.com:3211/mydb

或者还可以根据连接属性,默认覆盖客户端的属性

连接重试

connectOptions
  // 设置重新连接尝试的值
  .setReconnectAttempts(2)
  // 设置重新连接间隔
  .setReconnectInterval(1000);

增删改查

// 增
pool.preparedQuery("INSERT INTO student (id, name) VALUES (?, ?)")
  .execute(Tuple.of("3", "刘备"), ar -> {
    if (ar.succeeded()) {
      RowSet<Row> rows = ar.result();
      System.out.println(rows.rowCount());
    } else {
      System.out.println("Failure: " + ar.cause().getMessage());
    }
  });

// 删
pool.preparedQuery("DELETE FROM student where id = ?")
  .execute(Tuple.of("3"), ar -> {
    if (ar.succeeded()) {
      RowSet<Row> rows = ar.result();
      System.out.println(rows.rowCount());
    } else {
      System.out.println("Failure: " + ar.cause().getMessage());
    }
  });

// 改
pool.preparedQuery("UPDATE student SET name = ? where id = ?")
  .execute(Tuple.of("刘备update","3"), ar -> {
    if (ar.succeeded()) {
      RowSet<Row> rows = ar.result();
      System.out.println(rows.rowCount());
    } else {
      System.out.println("Failure: " + ar.cause().getMessage());
    }
  });

简化的连接API

使用池时,可以调用withConnection将连接中执行的函数传递给池。它从池中借用一个连接,并使用该连接调用函数。该函数必须返回任意结果。将完成后,连接将返回到池中,并提供总体结果。

pool.withConnection(connection ->
      connection
        .preparedQuery("INSERT INTO student (id,name) VALUES (?, ?)")
        .executeBatch(Arrays.asList(
          Tuple.of("3", "刘备"),
          Tuple.of("4", "关羽")
        ))
        .compose(res -> connection
          // Do something with rows
          .query("SELECT COUNT(*) FROM student")
          .execute()
          .map(rows -> rows.iterator().next().getInteger(0)))
    ).onSuccess(count -> {
      System.out.println("Insert student now the number of student is " + count);
    });

使用事务

您可以使用SQL BEGINCOMMIT执行事务ROLLBACK,如果这样做,则必须使用SqlConnection和自己进行管理。

 pool.getConnection()
      // 事务必须使用连接
      .onSuccess(conn -> {
        // 事务开始
        conn.begin()
          .compose(tx -> conn
            .query("INSERT INTO student (id, name) VALUES ('5','曹操')")
            .execute()
            .compose(res2 -> conn
              .query("INSERT INTO student (id, name) VALUES ('6','司马懿')")
              .execute())
            // 提交事务
            .compose(res3 -> tx.commit()))
          // 将连接返回到连接池里面
          .eventually(v -> conn.close())
          .onSuccess(v -> System.out.println("Transaction succeeded"))
          .onFailure(err -> System.out.println("Transaction failed: " + err.getMessage()));
      });

简化事务API

使用池时,可以调用withTransaction将在事务中执行的函数传递给池。它从池中借用一个连接,开始事务,并在执行此事务范围内所有操作的客户端上调用该函数。该函数必须返回任意结果的未来:

  • 当未来成功时,客户将提交交易
  • 当未来失败时,客户将回滚交易

事务完成后,连接将返回到池中,并提供总体结果。

pool.withTransaction(client -> client
      .query("INSERT INTO student (id, name) VALUES ('5','曹操')")
      .execute()
      .flatMap(res -> client
        .query("INSERT INTO student (id, name) VALUES ('6','司马懿')")
        .execute()
        // Map to a message result
        .map("student inserted")))
      .onSuccess(v -> System.out.println("Transaction succeeded"))
      .onFailure(err -> System.out.println("Transaction failed: " + err.getMessage())
 );

SQL Client Templates

SQL客户端模板是一个小型库,旨在帮助执行SQL查询。

用法

添加依赖SQL Client Templates

  • Maven(在您的中pom.xml):
<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-sql-client-templates</artifactId>
</dependency>
  • Gradle(在您的build.gradle文件中):
dependencies {
 implementation 'io.vertx:vertx-sql-client-templates:4.0.1-SNAPSHOT'
}

入门

简单查询:SQL模板使用命名参数,因此(默认情况下)将映射用作参数源。

一个SQL模板(默认情况下)会产生RowSet一个client PreparedQuery。实际上,模板是的薄包装PreparedQuery

Map<String, Object> parameters = Collections.singletonMap("id", 1);
SqlTemplate
    .forQuery(pool, "SELECT * FROM student WHERE id=#{id}")
    .execute(parameters)
    .onSuccess(stu -> {
        stu.forEach(row -> {
            System.out.println(row.getString("id") + " " + row.getString("name"));
        });
    });

需要执行插入或更新操作而无需关心结果时,可以使用SqlTemplate.forUpdate

Map<String, Object> parameters = new HashMap<>();
parameters.put("id", "7");
parameters.put("name", "曹植");

SqlTemplate
    .forUpdate(pool, "UPDATE student set name=#{name} where id= #{id}")
    .execute(parameters)
    .onSuccess(v -> {
        System.out.println("Successful update");
    });

行映射

RowMapper<Student> ROW_STUDENT_MAPPER = row -> {
    Student student = new Student();
    student.setId(row.getString("id"));
    student.setName(row.getString("name"));
    return student;
};

Map<String, Object> parameters = Collections.singletonMap("id", 1);
SqlTemplate
    .forQuery(pool, "SELECT * FROM student WHERE id=#{id}")
    .mapTo(ROW_STUDENT_MAPPER)
    .execute(parameters)
    .onSuccess(students -> {
        students.forEach(student -> {
            System.out.println(student.getId() + " " + student.getName());
        });
    });

JSON行映射

Anemic JSON行映射是使用以下命令在模板行列和JSON对象之间进行的简单映射 toJson

SqlTemplate
    .forQuery(pool, "SELECT * FROM student WHERE id=#{id}")
    .mapTo(Row::toJson)
    .execute(Collections.singletonMap("id", 1))
    .onSuccess(users -> {
        users.forEach(user -> {
            System.out.println(user.encode());
        });
    });

参数映射

TupleMapper<Student> PARAMETERS_STUDENT_MAPPER = TupleMapper.mapper(user -> {
    Map<String, Object> parameters = new HashMap<>();
    parameters.put("id", user.getId());
    parameters.put("name", user.getName());
    return parameters;
});

Student student = new Student();
student.setId("10");
student.setName("周瑜");
SqlTemplate
    .forUpdate(pool, "INSERT INTO student (id, name) VALUES (#{id}, #{name})")
    .mapFrom(PARAMETERS_STUDENT_MAPPER)
    .execute(student)
    .onSuccess(res -> {
        System.out.println("Student inserted");
    });

JSON参数映射

JsonObject stu = new JsonObject();
stu.put("id", "11");
stu.put("name", "赵子龙");

SqlTemplate
    .forUpdate(pool, "INSERT INTO student (id, name) VALUES (#{id},#{name})")
    .mapFrom(TupleMapper.jsonObject())
    .execute(stu)
    .onSuccess(res -> {
        System.out.println("Student inserted");
    });

使用Jackson数据绑定进行映射

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.9</version>
</dependency>

这个Jackson的版本有点问题,最新的版本引用不生效,找到一个别人测试过的版本

SqlTemplate
      .forQuery(pool, "SELECT * FROM student WHERE id=#{id}")
      .mapTo(Student.class)
      .execute(Collections.singletonMap("id", 1))
      .onSuccess(students -> {
        students.forEach(student -> {
          System.out.println(student.getId() + " " + student.getName());
        });
      })
    .onFailure(event -> {
      System.out.println(event.getMessage());
    });

Vert.x操作MySQL数据库,从代码上看是要比Java难理解一点,看了很久,用的话就比较简单,但是在实际操作上可能还有很多需要注意的地方。

最近不是很忙,但是却没那么想学习了,估计是最近有点疲累,可是又什么都没有做,心理上的疲累,比实际的疲累还要难受。也有可以是最近太过放飞自我,没有学习观念,得赶紧恢复一下状态。

兄弟们各自加油了,先溜为上!