calcite连接mysql_calcite简单入门

1 介绍

Apache Calcite是一款开源的动态数据管理框架,它提供了标准的 SQL 语言、多种查询优化和连接各种数据源的能力,但不包括数据存储、处理数据的算法和存储元数据的存储库。

Calcite 之前的名称叫做optiq,optiq 起初在 Hive 项目中,为 Hive 提供基于成本模型的优化,即CBO(Cost Based Optimizatio)。2014 年 5 月 optiq 独立出来,成为 Apache 社区的孵化项目,2014 年 9 月正式更名为 Calcite。

Calcite 的目标是“one size fits all(一种方案适应所有需求场景)”,希望能为不同计算平台和数据源提供统一的查询引擎。

2 架构与解析步骤

一般来说Calcite解析SQL有以下几步:Parser. 此步中Calcite通过Java CC将SQL解析成未经校验的AST

Validate. 该步骤主要作用是校证Parser步骤中的AST是否合法,如验证SQL scheme、字段、函数等是否存在; SQL语句是否合法等. 此步完成之后就生成了RelNode树(关于RelNode树, 请参考下文)

Optimize. 该步骤主要的作用优化RelNode树, 并将其转化成物理执行计划。主要涉及SQL规则优化如:基于规则优化(RBO)及基于代价(CBO)优化; Optimze 这一步原则上来说是可选的, 通过Validate后的RelNode树已经可以直接转化物理执行计划,但现代的SQL解析器基本上都包括有这一步,目的是优化SQL执行计划。此步得到的结果为物理执行计划。

Execute,即执行阶段。此阶段主要做的是:将物理执行计划转化成可在特定的平台执行的程序。如Hive与Flink都在在此阶段将物理执行计划CodeGen生成相应的可执行代码。

2.1 查询优化INSERT INTO tmp_node

SELECT s1.id1, s1.id2, s2.val1

FROM source1 as s1 INNER JOIN source2 AS s2

ON s1.id1 = s2.id1 and s1.id2 = s2.id2 where s1.val1 > 5 and s2.val2 = 3;

2.2 Parser解析LogicalTableModify(table=[[TMP_NODE]], operation=[INSERT], flattened=[false])

LogicalProject(ID1=[$0], ID2=[$1], VAL1=[$7])

LogicalFilter(condition=[AND(>($2, 5), =($8, 3))])

LogicalJoin(condition=[AND(=($0, $5), =($1, $6))], joinType=[INNER])

LogicalTableScan(table=[[SOURCE1]])

LogicalTableScan(table=[[SOURCE2]])

2.3 Optimize优化

谓词下推,投影下推,关系代数定律优化LogicalTableModify(table=[[TMP_NODE]], operation=[INSERT], flattened=[false])

LogicalProject(ID1=[$0], ID2=[$1], VAL1=[$7])

LogicalJoin(condition=[AND(=($0, $5), =($1, $6))], joinType=[inner])

LogicalFilter(condition=[=($4, 3)])

LogicalProject(ID1=[$0], ID2=[$1], ID3=[$2], VAL1=[$3], VAL2=[$4],VAL3=[$5])

LogicalTableScan(table=[[SOURCE1]])

LogicalFilter(condition=[>($3,5)])

LogicalProject(ID1=[$0], ID2=[$1], ID3=[$2], VAL1=[$3], VAL2=[$4],VAL3=[$5])

LogicalTableScan(table=[[SOURCE2]])

3 LogicalTableScan查询

如上,节点树中的最后节点均为LogicalTableScan,假设我们不参与(LogicalTableScan)Calcite的查询过程,即不做SQL解析,不做优化,只要把它接入进来,实际Calcite是可以工作的,无非就是可能会有扫全表、数据全部加载到内存里等问题,所以实际中我们可能会参与全部(Translatable)或部分工作(FilterableTable),覆盖Calcite的一些执行计划或过滤条件,让它能更高效的工作。

值得一提的是,Calcite支持异构数据源查询,比如数据存在es和mysql,可以通过写sql join之类的操作,让calcite分别先从不同的数据源查询数据,然后再在内存里进行合并计算;另外,它本身提供了许多优化规则,也支持我们自定义优化规则,来优化整个查询。

3.1 ScannableTable

a simple implementation of Table, using the ScannableTable interface, that enumerates all rows directly

