nvGRAPH API参考分析(二)

nvGRAPH Code Examples

本文提供了简单的示例。

1. nvGRAPH convert topology example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

int main(int argc, char **argv) {

size_t  n = 6, nnz = 10;

// nvgraph variables

nvgraphHandle_t handle;

nvgraphCSCTopology32I_t CSC_input;

nvgraphCSRTopology32I_t CSR_output;

float *src_weights_d, *dst_weights_d;

cudaDataType_t edge_dimT = CUDA_R_32F;

// Allocate source data

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

cudaMalloc( (void**)&(CSC_input->destination_offsets), (n+1)*sizeof(int));

cudaMalloc( (void**)&(CSC_input->source_indices), nnz*sizeof(int));

cudaMalloc( (void**)&src_weights_d, nnz*sizeof(float));

// Copy source data

float src_weights_h[] = {0.333333f, 0.5f, 0.333333f, 0.5f, 0.5f, 1.0f, 0.333333f, 0.5f, 0.5f, 0.5f};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

cudaMemcpy(CSC_input->destination_offsets, destination_offsets_h, (n+1)*sizeof(int), cudaMemcpyDefault);

cudaMemcpy(CSC_input->source_indices, source_indices_h, nnz*sizeof(int), cudaMemcpyDefault);

cudaMemcpy(src_weights_d, src_weights_h, nnz*sizeof(float), cudaMemcpyDefault);

// Allocate destination data

CSR_output = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSRTopology32I_st));

cudaMalloc( (void**)&(CSR_output->source_offsets), (n+1)*sizeof(int));

cudaMalloc( (void**)&(CSR_output->destination_indices), nnz*sizeof(int));

cudaMalloc( (void**)&dst_weights_d, nnz*sizeof(float));

// Starting nvgraph and convert

check(nvgraphCreate (&handle));

check(nvgraphConvertTopology(handle, NVGRAPH_CSC_32, CSC_input, src_weights_d,

&edge_dimT, NVGRAPH_CSR_32, CSR_output, dst_weights_d));

// Free memory

check(nvgraphDestroy(handle));

cudaFree(CSC_input->destination_offsets);

cudaFree(CSC_input->source_indices);

cudaFree(CSR_output->source_offsets);

cudaFree(CSR_output->destination_indices);

cudaFree(src_weights_d);

cudaFree(dst_weights_d);

free(CSC_input);

free(CSR_output);

return 0;

}

2. nvGRAPH convert graph example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

int main(int argc, char **argv) {

size_t  n = 6, nnz = 10, vert_sets = 2, edge_sets = 1;

// nvgraph variables

nvgraphHandle_t handle; nvgraphGraphDescr_t src_csc_graph;

nvgraphCSCTopology32I_t CSC_input;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// Allocate host data

float *pr_1 = (float*)malloc(n*sizeof(float));

void **vertex_dim = (void**)malloc(vert_sets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vert_sets*sizeof(cudaDataType_t));

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

// Initialize host data

float weights_h[] = {0.333333f, 0.5f, 0.333333f, 0.5f, 0.5f, 1.0f, 0.333333f, 0.5f, 0.5f, 0.5f};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

float bookmark_h[] = {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f};

vertex_dim[0] = (void*)bookmark_h; vertex_dim[1]= (void*)pr_1;

vertex_dimT[0] = CUDA_R_32F; vertex_dimT[1]= CUDA_R_32F, vertex_dimT[2]= CUDA_R_32F;

// Starting nvgraph

check(nvgraphCreate (&handle));

check(nvgraphCreateGraphDescr (handle, &src_csc_graph));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

CSC_input->destination_offsets = destination_offsets_h;

CSC_input->source_indices = source_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, src_csc_graph, (void*)CSC_input, NVGRAPH_CSC_32));

check(nvgraphAllocateVertexData(handle, src_csc_graph, vert_sets, vertex_dimT));

check(nvgraphAllocateEdgeData  (handle, src_csc_graph, edge_sets, &edge_dimT));

for (int i = 0; i < 2; ++i)

check(nvgraphSetVertexData(handle, src_csc_graph, vertex_dim[i], i));

check(nvgraphSetEdgeData(handle, src_csc_graph, (void*)weights_h, 0));

