通过使用脚本语言和编译型系统语言(例如 C),将数据库集成到Linux应用就可能相当容易。可免费获得的MySQL(在GNU Public License下发行)数据库提供了一系列复杂的SQL功能,并易于集成到应用中。MySQL是快速、多线程的,并支持ANSI和ODBC SQL标准。加上第三方软件,MySQL就支持用于事务处理应用的事务安全的表。
MySQL被设计和构造成客户机/服务器。服务器mysqld可以在能从因特网访问到的任何机器上运行(最好与Web服务器在同一台或最接近的一台机器上,以确保合理的响应时间)。MySQL客户机使用请求来与MySQL服务器联系,修改或查询服务器所拥有的数据库。在支持数据库的Web应用程序中,数据库客户机是Web服务器或由Web服务器产生的CGI脚本。这些客户机可以用高级脚本语言或低级系统语言编写,只要存在这种语言的数据库API即可。在Linux中,大多数脚本语言是以C 实现的,因为存在MySQL C API,所以要将MySQL支持添加到任何现有的脚本语言或工具应该很容易。绝大部分脚本语言已经完成了这一步。
MySQL API
MySQL API可用于各种语言,包括几乎所有编写网站后端所实际使用的语言。 使用这些API,我们可以构建由Web服务器控制的 MySQL客户机。
要构建集成数据库访问的网站,需要编写CGI脚本来根据数据库状态生成动态结果。Web服务器启动CGI脚本,然后将适当格式化的HTML输出到它们的标准输出流中。Web服务器捕捉到HTML后将它发送回客户机,如同请求是对静态HTML页面进行的那样。 在生成 HTML 的过程中,脚本可以修改数据库,也可以查询并将结果合并到它们的输出中。
作为简单解释上述过程的一个示例,下面的代码(以C和Tcl编写)查询一个包含某公司供销售的产品清单的数据库。 这绝没有使用两种语言MySQL API的所有特性,但提供了快速、简易扩展的示例,可以对数据库内容执行任何SQL命令。 在该例中,脚本显示了低于特定价格的所有产品。在实践中,用户可能在Web浏览器中输入该价格,然后将它发给服务器。 我们省去了从环境变量中进行读取来确定 HTML 表单值的细节,因为它与不支持数据库的 CGI 脚本中执行的情况没有什么差别。 为清晰起见,我们假设事先设置了特定一些参数(例如要查询的价格)。
[pre]#This code prints out all products in the database# that are below a specified price (assumed to have been determined# beforehand, and stored in the variable targetPrice)# The output is in HTML table format, appropriate for CGI output#load the SQL shared object library. the Tcl interpreter could also#have been compiled with the library, making this line unnecessaryload /home/aroetter/tcl-sql/sql.so#these are well defined beforehand, or they could#be passed into the scriptset DBNAME "clientWebSite";set TBLNAME "products";set DBHOST "backend.company.com"set DBUSER "mysqluser"set DBPASSWD "abigsecret"set targetPrice 200;#connect to the databaseset handle [sql connect $DBHOST $DBUSER $DBPASSWD]sql selectdb $handle $DBNAME ;# get test database#run a query using the specified sql codesql query $handle "select * from $TBLNAME where price <= $targetPrice"#print out html table headerputs "<table border=4>"puts "<th>Product Id <th width=200>Description <th>Price (\$)"#output table rows - each fetchrow retrieves one result#from the sql querywhile {[set row [sql fetchrow $handle]] != ""} { set prodid [lindex $row 0] set descrip [lindex $row 1] set price [lindex $row 2] puts "<tr><td>$prodid <td align=center>$descrip <td>$price"}puts "</table>"#empty the query result buffer - should already be empty in this casesql endquery $handle#close the db connection - in practice this same connection#is used for multiple queriessql disconnect $handle[/pre]
下面的代码是使用正式MySQL C++ API MySQL++以C++编写的等价脚本。该版本的优势在于它是编译型的,因此比解释语言更快。经常用在特定站点的数据库代码应该以C或C++编写,然后由脚本或直接由Web服务器访问,以改进整体运行时间。
C++示例
[pre]#include #include #include const char *DBNAME = "clientWebSite";const char *DBTABLE = "products";const char *DBHOST = "backend.company.com";const char *DBUSER = "mysqluser";const char *DBPASSWD = "abigsecret":int main() { try { //open the database connection and query Connection con(DBNAME, DBHOST, DBUSER, DBPASSWD); Query query = con.query(); //write valid sql code to the query object query << "select * from " << DBTABLE; //run the query and store the results Result res = query.store(); //write out the html table header cout << "<table border=4>\n"; cout << "<th>Product Id <th width=200>Description" << "<th>Price ($)" << endl; Result::iterator curResult; Row row; //iterate over each result and put it into an html table for (curResult = res.begin(); curResult != res.end(); curResult++) { row = *curResult; cout << "<tr><td align=center>" << row[0] << "<td>" << row[1] << "<td>" << row[2] << endl; } cout << "</table>" << endl; } catch (BadQuery er) { // handle a bad query (usually caused by a sql syntax error) cerr << "Error: " << er.error << endl; return -1; } catch (BadConversion er) {//handle conversion errors out of the database as well cerr << "Error: Can't convert \"" << er.data << "\" to a \"" << er.type_name << "\"." << endl; return -1; } return 0;}[/pre]
在实际中,最安全的方法是在 Web 服务器所在的机器上运行数据库服务器,并让由Web服务器产生的CGI脚本通过UNIX(本地)套接字与MySQL服务器进行通信。该设置可以让数据库管理员禁用所有与MySQL服务器的远程连接。如果Web和数据库服务器必须位于不同的机器上,加密它们之间的所有通信,或者将两台机器通过其自己专用的、物理上隔离的网络连接。只创建一个由Web服务器使用的用户帐户(除 root 用户外)以登录到数据库服务器。