这种方式基本不会用,原因是查询数据库的时候没有任何条件限制,默认会先把全部数据拉到内存,然后再根据filter条件在内存中过滤。

使用方式:实现Enumerable scan(DataContext root);,该函数返回Enumerable对象,通过该对象可以一行行的获取这个Table的全部数据。

3.2 FilterableTable

a more advanced implementation that implements FilterableTable, and can filter out rows according to simple predicates

初级用法,我们能拿到filter条件,即能再查询底层DB时进行一部分的数据过滤,一般开始介入calcite可以用这种方式(translatable方式学习成本较高)。

使用方式:实现Enumerable scan(DataContext root, List filters )。

如果当前类型的“表”能够支持我们自己写代码优化这个过滤器,那么执行完自定义优化器,可以把该过滤条件从集合中移除,否则,就让calcite来过滤,简言之就是,如果我们不处理List filters ,Calcite也会根据自己的规则在内存中过滤,无非就是对于查询引擎来说查的数据多了,但如果我们可以写查询引擎支持的过滤器(比如写一些hbase、es的filter),这样在查的时候引擎本身就能先过滤掉多余数据,更加优化。提示,即使走了我们的查询过滤条件,可以再让calcite帮我们过滤一次,比较灵活。

3.3 TranslatableTable

advanced implementation of Table, using TranslatableTable, that translates to relational operators using planner rules.

高阶用法,有些查询用上面的方式都支持不了或支持的不好,比如join、聚合、或对于select的字段筛选等,需要用这种方式来支持,好处是可以支持更全的功能,代价是所有的解析都要自己写,“承上启下”,上面解析sql的各个部件,下面要根据不同的DB(es\mysql\drudi..)来写不同的语法查询。

当使用ScannableTable的时候,我们只需要实现函数Enumerable scan(DataContext root);,该函数返回Enumerable对象,通过该对象可以一行行的获取这个Table的全部数据(也就意味着每次的查询都是扫描这个表的数据,我们干涉不了任何执行过程);当使用FilterableTable的时候,我们需要实现函数Enumerable scan(DataContext root, List filters );参数中多了filters数组,这个数据包含了针对这个表的过滤条件,这样我们根据过滤条件只返回过滤之后的行,减少上层进行其它运算的数据集;当使用TranslatableTable的时候,我们需要实现RelNode toRel( RelOptTable.ToRelContext context, RelOptTable relOptTable);,该函数可以让我们根据上下文自己定义表扫描的物理执行计划,至于为什么不在返回一个Enumerable对象了,因为上面两种其实使用的是默认的执行计划,转换成EnumerableTableAccessRel算子,通过TranslatableTable我们可以实现自定义的算子,以及执行一些其他的rule,Kylin就是使用这个类型的Table实现查询。

4 自定义数据源表接入demo

如果你的数据源不在官方的支持列表中,或者官方的支持不能满足你的需求,那么则需要自己实现源接入。

4.1 准备工作

4.1.1 maven引入

org.apache.calcite

calcite-core

1.19.0

com.alibaba

fastjson

1.2.54

com.google.guava

guava

16.0.1

4.1.2 开发流程

calcite中,引入一个数据库通常是通过注册一个SchemaFactory接口实现类来实现。SchemaFactory中只有一个方法,就是生成Schema。Schema最重要的功能是获取所有Table。Table有两个功能,一个是获取所有字段的类型,另一个是得到Enumerable迭代器用来读取数据。

4.1.3 配置信息

如果将你的数据源引入calcite,一般情况下是使用一个配置文件,以下是配置文件的demo。{

"version": "1.0",

"defaultSchema": "TEST",

"schemas": [

{

"name": "TEST",

"type": "custom",

"factory": "org.apache.calcite.adapter.jdbc.JdbcSchema$Factory",

"operand": {

"jdbcUrl": "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8",

"jdbcDriver":"com.mysql.cj.jdbc.Driver",

"jdbcUser":"test",

"jdbcPassword":"test"

}

}

]

}

4.2 CSV表demo

这里我们先生成一个CSV文件,后边的操作就是通过在calcite中调用SQL访问CSV中的数据。

TEST01.csvID:VARCHAR,NAME1:VARCHAR,NAME2:VARCHAR

0,first,second

1,hello,world

CsvSchemaFactory类package com.calcite.csv;

import org.apache.calcite.schema.Schema;