// Convert to CSR graph

nvgraphGraphDescr_t dst_csr_graph;

check(nvgraphCreateGraphDescr (handle, &dst_csr_graph));

check(nvgraphConvertGraph(handle, src_csc_graph, dst_csr_graph, NVGRAPH_CSR_32));

check(nvgraphDestroyGraphDescr(handle, src_csc_graph));

check(nvgraphDestroyGraphDescr(handle, dst_csr_graph));

check(nvgraphDestroy(handle));

free(pr_1); free(vertex_dim); free(vertex_dimT);

free(CSC_input);

return 0;

}

3. nvGRAPH pagerank example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

int main(int argc, char **argv) {

size_t  n = 6, nnz = 10, vert_sets = 2, edge_sets = 1;

float alpha1 = 0.9f; void *alpha1_p = (void *) &alpha1;

// nvgraph variables

nvgraphHandle_t handle; nvgraphGraphDescr_t graph;

nvgraphCSCTopology32I_t CSC_input;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// Allocate host data

float *pr_1 = (float*)malloc(n*sizeof(float));

void **vertex_dim = (void**)malloc(vert_sets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vert_sets*sizeof(cudaDataType_t));

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

// Initialize host data

float weights_h[] = {0.333333f, 0.5f, 0.333333f, 0.5f, 0.5f, 1.0f, 0.333333f, 0.5f, 0.5f, 0.5f};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

float bookmark_h[] = {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f};

vertex_dim[0] = (void*)bookmark_h; vertex_dim[1]= (void*)pr_1;

vertex_dimT[0] = CUDA_R_32F; vertex_dimT[1]= CUDA_R_32F, vertex_dimT[2]= CUDA_R_32F;

// Starting nvgraph

check(nvgraphCreate (&handle));

check(nvgraphCreateGraphDescr (handle, &graph));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

CSC_input->destination_offsets = destination_offsets_h;

CSC_input->source_indices = source_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, graph, (void*)CSC_input, NVGRAPH_CSC_32));

check(nvgraphAllocateVertexData(handle, graph, vert_sets, vertex_dimT));

check(nvgraphAllocateEdgeData  (handle, graph, edge_sets, &edge_dimT));

for (int i = 0; i < 2; ++i)

check(nvgraphSetVertexData(handle, graph, vertex_dim[i], i));

check(nvgraphSetEdgeData(handle, graph, (void*)weights_h, 0));

check(nvgraphPagerank(handle, graph, 0, alpha1_p, 0, 0, 1, 0.0f, 0));

// Get result

check(nvgraphGetVertexData(handle, graph, vertex_dim[1], 1));

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

free(pr_1); free(vertex_dim); free(vertex_dimT);

free(CSC_input);

return 0;

}

4. nvGRAPH SSSP example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

int main(int argc, char **argv) {

const size_t  n = 6, nnz = 10, vertex_numsets = 1, edge_numsets = 1;

float *sssp_1_h;

void** vertex_dim;

// nvgraph variables

nvgraphStatus_t status; nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSCTopology32I_t CSC_input;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// Init host data

sssp_1_h = (float*)malloc(n*sizeof(float));

vertex_dim  = (void**)malloc(vertex_numsets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vertex_numsets*sizeof(cudaDataType_t));

CSC_input = (nvgraphCSCTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

vertex_dim[0]= (void*)sssp_1_h; vertex_dimT[0] = CUDA_R_32F;

float weights_h[] = {0.333333, 0.5, 0.333333, 0.5, 0.5, 1.0, 0.333333, 0.5, 0.5, 0.5};

int destination_offsets_h[] = {0, 1, 3, 4, 6, 8, 10};

int source_indices_h[] = {2, 0, 2, 0, 4, 5, 2, 3, 3, 4};

check(nvgraphCreate(&handle));

check(nvgraphCreateGraphDescr (handle, &graph));

CSC_input->nvertices = n; CSC_input->nedges = nnz;

CSC_input->destination_offsets = destination_offsets_h;

CSC_input->source_indices = source_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, graph, (void*)CSC_input, NVGRAPH_CSC_32));

check(nvgraphAllocateVertexData(handle, graph, vertex_numsets, vertex_dimT));

