热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

MySQLConnector/C++入门教程(上)

原文地址:dev.mysql.comtech-resourcesarticlesmysql-connector-cpp.html#trx翻译:DarkBull(www.darkbull.net)示例代码:MySqlDemo.7z译者注:该教程是一篇介绍如何使用C++操作MySQL的入门教程,内容简单易用。我对原文中的一些例子进行了修

原文地址:http://dev.mysql.com/tech-resources/articles/mysql-connector-cpp.html#trx 翻译: DarkBull(www.darkbull.net) 示例代码:MySqlDemo.7z 译者注:该教程是一篇介绍如何使用C++操作MySQL的入门教程,内容简单易用。我对原文中的一些例子进行了修

原文地址: http://dev.mysql.com/tech-resources/articles/mysql-connector-cpp.html#trx

翻译: DarkBull(www.darkbull.net)

示例代码:MySqlDemo.7z

译者注:该教程是一篇介绍如何使用C++操作MySQL的入门教程,内容简单易用。我对原文中的一些例子进行了修改,并新添加了部分例子,主要目标是更简单明了的向读者介绍如何操作MySQL数据库。本人也是MySQL的初学者,错误也在所难免,欢迎拍砖!

这篇教程将一步一步引导您如何去构建和安装MySql Connection/C++ Driver,同时提供几个简单的例子来演示如何连接MySQL数据库,如何向MySQL添加、获取数据。本教程关注如何在C++应用程序中操作MySQL,所以首先应该确定MySQL数据库服务已经开启并且在当前机器能够访问到。

本教程面向的读者是MySQL Connector/C++的初学者,如果您对C++语言或者MySQL数据库不是很了解,请参考其他的教程。

教程使用了下面所列的一些工具和技术,来构建、编译、运行例子程序(译者注:这是原文作者使用的环境。笔者使用的环境是:WinXP,MySQL5.1,VS2008, ):

  • Database MySQL Server 5.1.24-rc
  • C++ Driver MySQL Connector/C++ 1.0.5
  • MySQL Client Library MySQL Connector/C 6.0
  • Compiler Sun Studio 12 C++ compiler
  • Make CMake 2.6.3
  • Operating System OpenSolaris 2008.11 32-bit
  • CPU / ISA Intel Centrino / x86
  • Hardware Toshiba Tecra M2 Laptop

目录

MySQL C++ Driver的实现基于JDBC4.0规范

安装MySQL Connector/C++

运行时依赖

C++ IDE

为示例程序创建数据库与数据表

使用Connector/C++测试数据库连接

使用prepared Statements

使用事务

访问Result Set Metadata

访问Database Metadata

通过PreparedStatment对象访问参数元数据

捕获异常

调试/跟踪 MySQL Connector/C++

更多信息

MySQL C++ Driver的实现基于JDBC4.0规范

MySQL Connector/C++是由Sun Microsystems开发的MySQL连接器。它提供了基于OO的编程接口与数据库驱动来操作MySQL服务器。

与许多其他现存的C++接口实现不同,Connector/C++遵循了JDBC规范。也就是说,Connector/C++ Driver的API主要是基于Java语言的JDBC接口。JDBC是java语言与各种数据库连接的标准工业接口。Connector/C++实现了大部分JDBC4.0规范。如果C++程序的开发者很熟悉JDBC编程,将很快的入门。

MySQL Connector/C++实现了下面这些类:

  • Driver
  • Connection
  • Statement
  • PreparedStatement
  • ResultSet
  • Savepoint
  • DatabaseMetaData
  • ResultSetMetaData
  • ParameterMetaData
Connector/C++可用于连接MySQL5.1及其以后版本。

在MySQL Connector/C++发布之前,C++程序员可以使用MySQL C API或者MySQL++访问MySQL。前者是非标准、过程化的C API,后者是对MySQL C API的C++封装。

安装MySQL Connector/C++

