整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JavaWeb连接MySQL数据库最细图解

JavaWeb连接MySQL数据库最细图解

avaWeb连接MySQL数据库的方式有很多,首先我们讲解JDBC的配置方法

一、JDBC的配置方法

1、什么是JDBC

什么是JDBC嘞?JDBC代表Java数据库连接(Java Database Connectivity),它是用于Java编程语言和数据库之间的数据库无关连接的标准Java API,

换句话说:JDBC是用于在Java语言编程中与数据库连接的API。

JDBC库包括通常与数据库使用相关,如下面提到的每个任务的API -

  • 连接到数据库
  • 创建SQL或MySQL语句
  • 在数据库中执行SQL或MySQL查询
  • 查看和修改结果记录

从根本上说,JDBC是一个规范,它提供了一整套接口,允许以一种可移植的访问底层数据库API。 Java可以用它来编写不同类型的可执行文件,如 -

  • Java应用程序
  • Java Applet
  • Java Servlets
  • Java ServerPages(JSP)
  • 企业级JavaBeans(EJB)

所有这些不同的可执行文件都能够使用JDBC驱动程序来访问数据库,并用于存储数据到数据库中。

JDBC提供与ODBC相同的功能,允许Java程序包含与数据库无关的代码(同样的代码,只需要指定使用的数据库类型,不需要重修改数据库查询或操作代码)。

2、下载配置

(1)首先我们到MySQL的官网去下载支持程序“MySQL Connector/J”(MySQL官方的JDBC驱动程序)

这里附上一键直达的链接:MySQL :: Download MySQL Connector/J (Archived Versions)

首先打开MySQL官网,点击DOWNLOADS

之后我们点击MySQL Community(GPL) Downloads

点击Connector/J

点击Archives