check(nvgraphAllocateEdgeData  (handle, graph, edge_numsets, &edge_dimT));

check(nvgraphSetEdgeData(handle, graph, (void*)weights_h, 0));

// Solve

int source_vert = 0;

check(nvgraphSssp(handle, graph, 0,  &source_vert, 0));

// Get and print result

check(nvgraphGetVertexData(handle, graph, (void*)sssp_1_h, 0));

//Clean

free(sssp_1_h); free(vertex_dim);

free(vertex_dimT); free(CSC_input);

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

return 0;

}

5. nvGRAPH Semi-Ring SPMV example

void check(nvgraphStatus_t status) {

if (status != NVGRAPH_STATUS_SUCCESS) {

printf("ERROR : %d\n",status);

exit(0);

}

}

int main(int argc, char **argv) {

size_t  n = 5, nnz = 10, vertex_numsets = 2, edge_numsets = 1;

float alpha = 1.0, beta = 0.0;

void *alpha_p = (void *)&alpha, *beta_p = (void *)&beta;

void** vertex_dim;

cudaDataType_t edge_dimT = CUDA_R_32F;

cudaDataType_t* vertex_dimT;

// nvgraph variables

nvgraphStatus_t status; nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSRTopology32I_t CSR_input;

// Init host data

vertex_dim  = (void**)malloc(vertex_numsets*sizeof(void*));

vertex_dimT = (cudaDataType_t*)malloc(vertex_numsets*sizeof(cudaDataType_t));

CSR_input = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSRTopology32I_st));

float x_h[] = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f};

float y_h[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f};

vertex_dim[0]= (void*)x_h; vertex_dim[1]= (void*)y_h;

vertex_dimT[0] = CUDA_R_32F; vertex_dimT[1]= CUDA_R_32F;

float weights_h[] = {1.0f, 4.0f, 2.0f, 3.0f, 5.0f, 7.0f, 8.0f, 9.0f, 6.0f, 1.5f};

int source_offsets_h[] = {0, 2, 4, 7, 9, 10};

int destination_indices_h[] = {0, 1, 1, 2, 0, 3, 4, 2, 4, 2};

check(nvgraphCreate(&handle));

check(nvgraphCreateGraphDescr(handle, &graph));

CSR_input->nvertices = n; CSR_input->nedges = nnz;

CSR_input->source_offsets = source_offsets_h;

CSR_input->destination_indices = destination_indices_h;

// Set graph connectivity and properties (tranfers)

check(nvgraphSetGraphStructure(handle, graph, (void*)CSR_input, NVGRAPH_CSR_32));

check(nvgraphAllocateVertexData(handle, graph, vertex_numsets, vertex_dimT));

for (int i = 0; i < vertex_numsets; ++i)

check(nvgraphSetVertexData(handle, graph, vertex_dim[i], i));

check(nvgraphAllocateEdgeData  (handle, graph, edge_numsets, &edge_dimT));

check(nvgraphSetEdgeData(handle, graph, (void*)weights_h, 0));

// Solve

check(nvgraphSrSpmv(handle, graph, 0, alpha_p, 0, beta_p, 1, NVGRAPH_PLUS_TIMES_SR));

//Get result

check(nvgraphGetVertexData(handle, graph, (void*)y_h, 1));

//Clean

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

free(vertex_dim); free(vertex_dimT); free(CSR_input);

return 0;

}

6. nvGRAPH Triangles Counting example

#include "stdlib.h"

#include "inttypes.h"

#include "stdio.h"

#include "nvgraph.h"

#define check( a ) \

{\

nvgraphStatus_t status = (a);\

if ( (status) != NVGRAPH_STATUS_SUCCESS) {\

printf("ERROR : %d in %s : %d\n", status, __FILE__ , __LINE__ );\

exit(0);\

}\

}

int main(int argc, char **argv)

{

// nvgraph variables

nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSRTopology32I_t CSR_input;

// Init host data

CSR_input = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSRTopology32I_st));

// Undirected graph:

// 0       2-------4

//  \     / \     / \

//   \   /   \   /   \

//    \ /     \ /     \

//     1-------3-------5

// 3 triangles

// CSR of lower triangular of adjacency matrix:

