架构的差异

原生数据源:

常规数据源

引入 apache calcite 之后:

引入 calcite 之后

说明

实战记录一下 mysql 如何整合 apache calcite。

mysql 数据准备

建表语句

  [sql]
1
2
3
4
5
6
7
8
use test; CREATE TABLE "users" ( "id" int(11) NOT NULL, "username" varchar(255) NOT NULL, "email" varchar(255) NOT NULL, PRIMARY KEY ("id") ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

插入数据

  [sql]
1
2
3
insert into users (id, username, email) values (1, 'u-1', '1@email.com'); insert into users (id, username, email) values (2, 'u-2', '2@email.com'); insert into users (id, username, email) values (3, 'u-3', '3@email.com');

数据确认:

  [plaintext]
1
2
3
4
5
6
7
8
9
mysql> select * from users; +----+----------+-------------+ | id | username | email | +----+----------+-------------+ | 1 | u-1 | 1@email.com | | 2 | u-2 | 2@email.com | | 3 | u-3 | 3@email.com | +----+----------+-------------+ 3 rows in set (0.00 sec)

mysql 整合基本例子-v1

maven 引入

  [xml]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependencies> <!-- jdbc 应该是 core 的一部分--> <dependency> <groupId>org.apache.calcite</groupId> <artifactId>calcite-core</artifactId> <version>1.36.0</version> </dependency> <!-- MySQL JDBC Driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> <!-- 或者最新版本 --> </dependency> </dependencies>

java 代码

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.github.houbb.calcite.learn.mysql; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import org.apache.calcite.adapter.jdbc.JdbcSchema; import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaPlus; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /** * https://blog.csdn.net/a17816876003/article/details/125592222 * */ public class CalciteMySQLExample { public static void main(String[] args) throws Exception { // check driver exist Class.forName("org.apache.calcite.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver"); // the properties for calcite connection Properties info = new Properties(); //LEX: 使用传统的 SQL 解析器,也称为 "LEX" 解析器。这是 Calcite 默认的解析器类型,能够处理大多数 SQL 语法。 //JAVA: 使用 Java 解析器,也称为 "JAVA" 解析器。这个解析器是针对 Calcite 提供的 SQL 格式进行解析。 info.setProperty("lex", "JAVA"); // remarks 是指定是否应该包含数据库的备注信息(也称为注释)。当设置为 true 时,表示在元数据中包含数据库对象的备注信息;当设置为 false 时,不包含备注信息。 info.setProperty("remarks","true"); // SqlParserImpl can analysis sql dialect for sql parse info.setProperty("parserFactory","org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY"); // create calcite connection and schema Connection connection = DriverManager.getConnection("jdbc:calcite:", info); CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class); System.out.println(calciteConnection.getProperties()); // code for mysql datasource MysqlDataSource dataSource = new MysqlDataSource(); // please change host and port maybe like "jdbc:mysql://127.0.0.1:3306/test" dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC"); dataSource.setUser("admin"); dataSource.setPassword("123456"); // mysql schema, the sub schema for rootSchema, "test" is a schema in mysql SchemaPlus rootSchema = calciteConnection.getRootSchema(); Schema schema = JdbcSchema.create(rootSchema, "test", dataSource, null, "test"); rootSchema.add("test", schema); // run sql query Statement statement = calciteConnection.createStatement(); ResultSet resultSet = statement.executeQuery("select * from test.users"); while (resultSet.next()) { System.out.println(resultSet.getObject(1) + "," + resultSet.getObject(2) + "," + resultSet.getObject(3)); } statement.close(); connection.close(); } }

输出日志:

  [plaintext]
1
2
3
4
{lex=JAVA, parserFactory=org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY, remarks=true} 1,u-1,1@email.com 2,u-2,2@email.com 3,u-3,3@email.com

mysql 整合-v2

说明

select * from test.users 这个 test 前缀感觉比较别扭,如果不想要呢。

其实加一句就行:

  [java]
1
2
// Set default schema for unqualified table names,这样可以让 sql 不加前缀? calciteConnection.setSchema("test");

完整代码

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.github.houbb.calcite.learn.mysql; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import org.apache.calcite.adapter.jdbc.JdbcSchema; import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaPlus; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /** * https://blog.csdn.net/a17816876003/article/details/125592222 * */ public class CalciteMySQLExampleNoPrefix { public static void main(String[] args) throws Exception { // check driver exist Class.forName("org.apache.calcite.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver"); // the properties for calcite connection Properties info = new Properties(); //LEX: 使用传统的 SQL 解析器,也称为 "LEX" 解析器。这是 Calcite 默认的解析器类型,能够处理大多数 SQL 语法。 //JAVA: 使用 Java 解析器,也称为 "JAVA" 解析器。这个解析器是针对 Calcite 提供的 SQL 格式进行解析。 info.setProperty("lex", "JAVA"); // remarks 是指定是否应该包含数据库的备注信息(也称为注释)。当设置为 true 时,表示在元数据中包含数据库对象的备注信息;当设置为 false 时,不包含备注信息。 info.setProperty("remarks","true"); // SqlParserImpl can analysis sql dialect for sql parse info.setProperty("parserFactory","org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY"); // create calcite connection and schema Connection connection = DriverManager.getConnection("jdbc:calcite:", info); CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class); System.out.println(calciteConnection.getProperties()); // code for mysql datasource MysqlDataSource dataSource = new MysqlDataSource(); // please change host and port maybe like "jdbc:mysql://127.0.0.1:3306/test" dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC"); dataSource.setUser("admin"); dataSource.setPassword("123456"); // mysql schema, the sub schema for rootSchema, "test" is a schema in mysql SchemaPlus rootSchema = calciteConnection.getRootSchema(); Schema schema = JdbcSchema.create(rootSchema, "test", dataSource, null, "test"); rootSchema.add("test", schema); // Set default schema for unqualified table names,这样可以让 sql 不加前缀? calciteConnection.setSchema("test"); // run sql query Statement statement = calciteConnection.createStatement(); ResultSet resultSet = statement.executeQuery("select * from users"); while (resultSet.next()) { System.out.println(resultSet.getObject(1) + "," + resultSet.getObject(2) + "," + resultSet.getObject(3)); } statement.close(); connection.close(); } }

效果

  [plaintext]
1
2
3
4
{lex=JAVA, parserFactory=org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY, remarks=true} 1,u-1,1@email.com 2,u-2,2@email.com 3,u-3,3@email.com

mysql join 场景测试-v2

java 代码

我们实际测试一下 Left join 的场景,核心 SQL:

  [sql]
1
select u.* from users u left join users_fake f ON u.id=f.id where f.id=2

如下

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.github.houbb.calcite.learn.mysql; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import org.apache.calcite.adapter.jdbc.JdbcSchema; import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaPlus; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /** * https://blog.csdn.net/a17816876003/article/details/125592222 * */ public class CalciteMySQLExampleNoPrefixLeftJoin { public static void main(String[] args) throws Exception { // check driver exist Class.forName("org.apache.calcite.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver"); // the properties for calcite connection Properties info = new Properties(); //LEX: 使用传统的 SQL 解析器,也称为 "LEX" 解析器。这是 Calcite 默认的解析器类型,能够处理大多数 SQL 语法。 //JAVA: 使用 Java 解析器,也称为 "JAVA" 解析器。这个解析器是针对 Calcite 提供的 SQL 格式进行解析。 info.setProperty("lex", "JAVA"); // remarks 是指定是否应该包含数据库的备注信息(也称为注释)。当设置为 true 时,表示在元数据中包含数据库对象的备注信息;当设置为 false 时,不包含备注信息。 info.setProperty("remarks","true"); // SqlParserImpl can analysis sql dialect for sql parse info.setProperty("parserFactory","org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY"); // create calcite connection and schema Connection connection = DriverManager.getConnection("jdbc:calcite:", info); CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class); System.out.println(calciteConnection.getProperties()); // code for mysql datasource MysqlDataSource dataSource = new MysqlDataSource(); // please change host and port maybe like "jdbc:mysql://127.0.0.1:3306/test" dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC"); dataSource.setUser("admin"); dataSource.setPassword("123456"); // mysql schema, the sub schema for rootSchema, "test" is a schema in mysql SchemaPlus rootSchema = calciteConnection.getRootSchema(); Schema schema = JdbcSchema.create(rootSchema, "test", dataSource, null, "test"); rootSchema.add("test", schema); // Set default schema for unqualified table names,这样可以让 sql 不加前缀? calciteConnection.setSchema("test"); // run sql query Statement statement = calciteConnection.createStatement(); ResultSet resultSet = statement.executeQuery("select u.* from users u left join users_fake f ON u.id=f.id where f.id=2"); while (resultSet.next()) { System.out.println(resultSet.getObject(1) + "," + resultSet.getObject(2) + "," + resultSet.getObject(3)); } statement.close(); connection.close(); } }

测试效果:

  [plaintext]
1
2
{lex=JAVA, parserFactory=org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY, remarks=true} 2,u-2,2@email.com

引入 druid 数据库池化

场景

上面没有引入数据库池化能力。

java 实现方式

这里我们使用 alibaba druid,其实实现也比较简单。

MysqlDataSource=>DruidDataSource

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.github.houbb.calcite.learn.mysql; import com.alibaba.druid.pool.DruidDataSource; import org.apache.calcite.adapter.jdbc.JdbcSchema; import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaPlus; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /** * druid + calcite + mysql */ public class DruidCalciteMySQLNoPrefixExample { public static void main(String[] args) throws Exception { Properties info = new Properties(); info.setProperty("lex", "JAVA"); info.setProperty("remarks","true"); info.setProperty("parserFactory","org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY"); // create calcite connection and schema Connection connection = DriverManager.getConnection("jdbc:calcite:", info); CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class); System.out.println(calciteConnection.getProperties()); // code for mysql datasource DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC"); dataSource.setUsername("admin"); dataSource.setPassword("123456"); SchemaPlus rootSchema = calciteConnection.getRootSchema(); Schema schema = JdbcSchema.create(rootSchema, "test", dataSource, null, "test"); rootSchema.add("test", schema); calciteConnection.setSchema("test"); // run sql query Statement statement = calciteConnection.createStatement(); ResultSet resultSet = statement.executeQuery("select * from users"); while (resultSet.next()) { System.out.println(resultSet.getObject(1) + "," + resultSet.getObject(2) + "," + resultSet.getObject(3)); } statement.close(); connection.close(); } }

效果:

  [plaintext]
1
2
3
4
5
6
{lex=JAVA, parserFactory=org.apache.calcite.sql.parser.impl.SqlParserImpl#FACTORY, remarks=true} 三月 12, 2024 10:36:22 上午 com.alibaba.druid.pool.DruidDataSource info 信息: {dataSource-1} inited 1,u-1,1@email.com 2,u-2,2@email.com 3,u-3,3@email.com

参考资料

https://blog.csdn.net/a17816876003/article/details/125592222