import org.apache.calcite.schema.SchemaFactory;

import org.apache.calcite.schema.SchemaPlus;

import java.util.Map;

public class CsvSchemaFactory implements SchemaFactory {

/**

* parentSchema 他的父节点,一般为root

* name 数据库的名字,它在model中定义的

* operand 也是在mode中定义的,是Map类型,用于传入自定义参数。

* */

@Override

public Schema create(SchemaPlus parentSchema, String name, Map operand) {

return new CsvSchema(String.valueOf(operand.get("dataFile")));

}

}

CsvSchema类package com.calcite.csv;

import com.google.common.collect.ImmutableMap;

import com.google.common.io.Resources;

import org.apache.calcite.schema.Table;

import org.apache.calcite.schema.impl.AbstractSchema;

import org.apache.calcite.util.Source;

import org.apache.calcite.util.Sources;

import java.net.URL;

import java.util.Map;

public class CsvSchema extends AbstractSchema {

private Map tableMap;

private String dataFile;

public CsvSchema(String dataFile) {

this.dataFile = dataFile;

}

@Override

protected Map getTableMap() {

URL url = Resources.getResource(dataFile);

Source source = Sources.of(url);

if (tableMap == null) {

final ImmutableMap.Builder builder = ImmutableMap.builder();

builder.put(this.dataFile.split("\\.")[0],new CsvTable(source));

// 一个数据库有多个表名,这里初始化,大小写要注意了,TEST01是表名。

tableMap = builder.build();

}

return tableMap;

}

}

CsvTable类package com.calcite.csv;

import com.google.common.collect.Lists;

import org.apache.calcite.DataContext;

import org.apache.calcite.adapter.java.JavaTypeFactory;

import org.apache.calcite.linq4j.AbstractEnumerable;

import org.apache.calcite.linq4j.Enumerable;

import org.apache.calcite.linq4j.Enumerator;

import org.apache.calcite.rel.type.RelDataType;

import org.apache.calcite.rel.type.RelDataTypeFactory;

import org.apache.calcite.schema.ScannableTable;

import org.apache.calcite.schema.impl.AbstractTable;

import org.apache.calcite.sql.type.SqlTypeName;

import org.apache.calcite.util.Pair;

import org.apache.calcite.util.Source;

import java.io.*;

import java.util.List;