const size_t n = 6, nnz = 8;

int source_offsets[] = {0, 0, 1, 2, 4, 6, 8};

int destination_indices[] = {0, 1, 1, 2, 2, 3, 3, 4};

check(nvgraphCreate(&handle));

check(nvgraphCreateGraphDescr (handle, &graph));

CSR_input->nvertices = n;

CSR_input->nedges = nnz;

CSR_input->source_offsets = source_offsets;

CSR_input->destination_indices = destination_indices;

// Set graph connectivity

check(nvgraphSetGraphStructure(handle, graph, (void*)CSR_input, NVGRAPH_CSR_32));

uint64_t trcount = 0;

check(nvgraphTriangleCount(handle, graph, &trcount));

printf("Triangles count: %" PRIu64 "\n", trcount);

free(CSR_input);

check(nvgraphDestroyGraphDescr(handle, graph));

check(nvgraphDestroy(handle));

return 0;

}

7. nvGRAPH Traversal example

void check_status(nvgraphStatus_t status){

if ((int)status != 0)    {

printf("ERROR : %d\n",status);

exit(0);

}

}

int main(int argc, char **argv){

//Example of graph (CSR format)

const size_t  n = 7, nnz = 12, vertex_numsets = 2, edge_numset = 0;

int source_offsets_h[] = {0, 1, 3, 4, 6, 8, 10, 12};

int destination_indices_h[] = {5, 0, 2, 0, 4, 5, 2, 3, 3, 4, 1, 5};

//where to store results (distances from source) and where to store results (predecessors in search tree)

int bfs_distances_h[n], bfs_predecessors_h[n];

// nvgraph variables

nvgraphStatus_t status;

nvgraphHandle_t handle;

nvgraphGraphDescr_t graph;

nvgraphCSRTopology32I_t CSR_input;

cudaDataType_t* vertex_dimT;

size_t distances_index = 0;

size_t predecessors_index = 1;

vertex_dimT = (cudaDataType_t*)malloc(vertex_numsets*sizeof(cudaDataType_t));

vertex_dimT[distances_index] = CUDA_R_32I;

vertex_dimT[predecessors_index] = CUDA_R_32I;

//Creating nvgraph objects

check_status(nvgraphCreate (&handle));

check_status(nvgraphCreateGraphDescr (handle, &graph));

// Set graph connectivity and properties (tranfers)

CSR_input = (nvgraphCSRTopology32I_t) malloc(sizeof(struct nvgraphCSCTopology32I_st));

CSR_input->nvertices = n;

CSR_input->nedges = nnz;

CSR_input->source_offsets = source_offsets_h;

CSR_input->destination_indices = destination_indices_h;

check_status(nvgraphSetGraphStructure(handle, graph, (void*)CSR_input, NVGRAPH_CSR_32));

check_status(nvgraphAllocateVertexData(handle, graph, vertex_numsets, vertex_dimT));

int source_vert = 1;

//Setting the traversal parameters

nvgraphTraversalParameter_t traversal_param;

nvgraphTraversalParameterInit(&traversal_param);

nvgraphTraversalSetDistancesIndex(&traversal_param, distances_index);

nvgraphTraversalSetPredecessorsIndex(&traversal_param, predecessors_index);

nvgraphTraversalSetUndirectedFlag(&traversal_param, false);

//Computing traversal using BFS algorithm

check_status(nvgraphTraversal(handle, graph, NVGRAPH_TRAVERSAL_BFS, &source_vert, traversal_param));

// Get result

check_status(nvgraphGetVertexData(handle, graph, (void*)bfs_distances_h, distances_index));

check_status(nvgraphGetVertexData(handle, graph, (void*)bfs_predecessors_h, predecessors_index));

// expect bfs distances_h = (1 0 1 3 3 2 2147483647)

for (int i = 0; i<n; i++)  printf("Distance to vertex %d: %i\n",i, bfs_distances_h[i]); printf("\n");

// expect bfs predecessors = (1 -1 1 5 5 0 -1)

for (int i = 0; i<n; i++)  printf("Predecessor of vertex %d: %i\n",i, bfs_predecessors_h[i]); printf("\n");

free(vertex_dimT);

free(CSR_input);

check_status(nvgraphDestroyGraphDescr (handle, graph));

check_status(nvgraphDestroy (handle));

return 0;

}

