Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
avaWeb連接MySQL數(shù)據(jù)庫的方式有很多,首先我們講解JDBC的配置方法
什么是JDBC嘞?JDBC代表Java數(shù)據(jù)庫連接(Java Database Connectivity),它是用于Java編程語言和數(shù)據(jù)庫之間的數(shù)據(jù)庫無關(guān)連接的標(biāo)準(zhǔn)Java API,
換句話說:JDBC是用于在Java語言編程中與數(shù)據(jù)庫連接的API。
JDBC庫包括通常與數(shù)據(jù)庫使用相關(guān),如下面提到的每個任務(wù)的API -
從根本上說,JDBC是一個規(guī)范,它提供了一整套接口,允許以一種可移植的訪問底層數(shù)據(jù)庫API。 Java可以用它來編寫不同類型的可執(zhí)行文件,如 -
所有這些不同的可執(zhí)行文件都能夠使用JDBC驅(qū)動程序來訪問數(shù)據(jù)庫,并用于存儲數(shù)據(jù)到數(shù)據(jù)庫中。
JDBC提供與ODBC相同的功能,允許Java程序包含與數(shù)據(jù)庫無關(guān)的代碼(同樣的代碼,只需要指定使用的數(shù)據(jù)庫類型,不需要重修改數(shù)據(jù)庫查詢或操作代碼)。
這里附上一鍵直達(dá)的鏈接:MySQL :: Download MySQL Connector/J (Archived Versions)
首先打開MySQL官網(wǎng),點擊DOWNLOADS
之后我們點擊MySQL Community(GPL) Downloads
點擊Connector/J
點擊Archives
按照圖片進(jìn)行選擇并下載(這里我們不可以選擇上方的那個文件,因為上面那個文件是Liunx、Dabian等系統(tǒng)的文件,下面的文件才是Windows版本的!!!)
至此,我們下載完成。
我們將下載的壓縮包進(jìn)行解壓,在生成的文件中會有一個名為mysql-connector-java-8.0.28.jar的文件。
我們要在需要與MySQL連接的項目中建立一個lib文件夾,并將.jar文件復(fù)制粘貼到此文件夾下(也可以直接進(jìn)行拖拽)
之后我們用右鍵,按照圖片上的步驟操作,添加驅(qū)動程序路徑(成功后會多出一個
文件)
到這里不要著急,下面我們將.jar包導(dǎo)入到你電腦Tomcat文件根目錄下的lib文件夾內(nèi),這樣,你就完成了所有配置!
連接數(shù)據(jù)庫時,需要將數(shù)據(jù)庫驅(qū)動程序注冊到j(luò)dbc的驅(qū)動管理器中。
調(diào)用Class.forName()方法例如:Class.forName(“com.mysql.jdbc.Driver”);當(dāng)jdbc驅(qū)動程序mysql-connector-java-5.0.5-bin.jar為6.x版本以上時,調(diào)用為Class.forName(“com.mysql.cj.jdbc.Driver”);
雖然不同數(shù)據(jù)庫廠商的URL不完全相同,但是都符合一個基本的格式,即“jdbc協(xié)議+IP地址或域名+端口號+數(shù)據(jù)庫名稱”。
創(chuàng)建數(shù)據(jù)庫連接時,需要使用DriverManager類中g(shù)etConnection()的靜態(tài)方法,方法聲明如下:DriverManager.getConnection(String url,String username,password);
下面我們寫一個JSP代碼,用來驗證是否可以連接MySQL數(shù)據(jù)庫。
<%@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"); //顯示聲明將數(shù)據(jù)庫驅(qū)動程序注冊到j(luò)dbc的驅(qū)動管理器中 String url="jdbc:mysql://localhost:3306/text"; //數(shù)據(jù)庫名稱為text(需要提前在MySQL里面建立text數(shù)據(jù)庫) String username="root"; //數(shù)據(jù)庫用戶名 String password="123456"; //數(shù)據(jù)庫密碼 Connection conn=DriverManager.getConnection(url, username, password); //連接數(shù)據(jù)庫 out.print("數(shù)據(jù)庫連接成功!"); conn.close(); } catch (Exception e) { out.print("數(shù)據(jù)庫連接失敗!"); out.print("錯誤信息:" + e.toString()); } %> </body></html>
PS:這里需要注意的是我們自己使用時一定要修改成自己MySQL的用戶名和密碼,保證可以正常連接數(shù)據(jù)庫。并且我們連接的數(shù)據(jù)庫一定要存在!!!
首先需要創(chuàng)建一個新的首頁,首頁可以顯示用戶名,密碼,登錄按鈕等。代碼如下:
<%@ 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>
效果如下:
接下來我們創(chuàng)建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); } }
代碼如下:
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; } }
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; } }
<%@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> <% //加載、注冊數(shù)據(jù)庫驅(qū)動程序 Class.forName("com.mysql.cj.jdbc.Driver"); //數(shù)據(jù)庫連接字符串 String url="jdbc:mysql://localhost:3306/text"; //用戶名 String username="root"; //密碼 String password="123456"; //數(shù)據(jù)庫連接 Connection conn=DriverManager.getConnection(url, username, password); //構(gòu)造sql語句 String sql="select * from user"; //獲取數(shù)據(jù)庫操作對象(PreparedStatement對象) PreparedStatement pstmt=conn.prepareStatement(sql); ResultSet rs=pstmt.executeQuery(); //循環(huán)前準(zhǔn)備變量 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>
<%@ 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>
如果本文對你有幫助,別忘記給我個3連 ,點贊,轉(zhuǎn)發(fā),評論,,咱們下期見。
收藏 等于白嫖,點贊才是真情。
原文 https://www.cnblogs.com/soosoo/p/16219491.html
先說明,由于是8版本的數(shù)據(jù)庫,所以配置類的寫法上與5版本的有所區(qū)別,需要注意,同時用idea或eclipse時需要導(dǎo)入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導(dǎo)入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 '始發(fā)地',
`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 '列車狀態(tài)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3
然后創(chuàng)建連接的配置類DbConfig.java,localhost是本機(jī)的ip地址,如果有服務(wù)器就填服務(wù)器的ip地址,message是數(shù)據(jù)庫的名字,這里一張圖說下有很多新手誤解的名字
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 數(shù)據(jù)庫配置類
* @author 景苒
*/
public class DbConfig {
public Connection dbConfig() throws SQLException {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
}catch (Exception e) {
System.out.print("加載驅(qū)動失敗!");
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);
}
}
然后寫下主函數(shù)Main.java,這里主函數(shù)的函數(shù)體可以在最后再寫,需要什么功能就把注釋打開就好,快捷注釋的方法,選中這句話,按ctrl加/,就能全注釋了。
import java.sql.SQLException;
/**
* 主函數(shù),調(diào)用功能
* @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.查詢沈陽到武漢的所有列車信息,按出發(fā)時間先后排序
建GetMessage.java類
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 查詢沈陽到武漢的所有列車信息,按出發(fā)時間先后排序
* @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")
+ " 始發(fā)站:" + rs.getString("origin")
+ " 終到站:" + rs.getString("terminal")
+ " 出發(fā)時間:" + rs.getString("departure_time")
+ " 列車狀態(tài):" + rs.getString("state"));
}
}catch (SQLException e) {
e.printStackTrace();
}finally {
ps.close();
con.close();
}
}
}
2.修改T2255列車的狀態(tài)為停運(yùn)
建UpdateTrainState.java類
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 修改T2255列車的狀態(tài)為停運(yùn)
* @author 景苒
*/
public class UpdateTrainState {
public void updateTrainState() throws SQLException {
Connection con=new DbConfig().dbConfig();
String sql="UPDATE `train_message` SET state='停運(yùn)' 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;
/**
* 新增一輛列車信息(自己輸入)
* 始發(fā)時間為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("請輸入始發(fā)站:");
String origin=scanner.nextLine();
System.out.print("請輸入終到站:");
String terminal=scanner.nextLine();
System.out.print("請輸入始發(fā)時間:");
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.查詢狀態(tài)為正常的列車數(shù)量
建GetNumber.java類
import java.sql.Statement;
/**
* 查詢狀態(tài)為正常的列車數(shù)量
* @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("狀態(tài)為正常的列車數(shù)量為:" + resultSet.getInt(1));
}
}catch (SQLException e){
e.printStackTrace();
}finally {
statement.close();
con.close();
}
}
}
最后附上navicat的屬性結(jié)構(gòu)圖和樣例插入的語句
數(shù)據(jù)根據(jù)自己需求自行寫入幾個就行,以上就是java連接mysql數(shù)據(jù)庫的實例代碼,eclipse也大同小異,就導(dǎo)入jar包的方式不同。
文章來自https://www.cnblogs.com/jingran/p/16120104.html
數(shù)據(jù)庫已經(jīng)越來越被人們熟知,同時也在許多企業(yè)中得到了應(yīng)用,但是由于市面上沒有統(tǒng)一的圖查詢語言標(biāo)準(zhǔn),所以有部分開發(fā)者對于不同圖數(shù)據(jù)庫的用法存在著疑問。因此本文作者對市面上主流的幾款圖數(shù)據(jù)庫進(jìn)行了一番分析,并以查詢操作為例進(jìn)行深入介紹。
文章的開頭我們先來看下什么是圖數(shù)據(jù)庫,根據(jù)維基百科的定義:圖數(shù)據(jù)庫是使用圖結(jié)構(gòu)進(jìn)行語義查詢的數(shù)據(jù)庫,它使用節(jié)點、邊和屬性來表示和存儲數(shù)據(jù)。
雖然和關(guān)系型數(shù)據(jù)庫存儲的結(jié)構(gòu)不同(關(guān)系型數(shù)據(jù)庫為表結(jié)構(gòu),圖數(shù)據(jù)庫為圖結(jié)構(gòu)),但不計各自的性能問題,關(guān)系型數(shù)據(jù)庫可以通過遞歸查詢或者組合其他 SQL 語句(Join)完成圖查詢語言查詢節(jié)點關(guān)系操作。得益于 1987 年 SQL 成為國際標(biāo)準(zhǔn)化組織(ISO)標(biāo)準(zhǔn),關(guān)系型數(shù)據(jù)庫行業(yè)得到了很好的發(fā)展。同 60、70 年代的關(guān)系型數(shù)據(jù)庫類似,圖數(shù)據(jù)庫這個領(lǐng)域的查詢語言目前也沒有統(tǒng)一標(biāo)準(zhǔn),雖然 19 年 9 月經(jīng)過國際 SQL 標(biāo)準(zhǔn)委員會投票表決,決定將圖查詢語言(Graph Query Language)納為一種新的數(shù)據(jù)庫查詢語言,但 GQL 的制定仍需要一段時間。
鑒于市面上沒有統(tǒng)一的圖查詢語言標(biāo)準(zhǔn),在本文中我們選取市面上主流的幾款圖查詢語言來分析一波用法,由于篇幅原因本文旨在簡單介紹圖查詢語言和常規(guī)用法,更詳細(xì)的內(nèi)容將在進(jìn)階篇中講述。
Gremlin 是 Apache ThinkerPop 框架下的圖遍歷語言。Gremlin 可以是聲明性的也可以是命令性的。雖然 Gremlin 是基于 Groovy 的,但具有許多語言變體,允許開發(fā)人員以 Java、JavaScript、Python、Scala、Clojure 和 Groovy 等許多現(xiàn)代編程語言原生編寫 Gremlin 查詢。
支持圖數(shù)據(jù)庫:Janus Graph、InfiniteGraph、Cosmos DB、DataStax Enterprise(5.0+) 、Amazon Neptune
Cypher 是一個描述性的圖形查詢語言,允許不必編寫圖形結(jié)構(gòu)的遍歷代碼對圖形存儲有表現(xiàn)力和效率的查詢,和 SQL 很相似,Cypher 語言的關(guān)鍵字不區(qū)分大小寫,但是屬性值,標(biāo)簽,關(guān)系類型和變量是區(qū)分大小寫的。
支持圖數(shù)據(jù)庫: Neo4j、RedisGraph、AgensGraph
nGQL 是一種類 SQL 的聲明型的文本查詢語言,nGQL 同樣是關(guān)鍵詞大小寫不敏感的查詢語言,目前支持模式匹配、聚合運(yùn)算、圖計算,可無嵌入組合語句。
支持圖數(shù)據(jù)庫:Nebula Graph
在比較這 3 個圖查詢語言之前,我們先來看看他們各自的術(shù)語,如果你翻閱他們的文檔會經(jīng)常見到下面這些“關(guān)鍵字”,在這里我們不講用法,只看這些圖數(shù)據(jù)庫常用概念在這 3 個圖數(shù)據(jù)庫文檔中的叫法。
術(shù)語GremlinCyphernGQL點VertexNodeVertex邊EdgeRelationshipEdge點類型LabelLabelTag邊類型labelRelationshipTypeedge type點 IDvidid(n)vid邊 IDeidid?無插入addcreateinsert刪除dropdeletedelete / drop更新屬性setPropertysetupdate
我們可以看到大體上對點和邊的叫法類似,只不過 Cypher 中直接使用了 Relationship 關(guān)系一詞代表邊。其他的術(shù)語基本都非常直觀。
上面說了一通術(shù)語之類的“干貨”之后,是時候展示真正的技術(shù)了——來個具體一點的例子,在具體的例子中我們將會分析 Gremlin、Cypher、nGQL 的用法不同。
實操示例使用了 Janus Graph 的示例圖 The Graphs of Gods。該圖結(jié)構(gòu)如下圖所示,描述了羅馬萬神話中諸神關(guān)系。
復(fù)制代碼
# 插入點## 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)
在數(shù)據(jù)插入這塊,我們可以看到 nGQL 使用 INSERT VERTEX 插入點,而 Gremlin 直接使用類函數(shù)的 g.addV() 來插入點,Cypher 使用 CREATE 這個 SQL 常見關(guān)鍵詞來創(chuàng)建插入的點。在點對應(yīng)的屬性值方面,nGQL 通過 VALUES 關(guān)鍵詞來賦值,Gremlin 則通過操作 .property() 進(jìn)行對應(yīng)屬性的賦值,Cypher 更直觀直接在對應(yīng)的屬性值后面跟上想對應(yīng)的值。
在邊插入方面,可以看到和點的使用語法類似,只不過在 Cypher 和 nGQL 中分別使用 -[]-> 和 **-> 來表示關(guān)系,而 Gremlin 則用 to() ** 關(guān)鍵詞來標(biāo)識指向關(guān)系,在使用這 3 種圖查詢語言的圖數(shù)據(jù)庫中的邊均為有向邊,下圖左邊為有向邊,右邊為無向邊。
復(fù)制代碼
# nGQLnebula> DELETE VERTEX hash("prometheus");# Gremlingremlin> g.V(prometheus).drop();# Cyphercypher> MATCH (n:character {name:"prometheus"}) DETACH DELETE n
這里,我們可以看到大家的刪除關(guān)鍵詞都是類似的:Delete 和 Drop,不過這里需要注意的是上面術(shù)語篇中提過 nGQL 中刪除操作對應(yīng)單詞有 Delete 和 Drop ,在 nGQL 中 Delete 一般用于點邊,Drop 用于 Schema 刪除,這點和 SQL 的設(shè)計思路是一樣的。
復(fù)制代碼
# 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 關(guān)鍵詞來設(shè)置點對應(yīng)的類型值,只不過 nGQL 中多了 UPDATE 關(guān)鍵詞來標(biāo)識操作,Gremlin 的操作和查看點操作類似,只不過增加了變更 property 值操作,這里我們注意到的是,Cypher 中常見的一個關(guān)鍵詞便是 MATCH,顧名思義,它是一個查詢關(guān)鍵詞,它會去選擇匹配對應(yīng)條件下的點邊,再進(jìn)行下一步操作。
復(fù)制代碼
# 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}│ └────────────────────────────────────────────┘
在查看數(shù)據(jù)這塊,Gremlin 通過調(diào)取 valueMap() 獲得對應(yīng)的屬性值,而 Cypher 正如上面更新數(shù)據(jù)所說,依舊是 MATCH 關(guān)鍵詞來進(jìn)行對應(yīng)的匹配查詢再通過 RETURN 返回對應(yīng)的數(shù)值,而 nGQL 則對 saturn 進(jìn)行 hash 運(yùn)算得到對應(yīng) VID 之后去獲取對應(yīng) VID 的屬性值。
復(fù)制代碼
# 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" │ └──────────┘
查詢父親,其實是一個查詢關(guān)系 / 邊的操作,這里不做贅述,上面插入邊的時候簡單介紹了 Gremlin、Cypher、nGQL 這三種圖數(shù)據(jù)庫是各自用來標(biāo)識邊的關(guān)鍵詞和操作符是什么。
復(fù)制代碼
# 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" │ └──────────┘
查詢祖父,其實是一個查詢對應(yīng)點的兩跳關(guān)系,即:父親的父親,我們可以看到 Gremlin 使用了兩次 out() 來表示為祖父,而 nGQL 這里使用了 |(Pipe 管道) 的概念,用于子查詢。在兩跳關(guān)系處理上,上面說到 Gremlin 是用了 2 次 out(),而 Cypher、nGQL 則引入了 step 數(shù)的概念,分別對應(yīng)到查詢語句的 GO 2 STEP 和 [:father *2],相對來說 Cypher、nGQL 這樣書寫更優(yōu)雅。
復(fù)制代碼
# 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" │ └───────────┘
這個是一個典型的查詢語句,找尋符合特定條件的點并返回結(jié)果,在 Cypher 和 nGQL 中用 WHRER 進(jìn)行條件判斷,而 Gremlin 延續(xù)了它的“編程風(fēng)”用 gt(100) 表示年大于齡 100 的這個篩選條件,延伸下 Gremlin 中 eq() 則表示等于這個查詢條件。
復(fù)制代碼
# 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 來表示反向關(guān)系,而 Cypher 則更直觀的將指向箭頭反向變成 <- 來表示反向關(guān)系,nGQL 則用關(guān)鍵詞 REVERSELY 來標(biāo)識反向關(guān)系。
復(fù)制代碼
# 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 的查詢,相對來說不是很復(fù)雜,這里就不做解釋說明了。
最后,本文只是對 Gremlin、Cypher、nGQL 等 3 個圖查詢語言進(jìn)行了簡單的介紹,更復(fù)雜的語法將在本系列的后續(xù)文章中繼續(xù),歡迎在論壇留言交流。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。