public class CsvTable extends AbstractTable implements ScannableTable {

private Source source;

public CsvTable(Source source) {

this.source = source;

}

/**

* 获取字段类型

*/

@Override

public RelDataType getRowType(RelDataTypeFactory relDataTypeFactory) {

JavaTypeFactory typeFactory = (JavaTypeFactory)relDataTypeFactory;

List names = Lists.newLinkedList();

List types = Lists.newLinkedList();

try {

BufferedReader reader = new BufferedReader(new FileReader(source.file()));

String line = reader.readLine();

List lines = Lists.newArrayList(line.split(","));

lines.forEach(column -> {

String name = column.split(":")[0];

String type = column.split(":")[1];

names.add(name);

types.add(typeFactory.createSqlType(SqlTypeName.get(type)));

});

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return typeFactory.createStructType(Pair.zip(names, types));

}

@Override

public Enumerable scan(DataContext dataContext) {

return new AbstractEnumerable() {

@Override

public Enumerator enumerator() {

return new CsvEnumerator<>(source);

}

};

}

}

CsvEnumerator类package com.calcite.csv;

import org.apache.calcite.linq4j.Enumerator;

import org.apache.calcite.util.Source;

import java.io.BufferedReader;

import java.io.IOException;

public class CsvEnumerator implements Enumerator {

private E current;

private BufferedReader br;

public CsvEnumerator(Source source) {

try {

this.br = new BufferedReader(source.reader());

this.br.readLine();

} catch (IOException e) {

e.printStackTrace();

}

}

@Override

public E current() {

return current;

}

@Override

public boolean moveNext() {

try {

String line = br.readLine();

if(line == null){

return false;

}

current = (E)line.split(","); // 如果是多列,这里要多个值

} catch (IOException e) {

e.printStackTrace();

return false;

}

return true;

}

/**

* 出现异常走这里

* */

@Override

public void reset() {

System.out.println("报错了兄弟,不支持此操作");

}

/**

* InputStream流在这里关闭

* */

@Override

public void close() {

}

}

model.json{

"version": "1.0",

"defaultSchema": "TEST_CSV",

"schemas": [

{

"name": "TEST_CSV",

"type": "custom",

"factory": "com.calcite.csv.CsvSchemaFactory",

"operand": {

"dataFile": "TEST01.csv"

}

}

]

}

Main方法调用package com.calcite;

import com.alibaba.fastjson.JSON;

import com.calcite.util.ReourceUtil;

import com.google.common.collect.Lists;

import com.google.common.collect.Maps;

import java.sql.*;

import java.util.List;

import java.util.Map;

public class Client {

/**

* 测试的时候用字符串 defaultSchema 默认数据库 name 数据库名称 type custom factory

* 请求接收类,该类会实例化Schema也就是数据库类,Schema会实例化Table实现类,Table会实例化数据类。

* operand 动态参数,ScheamFactory的create方法会接收到这里的数据

*/

public static void main(String[] args) {

try {

// 用文件的方式

//URL url = Client.class.getResource("/model.json");

//String str = URLDecoder.decode(url.toString(), "UTF-8");

//Properties info = new Properties();

//info.put("model", str.replace("file:", ""));

//Connection connection = DriverManager.getConnection("jdbc:calcite:", info);

// 字符串方式

String model = ReourceUtil.getResourceAsString("model.json");

Connection connection = DriverManager.getConnection("jdbc:calcite:model=inline:" + model);

Statement statement = connection.createStatement();

test1(statement);

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* CSV文件读取

* @param statement

* @throws Exception

*/

public static void test1(Statement statement) throws Exception {

ResultSet resultSet = statement.executeQuery("select * from test_csv.TEST01");

System.out.println(JSON.toJSONString(getData(resultSet)));

}

public static List> getData(ResultSet resultSet)throws Exception{

List> list = Lists.newArrayList();

ResultSetMetaData metaData = resultSet.getMetaData();

int columnSize = metaData.getColumnCount();

while (resultSet.next()) {

Map map = Maps.newLinkedHashMap();

for (int i = 1; i < columnSize + 1; i++) {

map.put(metaData.getColumnLabel(i), resultSet.getObject(i));

}

list.add(map);

}

return list;

}

}

4.3 内存数据源与CSV数据源关联查询demo

在4.2的演示中,我们能够使用SQL查询CSV文件中的数据。接下来,我们再定义一种内存数据源,主要作用是演示两种数据源间的关联查询。

MemSchemaFactory类package com.calcite.memory;

import org.apache.calcite.schema.Schema;

import org.apache.calcite.schema.SchemaFactory;

import org.apache.calcite.schema.SchemaPlus;

import java.util.Map;

public class MemSchemaFactory implements SchemaFactory {

@Override

public Schema create(SchemaPlus schemaPlus, String s, Map map) {

return new MemSchema(map);

}

}

MemSchema类package com.calcite.memory;

import com.google.common.collect.ImmutableMap;

import org.apache.calcite.schema.Table;

import org.apache.calcite.schema.impl.AbstractSchema;

import java.util.Map;

public class MemSchema extends AbstractSchema {

private Map map;

private Map tableMap;

public MemSchema(Map map) {

this.map = map;

}

@Override

protected Map getTableMap() {

if (tableMap == null) {

final ImmutableMap.Builder builder = ImmutableMap.builder();

map.forEach((key, value) -> {

builder.put(key, new MemTable(value));

});

tableMap = builder.build();

}

return tableMap;

}

}

MemTable类package com.calcite.memory;

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.TypeReference;

import com.alibaba.fastjson.parser.Feature;

import com.google.common.collect.Lists;

import org.apache.calcite.DataContext;

import org.apache.calcite.adapter.java.JavaTypeFactory;

import org.apache.calcite.linq4j.AbstractEnumerable;

import org.apache.calcite.linq4j.Enumerable;

import org.apache.calcite.linq4j.Enumerator;

import org.apache.calcite.rel.type.RelDataType;

import org.apache.calcite.rel.type.RelDataTypeFactory;

import org.apache.calcite.schema.ScannableTable;

import org.apache.calcite.schema.impl.AbstractTable;

import org.apache.calcite.sql.type.SqlTypeName;

import org.apache.calcite.util.Pair;

import java.io.BufferedReader;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.util.List;

import java.util.Map;

public class MemTable extends AbstractTable implements ScannableTable {

private List> list = Lists.newLinkedList();

public MemTable(Object list) {

if (list instanceof List) {

((List)list).forEach(o -> {

this.list.add(

JSON.parseObject(JSON.toJSONString(o),

new TypeReference>() {},

Feature.OrderedField));

});

}

}

@Override

public Enumerable scan(DataContext dataContext) {

return new AbstractEnumerable() {

@Override

public Enumerator enumerator() {

return new MemEnumerator(list);

}

};

}

@Override

public RelDataType getRowType(RelDataTypeFactory relDataTypeFactory) {

JavaTypeFactory typeFactory = (JavaTypeFactory)relDataTypeFactory;

List names = Lists.newLinkedList();

List types = Lists.newLinkedList();

if (list.size() != 0) {

list.get(0).forEach((key, value) -> {

names.add(key);

types.add(typeFactory.createSqlType(SqlTypeName.get("VARCHAR")));

});

}

return typeFactory.createStructType(Pair.zip(names, types));

}

}

MemEnumerator类package com.calcite.memory;

import com.google.common.collect.Lists;

import org.apache.calcite.linq4j.Enumerator;

import java.util.List;

import java.util.Map;

public class MemEnumerator implements Enumerator {

private List> list = Lists.newLinkedList();

private int index = -1;

private E e;

public MemEnumerator(List> list) {

this.list = list;

}

@Override

public E current() {

return e;

}

@Override

public boolean moveNext() {

if (index+1 >= list.size()){

return false;

}else {

e = (E)list.get(index+1).values().toArray();

index++;

return true;

}

}

@Override

public void reset() {

index = -1;

e = null;

}

@Override

public void close() {

}

}

model.json{

"version": "1.0",

"defaultSchema": "TEST_CSV",

"schemas": [

{

"name": "TEST_CSV",

"type": "custom",

"factory": "com.calcite.csv.CsvSchemaFactory",

"operand": {

"dataFile": "TEST01.csv"

}

},

{

"name": "TEST_MEM",

"type": "custom",

"factory": "com.calcite.memory.MemSchemaFactory",

"operand": {

"MEM_TABLE_1": [

{

"ID": 0,

"MEM_STR": "str0"

},

{

"ID": 1,

"MEM_STR": "str1"

},

{

"ID": 2,

"MEM_STR": "str2"

}

]

}

}

]

}

Main方法调用package com.calcite;

import com.alibaba.fastjson.JSON;

import com.calcite.util.ReourceUtil;

import com.google.common.collect.Lists;

import com.google.common.collect.Maps;

import java.sql.*;

import java.util.List;

import java.util.Map;

public class Client {

/**

* 测试的时候用字符串 defaultSchema 默认数据库 name 数据库名称 type custom factory

* 请求接收类,该类会实例化Schema也就是数据库类,Schema会实例化Table实现类,Table会实例化数据类。

* operand 动态参数,ScheamFactory的create方法会接收到这里的数据

*/

public static void main(String[] args) {

try {

// 用文件的方式

//URL url = Client.class.getResource("/model.json");

//String str = URLDecoder.decode(url.toString(), "UTF-8");

//Properties info = new Properties();

//info.put("model", str.replace("file:", ""));

//Connection connection = DriverManager.getConnection("jdbc:calcite:", info);

// 字符串方式

String model = ReourceUtil.getResourceAsString("model.json");

Connection connection = DriverManager.getConnection("jdbc:calcite:model=inline:" + model);

Statement statement = connection.createStatement();

test2(statement);

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* CSV文件读取

* @param statement

* @throws Exception

*/

public static void test1(Statement statement) throws Exception {

ResultSet resultSet = statement.executeQuery("select * from test_csv.TEST01");

System.out.println(JSON.toJSONString(getData(resultSet)));

}

/**

* CSV文件与内存文件关联读取

* @param statement

* @throws Exception

*/

public static void test2(Statement statement) throws Exception {

ResultSet resultSet1 = statement.executeQuery("select csv1.id as cid,csv1.name1 as cname ,mem1.id as mid,mem1.mem_str as mstr from test_csv.TEST01 as csv1 left join test_mem.mem_table_1 as mem1 on csv1.id = mem1.id");

System.out.println(JSON.toJSONString(getData(resultSet1)));

}

public static List> getData(ResultSet resultSet)throws Exception{

List> list = Lists.newArrayList();

ResultSetMetaData metaData = resultSet.getMetaData();

int columnSize = metaData.getColumnCount();

while (resultSet.next()) {

Map map = Maps.newLinkedHashMap();

for (int i = 1; i < columnSize + 1; i++) {

map.put(metaData.getColumnLabel(i), resultSet.getObject(i));

}

list.add(map);

}

return list;

}

}

小结

calcite对于没有高并发、低延时的多数据源间数据有着天然的优势。但需要注意的是,如果一个表中数据量特别大,大到读取速度很慢或内存无法容纳,那么务必在操作该表数据时加入尽可能多的筛选条件,如果自定义实现LogicalTableScan,最好也是实现FilterableTable,从而减少calcite在内存中操作数据行的量。

参考:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555881.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL数据库索引及失效场景

文章目录1. MySQL索引概述1.1 索引的概念1.2 索引的特点1.3 索引的分类1.4 索引的使用场景2. 索引失效场景2.1 索引失效9种场景2.2 索引失效场景总结3. 索引失效验证3.1 全值匹配3.2 最佳左前缀3.3 索引计算3.4 索引范围&#xff1a;索引列上不能有范围查询3.5 索引覆盖&#x…

getLong java_java.lang.Long.getLong()方法实例

全屏java.lang.Long.getLong(String nm) 方法确定具有指定名称的系统属性的long值。如果没有具有指定名称的属性&#xff0c;如果指定名称为空或null&#xff0c;或者该属性没有正确的数字格式&#xff0c;则返回null。声明以下是java.lang.Long.getLong()方法的声明public sta…

@JsonProperty注解解析

1. 概述 来源: JsonPrpperty是jackson包下的一个注解&#xff0c;详细路径(com.fasterxml.jackson.annotation.JsonProperty;)作用:JsonProperty用在属性上&#xff0c;将属性名称序列化为另一个名称。例子&#xff1a;public class Person{JsonProperty(value "name&qu…

java内部类为什么使用很少_java内部类有什么好处?为什么需要内部类?

提起Java内部类(Inner Class)可能很多人不太熟悉&#xff0c;实际上类似的概念在C里也有&#xff0c;那就是嵌套类(Nested Class)&#xff0c;关于这两者的区别与联系&#xff0c;在下文中会有对比。内部类从表面上看&#xff0c;就是在类中又定义了一个类(下文会看到&#xff…

jdk中提供的Collection、Collections、Collector、Collectors你分的清楚?

初次一看四个有点相似&#xff0c;而且有些时候一不小心还真有可能敲错&#xff0c;因为喜欢代码提示没仔细看提示&#xff0c;结果通过.去调用结果发现没有找到你想用的方法。所以写代码的时候需要注意一点这个区别 Collections.emptyList(); Collectors.toMap(......);//所在…

java swing panel问题_关于 Java swing Box 的使用问题

代码import javax.swing.*;import java.awt.*;public class C5Ex1_2 {final static int WIDTH 400;final static int HEIGHT 400;public C5Ex1_2() {JFrame jf new JFrame("program 1");jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setSize(WIDTH, HEI…

SpringMVC注解@RequestParam全面解析____ 注解@RequestParam如何使用加与不加的区别

SpringMVC注解RequestParam全面解析 在此之前&#xff0c;写项目一直用的是RequestParam&#xff08;value“aa” requiredfalse&#xff09;这个注解&#xff0c;但是并不知道它的意思。现在懂了&#xff0c;特来记录下。 1、可以对传入参数指定参数名 1 RequestParam Stri…

java编写流星_纯Java代码实现流星划过天空

废话不多说了&#xff0c;直接给大家贴java代码了。import java.awt.Color;import java.awt.Graphics;import java.awt.image.BufferedImage;import javax.swing.JFrame;import javax.swing.JPanel;public class MeteorFly extends JFrame {final int MAX ; // (~)流星的个数f…

@requestbody和@requestparam到底什么作用

1、什么都不写 GET 可以自动封装为对象模型&#xff0c;没有的数值自动为0值 POST 请求体里面放了数据&#xff0c;但是还是使用了RequestParam里的数据 总结&#xff1a; 在不使用注解的情况下&#xff0c;相当于默认使用了RequestParam里的数据 &#xff08;这种理解是错…

linux mysql学习_Linux学习笔记(MySql操作)

忘记MySql密码&#xff1a;编辑mysql主配置文件 my.cnf 在[mysqld]字段下添加参数 skip-grant重启数据库服务,这样就可以进入数据库不用授权了 mysql -uroot修改相应用户密码 use mysql;update user setpasswordpassword(密码) where userroot;flushprivileges; (刷新)最后…

注解@RequestParam【不添加默认项注解】与@RequestBody的使用场景

一、前言 一直有这么一个疑问&#xff1a;在使用postman工具测试api接口的时候&#xff0c;如何使用 json 字符串传值呢&#xff0c;而不是使用 x-www-form-urlencoded 类型&#xff0c;毕竟通过 key-value 传值是有局限性的。假如我要测试批量插入数据的接口呢&#xff0c;使用…

java新建对象校验_验证某个对象是否是一个mock对象或者一个spy对象

C**f回复了y**4在课程中的问题&#xff1a;final和自动装配...v**g添加了笔记&#xff1a;James Gosl...c**k向课程作业中提交了代码我**…向课程作业中提交了代码2**9在课程中提出了问题&#xff1a;谢谢回复。应该是网络...v**g在课程中提出了问题&#xff1a;里面的内容SESS…

SpringMVC参数的传递——接收List数组类型的数据

前言 本文主要是记录SpringMVC中当前台传过来数组的时候&#xff0c;如何把前台传过来的数据封装到Controller层方法的形参中。 在了解下面参数如何传递前先记住两个结论&#xff1a; 当Ajax以application/x-www-form-urlencoded编码格式上传数据&#xff0c;必须使用JSON对…

rowdata java_Java RowDataUtil.addRowData方法代碼示例

本文整理匯總了Java中org.pentaho.di.core.row.RowDataUtil.addRowData方法的典型用法代碼示例。如果您正苦於以下問題&#xff1a;Java RowDataUtil.addRowData方法的具體用法&#xff1f;Java RowDataUtil.addRowData怎麽用&#xff1f;Java RowDataUtil.addRowData使用的例子…

properties配置文件的加密

要完成properties属性文件某些属性值的加密&#xff0c;和读取属性文件时进行解密&#xff0c;需要4个步骤 编写加密解密工具类手动通过加密解密工具类获得加密后的属性值密文&#xff0c;并把密文填写在properties文件中编写PropertyPlaceholderConfigurer的子类&#xff0c;…

【springmvc】@RequestParam详解以及加与不加的区别

以前写controller层的时候都是默认带上 RequestParam 的&#xff0c; 今天发现不加RequestParam 也能接收到参数 下面我们来区分一下加与不加的区别 这里有两种写法 RequestMapping("/list")public String test(RequestParam Long parentId) {}RequestMapping(&qu…

java同样作用的方法_Java的接口用途和方法

1&#xff0c; 抽象类解决不了, 根本问题是Java的类不能多继承.因为Tiger类继承了动物Animal类的特性(例如 move() 和 drink()) , 但是严格上来将 捕猎(hunt())并不算是动物的特性之一. 有些植物, 单细胞生物也会捕猎的.所以Tiger要从别的地方来继承Hunt()这个方法. 接口就发挥…

有了 IP 地址,为什么还要用 MAC 地址?

我认为&#xff0c;IP地址和MAC地址可以类比生活中寄快递的过程。 在整个网络中数据被封装成数据报文进行发送&#xff0c;就像我们生活中寄快递时将物品放进包裹中。而数据在路由器之间的跳转也可以看作是不同地区快递小哥对物流的交接。 IP地址 ip地址等价于快递包裹上的…

java运动员最佳配对_运动员最佳配对问题 - osc_y1pyjby5的个人空间 - OSCHINA - 中文开源技术交流社区...

这道题可以看为排列数的一个典型模块一、算法实现题&#xff1a;1、问题描述&#xff1a;羽毛球队有男女运动员各n人&#xff0c;给定2个nn矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势&#xff1b;Q[i][j]则是女运动员i和男运动员j配合的女运动…

为什么POJO中变量不能用is开头

一、前言 在阿里编码规约中&#xff0c;有一个约定如下 【强制】POJO 类中的任何布尔类型的变量&#xff0c;都不要加 is 前缀&#xff0c;否则部分框架解析会引起序列 化错误。 但为什么类中的field不能用is开头呢&#xff1f;本文将从问题演示、框架源码&#xff08;本文使用…