nvGRAPH API参考分析(二)的更多相关文章

  1. nvGRAPH API参考分析(一)

    nvGRAPH API参考分析(一) 本文通过描述nvGRAPH库函数的输入/输出参数,数据类型和错误代码来指定其行为. 1.    返回值nvgraphStatus_t 除以下内容外,所有nvGRA ...

  2. PJSUA2开发文档--第十二章 PJSUA2 API 参考手册

    12 PJSUA2 API 参考手册 12.1 endpoint.hpp PJSUA2基本代理操作.  namespace pj PJSUA2 API在pj命名空间内. 12.1.1 class En ...

  3. Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI

    目录 引言 Search APIs Search API Search Request 可选参数 使用 SearchSourceBuilder 构建查询条件 指定排序 高亮请求 聚合请求 建议请求 R ...

  4. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  5. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  6. SQLite入门与分析(二)---设计与概念(续)

    SQLite入门与分析(二)---设计与概念(续)   写在前面:本节讨论事务,事务是DBMS最核心的技术之一.在计算机科学史上,有三位科学家因在数据库领域的成就而获ACM图灵奖,而其中之一Jim G ...

  7. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  8. 透过【百度地图API】分析双闭包问题

    原文:透过[百度地图API]分析双闭包问题 摘要: 有位API爱好者问到,昨天的教程里为什么不使用for循环?他使用for循环后,也发现代码无效.这是什么原因? ------------------- ...

  9. java微信开发API解析(二)-获取消息和回复消息

    java微信开发API解析(二)-获取消息和回复消息 说明 * 本演示样例依据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20 ...

随机推荐

  1. Windows核心编程 第十七章 -内存映射文件(下)

    17.3 使用内存映射文件 若要使用内存映射文件,必须执行下列操作步骤: 1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件. 2) 创建一个文件映射内核对象,告诉系统该 ...

  2. C#-WiFi共享

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. 前端不得不了解的TCP协议

    背景 早期的网络是基于OSI(开放式系统互联网,一般叫OSI参考模型)模型,该模型是由ISO国际标准组织制定的,包含了七层(应用层.表示层.会话层.传输层.网络层.数据链路层.物理层),即复杂又不实用 ...

  4. 电脑提示无法装入/加载SolidWorks DLL文件:sldshellutils如何解决

    电脑提示无法装入/加载SolidWorks DLL文件:sldshellutils如何解决 参考资料:http://www.xitongcheng.com/jiaocheng/dnrj_article ...

  5. opencv——感兴趣区域(ROI)的分析和选取[详细总结]

    引言 在利用OpenCV对图像进行处理时,通常会遇到一个情况,就是只需要对部分感兴趣区域进行处理.因此,如何选取感兴趣区域呢?(其实就是"抠图"). 在学习opencv的掩码运算后 ...

  6. 使用C#操作注册表

    这节讲一下使用C#操作注册表. 首先来了解一下,什么是注册表,注册表是Windows中特有的一个东西,百度百科中对其解释如下:Windows注册表(Registry)实质上是一个庞大的数据库,它存储着 ...

  7. 【Docker】5. 常用命令—镜像命令

    学习命令,官方文档千万别忘记了,不会的就到这里来查. 一.帮助命令 1.显示docker哪些命令 docker --help 另外,也可以查看具体命令的用法,比如我想知道命令docker images ...

  8. C++ primer plus读书笔记——第16章 string类和标准模板库

    第16章 string类和标准模板库 1. string容易被忽略的构造函数: string(size_type n, char c)长度为n,每个字母都为c string(const string ...

  9. Morgan Stanley Books List:经典金融书籍推荐

    一.经济学 1. 中华帝国的专制制度,佛朗索瓦.魁奈 2. 资本论(共3卷),马恩全集 3. 国家竞争优势,麦克尔.波特 4. Essentials of corporate analysis, by ...

  10. SSM框架整合(Spring+SpringMVC+Mybatis)

    第一步:创建maven项目并完善项目结构  第二步:相关配置 pom.xml 引入相关jar包 1 <properties> 2 <project.build.sourceEncod ...