此处略。(译者注:用户可以到MySQL的官网[http://dev.mysql.com/downloads/connector/cpp/1.0.html]去下载MySQL Connector/C++的安装程序,或者只下载dll,或者下载源代码自己编译。笔者在Window平台上使用MySQL,下载了mysql-connector-c++-noinstall-1.0.5-win32这个版本用于调试。)

运行时依赖

MySQL Connector/C++ Driver依赖MySQL的客户端库,在MySQL安装目录下的lib\opt\libmysql.dll。如果是通过安装程序来安装MySQL Connector/C++,libmysql会一并安装,如果从官网只下载了dll或源码,在使用时,程序必须链接到libmysql.dll。

C++ IDE

此处略。(译者注:原文作者使用NetBean作为C++的IED。笔者使用VS2008)

为示例程序创建数据库与数据表

(译者注:此节略掉许多不太重要的内容。)在MySQL中创建test数据库,使用下面语句创建数据表:City:

					Create Table: CREATE TABLE `City` ( `CityName` varchar(30) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=ascii 

然后向City表中添加一些数据。最后表的内容为:

mysql> SELECT * FROM City;

+--------------------+

| CityName |

+--------------------+

| Hyderabad, India |

| San Francisco, USA |

| Sydney, Australia |

+--------------------+

3 rows in set (0.17 sec)

使用Connector/C++测试数据库连接

下面的代码演示如何使用Connector/C++连接到MySQL服务器:

  • 连接到test数据库;
  • 执行一个查询获取City表中的数据,显示在控制台上; 
  • 使用Prepared Statements向City表插入数据;
  • 使用savepoints演示事务;
  • 获取结果集和数据库的元信息;

例子代码仅仅用于演示,不建议读者在实际开发中使用这种样式的代码。(译者注:例子代码很长,如果看不太明白,没关系,等阅读完全文之后再回过头来看)

				#include 
#include 
#include 
#include 
#include "mysql_driver.h"
#include "mysql_connection.h"
#include "cppconn/driver.h"
#include "cppconn/statement.h"
#include "cppconn/prepared_statement.h"
#include "cppconn/metadata.h"
#include "cppconn/exception.h"
#define DBHOST "tcp://127.0.0.1:3306"
#define USER "root"
#define PASSWORD "000000"
#define DATABASE "test"
#define NUMOFFSET 100
#define COLNAME 200
using namespace std;
using namespace sql;
#pragma comment(lib, "mysqlcppconn.lib")
void Demo();
int main(int argc, char *argv[])
{
	Demo();
	return 0;
}
/* 获取数据库信息 */
static void GetDBMetaData(Connection *dbcon) 
{
	if (dbcon->isClosed()) 
	{
		throw runtime_error("DatabaseMetaData FAILURE - database connection closed");
	}
	cout <<"\nDatabase Metadata" < dbcon_meta (dbcon->getMetaData());
	DatabaseMetaData *dbcon_meta = dbcon->getMetaData();
	cout <<"Database Product Name: " <getDatabaseProductName() <getDatabaseProductVersion() <getUserName() <getDriverName() <getDriverVersion() <isReadOnly() <supportsTransactions() <supportsDataManipulationTransactionsOnly() <supportsBatchUpdates() <supportsOuterJoins() <supportsMultipleTransactions() <supportsNamedParameters() <supportsStatementPooling() <supportsStoredProcedures() <supportsUnion() <getMaxConnections() <getMaxColumnsInTable() <getMaxColumnsInIndex() <getMaxRowSize() <<" bytes" < rs ( dbcon_meta->getSchemas());
	cout <<"\nTotal number of schemas = " <rowsCount() <next()) {
		cout <<"\t" <getString("TABLE_SCHEM") < rowsCount() == 0) 
	{
		throw runtime_error("ResultSetMetaData FAILURE - no records in the result set");
	}
	cout <<"ResultSet Metadata" < res_meta ( rs -> getMetaData() );
	ResultSetMetaData *res_meta = rs -> getMetaData();
	int numcols = res_meta -> getColumnCount();
	cout <<"\nNumber of columns in the result set = " < getColumnLabel (i+1);
		cout.width(20); 
		cout < getColumnTypeName (i+1);
		cout.width(20); 
		cout < getColumnDisplaySize (i+1) < getColumnLabel(1);
	cout <<"\" belongs to the Table: \"" < getTableName(1);
	cout <<"\" which belongs to the Schema: \"" < getSchemaName(1) <<"\"" <rowsCount() <<" row(s)." <next()) 
	{
		if (type == NUMOFFSET) 
		{
			cout < getString(colidx) < getString(colname) < connect(url, user, password);
		/* alternate syntax using auto_ptr to create the db connection */
		//auto_ptr  con (driver -> connect(url, user, password));
		/* turn off the autocommit */
		con -> setAutoCommit(0);
		cout <<"\nDatabase connection\'s autocommit mode = " < getAutoCommit() < setSchema(database);
		/* retrieve and display the database metadata */
		GetDBMetaData(con);
		/* create a statement object */
		stmt = con -> createStatement();
		cout <<"Executing the Query: \"SELECT * FROM City\" .." < executeQuery ("SELECT * FROM City");
		cout <<"Retrieving the result set .." < prepareStatement ("INSERT INTO City (CityName) VALUES (?)");
		cout <<"\tInserting \"London, UK\" into the table, City .." < setString (1, "London, UK");
		updatecount = prep_stmt -> executeUpdate();
		cout <<"\tCreating a save point \"SAVEPT1\" .." < setSavepoint ("SAVEPT1");
		cout <<"\tInserting \"Paris, France\" into the table, City .." < setString (1, "Paris, France");
		updatecount = prep_stmt -> executeUpdate();
		cout <<"\tRolling back until the last save point \"SAVEPT1\" .." < rollback (savept);
		con -> releaseSavepoint (savept);
		cout <<"\tCommitting outstanding updates to the database .." < commit();
		cout <<"\nQuerying the City table again .." < executeQuery ("SELECT * FROM City");
		/* retrieve the data from the result set and display on stdout */
		RetrieveDataAndPrint(res, COLNAME, 1, string ("CityName"));
		cout <<"Cleaning up the resources .." < close();
		delete con;
	} catch (SQLException &e) {
		cout <<"ERROR: " <

建立数据库连接
sql::Connection代表到数据库的连接,可以通过sql::Driver来创建。sql::mysql::get_mysql_driver_instance()方法用于获取sql::Driver,通过调用sql::Driver::connect方法来创建sql::Connection对象。(译者注:笔者使用的Connector/C++版本与作者使用的版本不一样,接口方面也有点细微的差别。这里根据笔者使用的最新版本mysql-connector-c++-noinstall-1.0.5-win32来说明。)

下面是get_mysql_driver_instance与connect这两个方法的签名:

					/* mysql_driver.h */
MySQL_Driver *sql::mysql::get_mysql_driver_instance()
/* mysql_driver.h */
sql::Connection * connect(const std::string& hostName, const std::string& userName, const std::string& password);
sql::Connection * connect(std::map & options);

Driver类重载了connect方法,一个接收数据库地址的url、用户名和密码的字符串,后一个接收一个map,map中以key/value的形式包含数据库地址、用户名与密码。使用TCP/IP连接到MySql服务器的url字符串的格式如下:"tcp://[hostname[:port]][/schemaname]"。例如:tcp://127.0.0.1:5555/some_scehma。hostname和端口号是可选的,如果省略,默认是127.0.0.1与3306。如果hostname为"localhost",会被自动转换为"127.0.0.1"。schemaname也是可选的,如果连接字符串中没有设置schema,需要在程序中通过Connection::setSchema方法手动设置。

在unix系统上,可以通过UNIX domain socket连接运行在本地的MySQL服务,连接字符串格式为:"unix://path/to/unix_socket_file",例如:unix:///tmp/mysql.sock.

在windows系统上,可以以命名管道的方式连接到运行在本地的MySQL数据库,连接字符串格式为:"pipe://path/to/the/pipe"。MySQL服务必须启动允许命名管道连接,可以在启动MySQL服务器的时候,通过--enable-named-pipe命令行选项来启动该功能。如果没有通过--socket=name选项设置命名管道的名称,系统默认使用MySQL。在windows上,管道的名称是区别大小写的。
下面的代码片断尝试连接到本地的MySQL服务器,通过3306端口,用户名为root,密码是000000,schema为test.

					sql::mysql::MySQL_Driver *driver = 0;
sql::Connection *cOnn= 0;
try 
{
	driver = sql::mysql::get_mysql_driver_instance();
	cOnn= driver->connect("tcp://localhost:3306/test", "root", "000000");
	cout <<"连接成功" <

也可以通过connection的第二个重载方法连接MySQL。ConnectPropertyVal是union类型,在connection.h中定义。

					sql::mysql::MySQL_Driver *driver = 0;
sql::Connection *cOnn= 0;
std::map connProperties; 
ConnectPropertyVal tmp; 
tmp.str.val = "tcp://127.0.0.1:3306/test"; 
connProperties[std::string("hostName")] = tmp; 
tmp.str.val = "root"; 
connProperties[std::string("userName")] = tmp; 
tmp.str.val = "000000"; 
connProperties[std::string("password")] = tmp; 
try 
{ 
	driver = sql::mysql::get_mysql_driver_instance();
	cOnn= driver -> connect(connProperties); 
	cout <<"连接成功" <

上面的连接字符串可以将协议与路径分开写(译者注:C++会把两个连在一起的字符串合并成一个字符串),如:mp.str.val = "unix://" "/tmp/mysql.sock"

当建立与服务器之间的连接后,通过Connection::setSessionVariable方法可以设置像sql_mode这样的选项。

C++细节注意点
像Connection这样的对象,必须在用完之后,显式的delete,例如:
				sql::Connection *cOnn= driver -> connect("tcp://127.0.0.1:3306", "root", "000000");
// do something
delete conn

使用使用auto_ptr来维护连接对象的清理, 如:

				use namespace std;
use namespace sql;
auto_ptr  con ( driver -> connect("tcp://127.0.0.1:3306", "root", "000000") );
获取Statement对象

Statement对象用于向MySQL服务器发送SQL语句。该对象可以通过调用Connection::createStatement方法获得。Statement向MySQL发送一个静态的SQL语句,然后从MySQL获取操作的结果,我们无法向它提供sql参数。如果要向它传递参数,可以使用PreparedStatemenet类。如果相同的SQL语句(只SQL参数不同)要被执行多次,建议使用PreparedStatement类。
Connection::createStatement的签名如下(关于Connection类所提供的方法列表,可以查看connection.h头文件):

					/* connection.h */ 
Statement* Connection::createStatement();

下面的的代码段通过调用Connection对象的createStatemenet来获取一个Statement对象:

					Connection *conn;  // Connection对象的引用
Statement *stat; 
Statement stat = conn -> createStatement(); 

执行SQL语句

在执行SQL语句之前应该通过Connection对象的setSchema方法设置相应的Schema(如果没有在数据库地址URL中指定schema)。

Statement::executeQuery用于执行一个Select语句,它返回ResultSet对象。Statement::executeUpdate方法主要用于执行INSERT, UPDATE, DELETE语句(executeUpdate可以执行所有的SQL语句,如DDL语句,像创建数据表。),该方法返回受影响记录的条数。

如果你不清楚要执行的是像select这样的查询语句还是像update/insert/delete这样的操作语句,可以使用execute方法。对于查询语句,execute()返回True,然后通过getResultSet方法获取查询的结果;对于操作语句,它返回False,通过getUpdateCount方法获取受影响记录的数量。

在一些特殊的情况下,单条SQL语句(如执行存储过程),可能会返回多个结果集 和/或 受影响的记录数量。如果你不想忽略这些结果,通过getResultSet或getUpdateCount方法第一个结果后,再通过getMoreResults()来获取其他的结果集。

下面是这些方法的签名,可以在statement.h头文件中查阅Statement的完整方法列表。

				/* connection.h */ 
void Connection::setSchema(const std::string& catalog); 
/* statement.h */ 
ResultSet* Statement::executeQuery (const std::string& sql); 
int Statement::executeUpdate (const std::string& sql); 
bool Statement::execute (const std::string& sql); 
ResultSet* Statement::getResultSet(); 
uint64_t Statement::getUpdateCount();

这些方法出错时都会抛出SQLException异常,所以在你的代码中应该使用try...catch语句块来捕获这些异常。

现在回顾上面那个完全的例子,你会发现获取City表的所有记录是如此的简单:

				Statement *stmt;
ResultSet *res;
res = stmt -> executeQuery ("SELECT * FROM City");

executeQuery方法返回ResultSet对象,它包含了查询的结果。在以下情况下,executeQuery会抛出SQLException异常:数据库在执行查询时出错;在一个关闭的Statement对象上调用executeQuery;给出的SQL语句返回的不是一个简单的结果集;

上面的代码可以用Statement::execute()重写:

				bool retvalue = stmt -> execute ("SELECT * FROM City");
if (retvalue) 
{
    res = stmt -> getResultSet();
} 
else 
{
    ...
}
execute()返回True表示操作的结果是一个ResultSet对象,否则结果是受影响记录的数量或没有结果。当返回True时,通过getResultSet方法获取结果集,在返回False的情况下调用getResultSet方法,将返回NULL。

当数据库在执行时发生错误或者在一个已关闭的Statement对象上执行execute与getResultSet方法,都会抛出SQLException异常。

如果要往数据库里添加一条新的记录,可以像下面的例子一样简单的调用executeUpdate方法:

				int updateCount = stmt -> executeUpdate ("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')");

如果executeUpdate执行的是像INSERT, UPDATE或DELETE这样的数据操作语句(DML),它返回受影响的记录的数量;如果执行的是数据定义语句(DDL),它返回0。在数据库操作失败,或者在一个已经关闭的Statement上调用该方法,或者给出的SQL语句是一个查询语句(会返回结果集),该方法会抛出SQLException异常。

下面的代码使用execute和getUpdateCount方法来生写上面的例子:

				int updateCount = 0;
bool retstatus = stat->execute("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')");
if (!retstatus) 
{
    updateCount = stat->getUpdateCount();
} 
else 
{
    ...
}
从ResultData中获取数据

上面的段落介绍了执行SQL查询的方法:executeQuery和execute,用于获取ResultSet对象。我们可以通过ResultSet访问查询的结果。每一个ResultSet都包含一个游标(cursor),它指向数据集中的当前记录行。ResultSet中排列的记录是有序的(译者注:只能按顺序一条一条获取,不能跳跃式获取)。(但)在同一行中,列值的访问却是随意的:可以通过列的位置或者名称。通过列的名称访问列值让代码更清晰,而通过位置访问列值则更高效。

列的名称通过SQL语句的AS子名设定,如果SQL语句中没有使用AS子名,列的名称默认为数据表中对应的列名。例如对于"SELECT CityName AS CN FROM City",CN就是结果集中列的名称。
在ResultSet中的数据,可以通过getXX系列方法来获取,例如:getString(), getInt(),"XX"取决于数据的类型。next()与previous()使游标移到结果集中的下一条或上一条记录。

Statement执行SQL语句返回ResultSet对象后,ResultSet就变成一个独立的对象,与原先的Statement再也没有联系,即使Statement对象关闭,重新执行其他sql语句,或者获取多个结果集中的下一个。ResultSet将一直有效,除非显式或隐式地将其关闭。
在撰写本文时,对于Statement对象,MySQL Connector/C++总是返回缓存结果,这些结果在客户端缓存。不管结果集数据量大小,MySQLConnector/C++ Driver总是获取所有的数据。希望以后的版本中,Statement对象能够返回缓存和非缓存的结果集。

下面是数据获取方法的签名,可以在resultset.h头文件中查看所有ResultSet类支持的方法。

					/* resultset.h */
size_t ResultSet::rowsCount() const;
void ResultSet::close();
bool ResultSet::next();
bool ResultSet::previous();
bool ResultSet::last();
bool ResultSet::first();
void ResultSet::afterLast();
void ResultSet::beforeFirst();
bool ResultSet::isAfterLast() const;
bool ResultSet::isBeforeFirst()const;
bool ResultSet::isClosed() const;
bool ResultSet::isNull(uint32_t columnIndex) const;
bool ResultSet::isNull(const std::string& columnLabel) const;
bool ResultSet::wasNull() const;
std::string ResultSet::getString(uint32_t columnIndex) const;
std::string ResultSet::getString(const std::string& columnLabel) const;
int32_t ResultSet::getInt(uint32_t columnIndex) const;
int32_t ResultSet::getInt(const std::string& columnLabel) const;
在下面的简单示例中,查询语句"SELECT * FROM City"返回的ResultSet中只包含一列:CityName,数据类型为String,对应MySQL中的VARCHAR类型。这个例子通过next方法循环从结果集中获取CityName值,并显示在控制台上:

				while (res -> next())
{
    cout < getString("CityName") <

也可以通过位置来获取列值(位置从1开始而非从0开始),下面的代码产生相同的结果:

				while (res -> next()) 
{
        cout < getString(1) <

如果数据库中该字段的值为NULL,getString将返回一个空的字符串。Result::isNull用于判断指定列在数据库中的值是否为NULL。Result::wasNULL()用于判断最近读取的列的值是否为空。

下面的例子演示了通过cursor(游标)倒序读取结果集中的数据:

				/* Move the cursor to the end of the ResultSet object, just after the last row */
res -> afterLast();
if (!res -> isAfterLast()) 
{
    throw runtime_error("Error: Cursor position should be at the end of the result set after the last row.");
}
/* fetch the data : retrieve all the rows in the result set */
while (res -> previous()) 
{
    cout <getString("CityName") <

getString方法在以下情况下会抛出SQLException异常:指定列名或位置不存在;数据库在执行操作时失败;在一个关闭的cursor上执行调用该方法。

未完待续!

推荐阅读
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文是一位90后程序员分享的职业发展经验,从年薪3w到30w的薪资增长过程。文章回顾了自己的青春时光,包括与朋友一起玩DOTA的回忆,并附上了一段纪念DOTA青春的视频链接。作者还提到了一些与程序员相关的名词和团队,如Pis、蛛丝马迹、B神、LGD、EHOME等。通过分享自己的经验,作者希望能够给其他程序员提供一些职业发展的思路和启示。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
author-avatar
jystmj-2009
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有