按照图片进行选择并下载(这里我们不可以选择上方的那个文件,因为上面那个文件是Liunx、Dabian等系统的文件,下面的文件才是Windows版本的!!!

至此,我们下载完成。

(2)接下来我们进行文件配置。

我们将下载的压缩包进行解压,在生成的文件中会有一个名为mysql-connector-java-8.0.28.jar的文件。

我们要在需要与MySQL连接的项目中建立一个lib文件夹,并将.jar文件复制粘贴到此文件夹下(也可以直接进行拖拽)

之后我们用右键,按照图片上的步骤操作,添加驱动程序路径(成功后会多出一个

文件)

到这里不要着急,下面我们将.jar包导入到你电脑Tomcat文件根目录下的lib文件夹内,这样,你就完成了所有配置!

(3)接下来我们注册JDBC驱动程序

连接数据库时,需要将数据库驱动程序注册到jdbc的驱动管理器中。

调用Class.forName()方法例如:Class.forName(“com.mysql.jdbc.Driver”);当jdbc驱动程序mysql-connector-java-5.0.5-bin.jar为6.x版本以上时,调用为Class.forName(“com.mysql.cj.jdbc.Driver”);

(4)基于数据库连接的URL创建连接

虽然不同数据库厂商的URL不完全相同,但是都符合一个基本的格式,即“jdbc协议+IP地址或域名+端口号+数据库名称”。

创建数据库连接时,需要使用DriverManager类中getConnection()的静态方法,方法声明如下:DriverManager.getConnection(String url,String username,password);

二、使用JDBC的方法使JavaWeb连接MySQL数据库

下面我们写一个JSP代码,用来验证是否可以连接MySQL数据库。

<%@page import="java.sql.DriverManager"%><%@page import="java.sql.DriverAction"%><%@page import="java.sql.Connection"%><%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%><!DOCTYPE html><html><head><meta http-equiv="Content-Type" content:"text/html" charset="UTF-8"><title>MySQL</title></head><body>	<%	try {		Class.forName("com.mysql.cj.jdbc.Driver"); //显示声明将数据库驱动程序注册到jdbc的驱动管理器中		String url="jdbc:mysql://localhost:3306/text"; //数据库名称为text(需要提前在MySQL里面建立text数据库)		String username="root"; //数据库用户名		String password="123456"; //数据库密码			Connection conn=DriverManager.getConnection(url, username, password); //连接数据库		out.print("数据库连接成功!");		conn.close();	} catch (Exception e) {		out.print("数据库连接失败!");		out.print("错误信息:" + e.toString());	}	%> </body></html>

PS:这里需要注意的是我们自己使用时一定要修改成自己MySQL的用户名和密码,保证可以正常连接数据库。并且我们连接的数据库一定要存在!!!

三、进行实际操作

1、创建首页(login.jsp)

首先需要创建一个新的首页,首页可以显示用户名,密码,登录按钮等。代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%><!DOCTYPE html><html><head><meta charset="UTF-8"><title>欢迎登录</title></head><body>	<div style="text-align: center; margin-top: 120px">		<form action="LoginServet" method="post">			<table style="margin-left: 40%">				<h1>登陆</h1>				<tr>					<td>登录名:</td>					<td><input name="username" type="text" size="21"></td>				</tr>				<tr>					<td>密码:</td>					<td><input name="password" type="password" size="21"></td>				</tr>			</table>			<input type="submit" value="登录">			<input type="reset"value="重置">		</form>		<br>	</div></body></html>

效果如下:

2、创建LoginServlet.java文件

接下来我们创建LoginServlet.java文件。代码如下:

package com.sdbi.servlet; import java.io.IOException;  import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;   import com.sdbi.dao.userDao;import com.sdbi.entity.User; @WebServlet("/LoginServet")public class LoginServet extends HttpServlet { 	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {		String account=request.getParameter("username");		String passWord=request.getParameter("password");				HttpSession session=request.getSession();		String username=request.getParameter("username");		String password=request.getParameter("password");		userDao userDao=new userDao();					User user=(User)userDao.login(username, password);		if (user !=null) {			session.setAttribute(username, user);			request.getRequestDispatcher("check.jsp").forward(request, response);					}else {			request.getRequestDispatcher("failed.jsp").forward(request, response);		}	} 	protected void doPost(HttpServletRequest request, HttpServletResponse response)			throws ServletException, IOException { 		doGet(request, response);	} }

4、创建UserDao.java文件

代码如下:

package com.sdbi.dao; import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;   import com.mysql.cj.protocol.Resultset.Concurrency;import com.sdbi.entity.User; import util.DButil; public class userDao { 	public User login(String username,String password) {		User u=null;		Connection connection=null;		PreparedStatement pstmt=null;		ResultSet resultSet=null;		try {			connection=DButil.getcon();			String sql="select * from user where username=? and password=?";			pstmt=(PreparedStatement) connection.prepareStatement(sql);			pstmt.setString(1, username);			pstmt.setString(2, password);			resultSet=pstmt.executeQuery();			if (resultSet.next()) {				u=new User();				u.setUsername(resultSet.getString("username"));				u.setPassword(resultSet.getString("password"));				System.out.println("登录成功!");			} else {				System.out.println("用户名或者密码错误!");			} 		} catch (SQLException e) {			e.printStackTrace(); 		} finally {			//DBUtil.close(pstmt, connection); 		}		return u;	} 	public boolean addUser(User user) {		 Connection connection=null;		 PreparedStatement psmt=null;		 try {			connection=DButil.getcon();			String sql="insert into user(username,password);";			psmt=(PreparedStatement) connection.prepareStatement(sql);			 psmt.setString(1, user.getUsername());			psmt.setString(2,user.getPassword());			psmt.executeUpdate();																			} catch (SQLException e) {			e.printStackTrace();			return false;					}finally {			//DBUtil.close(psmt, connection);		}		 return true;	} }

5、创建User.java文件

package com.sdbi.entity; public class User {	private String username;	private String password;	public String getUsername() {		return username;	}	public void setUsername(String username) {		this.username=username;	}	public String getPassword() {		return password;	}	public void setPassword(String password) {		this.password=password;	}				 }

6、创建check.jsp文件

<%@page import="java.sql.ResultSet"%><%@page import="java.sql.PreparedStatement"%><%@page import="java.sql.DriverManager"%><%@page import="java.sql.Connection"%><%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%><!DOCTYPE html><html><head><meta charset="UTF-8"><title>所有用户信息</title></head><body>	<center>		<h3>所有用户信息</h3>		<table border="1">			<tr>				<th>账户</th>				<th>密码</th>			</tr>			<%			//加载、注册数据库驱动程序			Class.forName("com.mysql.cj.jdbc.Driver"); 			//数据库连接字符串			String url="jdbc:mysql://localhost:3306/text";			//用户名			String username="root";			//密码			String password="123456";			//数据库连接			Connection conn=DriverManager.getConnection(url, username, password);			//构造sql语句			String sql="select * from user";			//获取数据库操作对象(PreparedStatement对象)			PreparedStatement pstmt=conn.prepareStatement(sql); 			ResultSet rs=pstmt.executeQuery(); 			//循环前准备变量			String uname=null;			String upassword=null;			while (rs.next()) {				uname=rs.getString("username");				upassword=rs.getString("password");			%>			<tr>				<td><%=uname%></td>				<th><%=upassword%></th>			</tr> 			<%			}			//释放对象			if (pstmt !=null) {			pstmt.close();			}			if (conn !=null) {			pstmt.close();			}			if (rs !=null) {			rs.close();			}			%>			</center>		</table></body></html>

7、创建failed.jsp文件

<%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%><!DOCTYPE html><html><head><meta charset="UTF-8"><title>登陆失败</title></head><body>	<h1>失败</h1><br />	<a href="login.jsp">请重新登录</a></body></html>

8、创建所需要的数据库连接

9、登录用户


如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,,咱们下期见。

收藏 等于白嫖,点赞才是真情。



原文 https://www.cnblogs.com/soosoo/p/16219491.html

先说明,由于是8版本的数据库,所以配置类的写法上与5版本的有所区别,需要注意,同时用idea或eclipse时需要导入jar包,jar包的下载链接:

https://dev.mysql.com/get/archives/mysql-connector-java-8.0/mysql-connector-java-8.0.28.zip

如果想要下载8版本不同的jar包只需要修改8.0.28为指定版本即可。

idea导入jar包的方法如下:

然后是代码部分,首先先建表:

CREATE TABLE `train_message` (
                                 `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
                                 `train_name` varchar(20) NOT NULL COMMENT '列车名',
                                 `origin` varchar(30) NOT NULL COMMENT '始发地',
                                 `terminal` varchar(30) NOT NULL COMMENT '终到地',
                                 `departure_time` timestamp NOT NULL COMMENT '出站时间',
                                 `state` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '正常' COMMENT '列车状态',
                                 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3

然后创建连接的配置类DbConfig.java,localhost是本机的ip地址,如果有服务器就填服务器的ip地址,message是数据库的名字,这里一张图说下有很多新手误解的名字

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 *  数据库配置类
 *  @author 景苒
 */
public class DbConfig {
    public Connection dbConfig() throws SQLException {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        }catch (Exception e) {
            System.out.print("加载驱动失败!");
            e.printStackTrace();
        }
        String url="jdbc:mysql://localhost:3306/message?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true";
        String user="root";
        String password="123456";
        return DriverManager.getConnection(url, user, password);
    }
}

然后写下主函数Main.java,这里主函数的函数体可以在最后再写,需要什么功能就把注释打开就好,快捷注释的方法,选中这句话,按ctrl加/,就能全注释了。

import java.sql.SQLException;

/**
 * 主函数,调用功能
 * @author 景苒
 */
public class Main {
    public static void main(String[] args) throws SQLException {
//        new GetMessage().getMessage();
//        new UpdateTrainState().updateTrainState();
//        new InsertTrain().insertTrain();
//        new GetNumber().getNumber();
    }
}

然后是每个的功能:

1.查询沈阳到武汉的所有列车信息,按出发时间先后排序

建GetMessage.java类

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 查询沈阳到武汉的所有列车信息,按出发时间先后排序
 * @author 景苒
 */
public class GetMessage {
    public void getMessage() throws SQLException {
        Connection con=new DbConfig().dbConfig();
        String sql="select * from `train_message` where origin=? and terminal=? ORDER BY departure_time ASC";
        String origin="沈阳";
        String terminal="武汉";
        PreparedStatement ps=con.prepareStatement(sql);
        ps.setString(1, origin);
        ps.setString(2, terminal);
        ResultSet rs=ps.executeQuery();
        try {
            while (rs.next()) {
                System.out.println("列车名:" + rs.getString("train_name")
                        + " 始发站:" + rs.getString("origin")
                        + " 终到站:" + rs.getString("terminal")
                        + " 出发时间:" + rs.getString("departure_time")
                        + " 列车状态:" + rs.getString("state"));
            }
        }catch (SQLException e) {
            e.printStackTrace();
        }finally {
            ps.close();
            con.close();
        }
    }
}

2.修改T2255列车的状态为停运

建UpdateTrainState.java类

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 修改T2255列车的状态为停运
 * @author 景苒
 */
public class UpdateTrainState {
    public void updateTrainState() throws SQLException {
        Connection con=new DbConfig().dbConfig();
        String sql="UPDATE `train_message` SET state='停运' WHERE train_name='T2255'";
        Statement statement=con.createStatement();
        try {
            int i=statement.executeUpdate(sql);
            if (i > 0) {
                System.out.println("更新成功");
            }else {
                System.out.println("更新失败");
            }
        }catch (SQLException e) {
            e.printStackTrace();
        }finally {
            statement.close();
            con.close();
        }
    }
}

3.新增一辆列车信息(自己输入)

建InsertTrain.java类

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * 新增一辆列车信息(自己输入)
 * 始发时间为timestamp类型,输入时需要确保格式正确,如:2019-01-01 00:00:00
 * @author 景苒
 */
public class InsertTrain {
    public void insertTrain() throws SQLException {
        Connection con=new DbConfig().dbConfig();
        Scanner scanner=new Scanner(System.in);
        String sql="insert into `train_message` values(null, ?, ?, ?, ?, default)";
        System.out.print("请输入列车名:");
        String trainName=scanner.nextLine();
        System.out.print("请输入始发站:");
        String origin=scanner.nextLine();
        System.out.print("请输入终到站:");
        String terminal=scanner.nextLine();
        System.out.print("请输入始发时间:");
        String departureTime=scanner.nextLine();
        PreparedStatement ps=con.prepareStatement(sql);
        ps.setString(1, trainName);
        ps.setString(2, origin);
        ps.setString(3, terminal);
        ps.setString(4, departureTime);
        try {
            int i=ps.executeUpdate();
            if (i > 0) {
                System.out.println("添加成功");
            }else {
                System.out.println("添加失败");
            }
        }catch (SQLException e) {
            e.printStackTrace();
        }finally {
            ps.close();
            con.close();
        }
    }
}

4.查询状态为正常的列车数量

建GetNumber.java类

import java.sql.Statement;

/**
 * 查询状态为正常的列车数量
 * @author 景苒
 */
public class GetNumber {
    public void getNumber() throws SQLException {
        Connection con=new DbConfig().dbConfig();
        String sql="select count(state) from `train_message` where state='正常'";
        Statement statement=con.createStatement();
        try {
            ResultSet resultSet=statement.executeQuery(sql);
            while (resultSet.next()) {
                System.out.println("状态为正常的列车数量为:" + resultSet.getInt(1));
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            statement.close();
            con.close();
        }
    }
}

最后附上navicat的属性结构图和样例插入的语句

数据根据自己需求自行写入几个就行,以上就是java连接mysql数据库的实例代码,eclipse也大同小异,就导入jar包的方式不同。

文章来自https://www.cnblogs.com/jingran/p/16120104.html

数据库已经越来越被人们熟知,同时也在许多企业中得到了应用,但是由于市面上没有统一的图查询语言标准,所以有部分开发者对于不同图数据库的用法存在着疑问。因此本文作者对市面上主流的几款图数据库进行了一番分析,并以查询操作为例进行深入介绍。

文章的开头我们先来看下什么是图数据库,根据维基百科的定义:图数据库是使用图结构进行语义查询的数据库,它使用节点、边和属性来表示和存储数据

虽然和关系型数据库存储的结构不同(关系型数据库为表结构,图数据库为图结构),但不计各自的性能问题,关系型数据库可以通过递归查询或者组合其他 SQL 语句(Join)完成图查询语言查询节点关系操作。得益于 1987 年 SQL 成为国际标准化组织(ISO)标准,关系型数据库行业得到了很好的发展。同 60、70 年代的关系型数据库类似,图数据库这个领域的查询语言目前也没有统一标准,虽然 19 年 9 月经过国际 SQL 标准委员会投票表决,决定将图查询语言(Graph Query Language)纳为一种新的数据库查询语言,但 GQL 的制定仍需要一段时间。

鉴于市面上没有统一的图查询语言标准,在本文中我们选取市面上主流的几款图查询语言来分析一波用法,由于篇幅原因本文旨在简单介绍图查询语言和常规用法,更详细的内容将在进阶篇中讲述。

图查询语言·介绍

图查询语言 Gremlin

Gremlin 是 Apache ThinkerPop 框架下的图遍历语言。Gremlin 可以是的也可以是命令性的。虽然 Gremlin 是基于 Groovy 的,但具有许多语言变体,允许开发人员以 Java、JavaScript、Python、Scala、Clojure 和 Groovy 等许多现代编程语言原生编写 Gremlin 查询

支持图数据库:Janus Graph、InfiniteGraph、Cosmos DB、DataStax Enterprise(5.0+) 、Amazon Neptune

图查询语言 Cypher

Cypher 是一个描述性的图形查询语言,允许不必编写图形结构的遍历代码对图形存储有表现力和效率的查询,和 SQL 很相似,Cypher 语言的关键字不区分大小写,但是属性值,标签,关系类型和变量是区分大小写的。

支持图数据库: Neo4j、RedisGraph、AgensGraph

图查询语言 nGQL

nGQL 是一种类 SQL 的声明型的文本查询语言,nGQL 同样是关键词大小写不敏感的查询语言,目前支持模式匹配、聚合运算、图计算,可无嵌入组合语句。

支持图数据库:Nebula Graph

图查询语言·术语篇

在比较这 3 个图查询语言之前,我们先来看看他们各自的术语,如果你翻阅他们的文档会经常见到下面这些“关键字”,在这里我们不讲用法,只看这些图数据库常用概念在这 3 个图数据库文档中的叫法。

术语GremlinCyphernGQL点VertexNodeVertex边EdgeRelationshipEdge点类型LabelLabelTag边类型labelRelationshipTypeedge type点 IDvidid(n)vid边 IDeidid?无插入addcreateinsert删除dropdeletedelete / drop更新属性setPropertysetupdate

我们可以看到大体上对点和边的叫法类似,只不过 Cypher 中直接使用了 Relationship 关系一词代表边。其他的术语基本都非常直观。

图查询语言·实操篇

上面说了一通术语之类的“干货”之后,是时候展示真正的技术了——来个具体一点的例子,在具体的例子中我们将会分析 Gremlin、Cypher、nGQL 的用法不同。

示例图:The Graphs of Gods

实操示例使用了 Janus Graph 的示例图 The Graphs of Gods。该图结构如下图所示,描述了罗马万神话中诸神关系。

插入数据

复制代码

# 插入点## nGQLnebula> INSERT VERTEX character(name, age, type) VALUES hash("saturn"):("saturn", 10000, "titan"), hash("jupiter"):("jupiter", 5000, "god");## Gremlingremlin> saturn=g.addV("character").property(T.id, 1).property('name', 'saturn').property('age', 10000).property('type', 'titan').next();==>v[1]gremlin> jupiter=g.addV("character").property(T.id, 2).property('name', 'jupiter').property('age', 5000).property('type', 'god').next();==>v[2]gremlin> prometheus=g.addV("character").property(T.id, 31).property('name',  'prometheus').property('age', 1000).property('type', 'god').next();==>v[31]gremlin> jesus=g.addV("character").property(T.id, 32).property('name',  'jesus').property('age', 5000).property('type', 'god').next();==>v[32]## Cyphercypher> CREATE (src:character {name:"saturn", age: 10000, type:"titan"})cypher> CREATE (dst:character {name:"jupiter", age: 5000, type:"god"})# 插入边## nGQLnebula> INSERT EDGE father() VALUES hash("jupiter")->hash("saturn"):();## Gremlingremlin> g.addE("father").from(jupiter).to(saturn).property(T.id, 13);==>e[13][2-father->1]## Cyphercypher> CREATE (src)-[rel:father]->(dst)

在数据插入这块,我们可以看到 nGQL 使用 INSERT VERTEX 插入点,而 Gremlin 直接使用类函数的 g.addV() 来插入点,Cypher 使用 CREATE 这个 SQL 常见关键词来创建插入的点。在点对应的属性值方面,nGQL 通过 VALUES 关键词来赋值,Gremlin 则通过操作 .property() 进行对应属性的赋值,Cypher 更直观直接在对应的属性值后面跟上想对应的值。

在边插入方面,可以看到和点的使用语法类似,只不过在 Cypher 和 nGQL 中分别使用 -[]-> 和 **-> 来表示关系,而 Gremlin 则用 to() ** 关键词来标识指向关系,在使用这 3 种图查询语言的图数据库中的边均为有向边,下图左边为有向边,右边为无向边。

删除数据

复制代码

# nGQLnebula> DELETE VERTEX hash("prometheus");# Gremlingremlin> g.V(prometheus).drop();# Cyphercypher> MATCH (n:character {name:"prometheus"}) DETACH DELETE n 

这里,我们可以看到大家的删除关键词都是类似的:Delete 和 Drop,不过这里需要注意的是上面术语篇中提过 nGQL 中删除操作对应单词有 Delete 和 Drop ,在 nGQL 中 Delete 一般用于点边,Drop 用于 Schema 删除,这点和 SQL 的设计思路是一样的。

更新数据

复制代码

# nGQLnebula> UPDATE VERTEX hash("jesus") SET character.type='titan';# Gremlingremlin> g.V(jesus).property('age', 6000);==>v[32]# Cyphercypher> MATCH (n:character {name:"jesus"}) SET n.type='titan';

可以看到 Cypher 和 nGQL 都使用 SET 关键词来设置点对应的类型值,只不过 nGQL 中多了 UPDATE 关键词来标识操作,Gremlin 的操作和查看点操作类似,只不过增加了变更 property 值操作,这里我们注意到的是,Cypher 中常见的一个关键词便是 MATCH,顾名思义,它是一个查询关键词,它会去选择匹配对应条件下的点边,再进行下一步操作。

查看数据

复制代码

# nGQLnebula> FETCH PROP ON character hash("saturn");===================================================| character.name | character.age | character.type |===================================================| saturn         | 10000         | titan          |---------------------------------------------------# Gremlingremlin> g.V(saturn).valueMap();==>[name:[saturn],type:[titan],age:[10000]]# Cyphercypher> MATCH (n:character {name:"saturn"}) RETURN properties(n)  ╒════════════════════════════════════════════╕  │"properties(n)"                             │  ╞════════════════════════════════════════════╡  │{"name":"saturn","type":"titan","age":10000}│  └────────────────────────────────────────────┘

在查看数据这块,Gremlin 通过调取 valueMap() 获得对应的属性值,而 Cypher 正如上面更新数据所说,依旧是 MATCH 关键词来进行对应的匹配查询再通过 RETURN 返回对应的数值,而 nGQL 则对 saturn 进行 hash 运算得到对应 VID 之后去获取对应 VID 的属性值。

查询 hercules 的父亲

复制代码

# nGQLnebula>  LOOKUP ON character WHERE character.name=='hercules' | \      -> GO FROM $-.VertexID OVER father YIELD $$.character.name;=====================| $$.character.name |=====================| jupiter           |---------------------# Gremlingremlin> g.V().hasLabel('character').has('name','hercules').out('father').values('name');==>jupiter# Cyphercypher> MATCH (src:character{name:"hercules"})-[:father]->(dst:character) RETURN dst.name      ╒══════════╕      │"dst.name"│      ╞══════════╡      │"jupiter" │      └──────────┘

查询父亲,其实是一个查询关系 / 边的操作,这里不做赘述,上面插入边的时候简单介绍了 Gremlin、Cypher、nGQL 这三种图数据库是各自用来标识边的关键词和操作符是什么。

查询 hercules 的祖父

复制代码

# nGQLnebula> LOOKUP ON character WHERE character.name=='hercules' | \     -> GO 2 STEPS FROM $-.VertexID OVER father YIELD $$.character.name;=====================| $$.character.name |=====================| saturn            |---------------------# Gremlingremlin> g.V().hasLabel('character').has('name','hercules').out('father').out('father').values('name');==>saturn# Cyphercypher> MATCH (src:character{name:"hercules"})-[:father*2]->(dst:character) RETURN dst.name      ╒══════════╕      │"dst.name"│      ╞══════════╡      │"saturn"  │      └──────────┘

查询祖父,其实是一个查询对应点的两跳关系,即:父亲的父亲,我们可以看到 Gremlin 使用了两次 out() 来表示为祖父,而 nGQL 这里使用了 (Pipe 管道) 的概念,用于子查询。在两跳关系处理上,上面说到 Gremlin 是用了 2 次 out(),而 Cypher、nGQL 则引入了 step 数的概念,分别对应到查询语句的 GO 2 STEP 和 [:father *2],相对来说 Cypher、nGQL 这样书写更优雅。

查询年龄大于 100 的人物

复制代码

# nGQLnebula> LOOKUP ON character WHERE character.age > 100 YIELD character.name, character.age;=========================================================| VertexID             | character.name | character.age |=========================================================| 6761447489613431910  | pluto          | 4000          |---------------------------------------------------------| -5860788569139907963 | neptune        | 4500          |---------------------------------------------------------| 4863977009196259577  | jupiter        | 5000          |---------------------------------------------------------| -4316810810681305233 | saturn         | 10000         |---------------------------------------------------------# Gremlingremlin> g.V().hasLabel('character').has('age',gt(100)).values('name');==>saturn==>jupiter==>neptune==>pluto# Cyphercypher> MATCH (src:character) WHERE src.age > 100 RETURN src.name      ╒═══════════╕      │"src.name" │      ╞═══════════╡      │  "saturn" │      ├───────────┤      │ "jupiter" │      ├───────────┤      │ "neptune" │      │───────────│      │  "pluto"  │      └───────────┘

这个是一个典型的查询语句,找寻符合特定条件的点并返回结果,在 Cypher 和 nGQL 中用 WHRER 进行条件判断,而 Gremlin 延续了它的“编程风”用 gt(100) 表示年大于龄 100 的这个筛选条件,延伸下 Gremlin 中 eq() 则表示等于这个查询条件。

从一起居住的人物中排除 pluto 本人

复制代码

# nGQLnebula>  GO FROM hash("pluto") OVER lives YIELD lives._dst AS place | GO FROM $-.place OVER lives REVERSELY WHERE $$.character.name !="pluto" YIELD $$.character.name AS cohabitants;===============| cohabitants |===============| cerberus    |---------------# Gremlingremlin> g.V(pluto).out('lives').in('lives').where(is(neq(pluto))).values('name');==>cerberus# Cyphercypher> MATCH (src:character{name:"pluto"})-[:lives]->()<-[:lives]-(dst:character) RETURN dst.name      ╒══════════╕      │"dst.name"│      ╞══════════╡      │"cerberus"│      └──────────┘

这是一个沿指定点 Pluto 反向查询指定边(居住)的操作,在反向查询中,Gremlin 使用了 in 来表示反向关系,而 Cypher 则更直观的将指向箭头反向变成 <- 来表示反向关系,nGQL 则用关键词 REVERSELY 来标识反向关系。

Pluto 的兄弟们居住在哪

复制代码

# which brother lives in which place?## nGQLnebula> GO FROM hash("pluto") OVER brother YIELD brother._dst AS god | \GO FROM $-.god OVER lives YIELD $^.character.name AS Brother, $$.location.name AS Habitations;=========================| Brother | Habitations |=========================| jupiter | sky         |-------------------------| neptune | sea         |-------------------------## Gremlingremlin> g.V(pluto).out('brother').as('god').out('lives').as('place').select('god','place').by('name');==>[god:jupiter, place:sky]==>[god:neptune, place:sea]## Cyphercypher> MATCH (src:Character{name:"pluto"})-[:brother]->(bro:Character)-[:lives]->(dst)RETURN bro.name, dst.name      ╒═════════════════════════╕      │"bro.name"    │"dst.name"│      ╞═════════════════════════╡      │ "jupiter"    │  "sky"   │      ├─────────────────────────┤      │ "neptune"    │ "sea"    │      └─────────────────────────┘

这是一个通过查询指定点 Pluto 查询指定边 brother 后再查询指定边 live 的查询,相对来说不是很复杂,这里就不做解释说明了。

最后,本文只是对 Gremlin、Cypher、nGQL 等 3 个图查询语言进行了简单的介绍,更复杂的语法将在本系列的后续文章中继续,欢迎在论坛留言交流。