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