GridView使用学习总结

时间:2022年12月21日

/

来源:狗蛋

/

编辑:本站小编

收藏本文

下载本文

下面就是小编给大家整理的GridView使用学习总结,本文共11篇,希望您能喜欢!本文原稿由网友“狗蛋”提供。

篇1:GridView使用学习总结

关于GridView使用学习总结

由于Asp.Net视频比较旧,涉及到的数据绑定控件DataGrid在VS中已经没有了,取而代之的是GridView。开始觉得视频中的例子没法实现了,其实不然,DataGrid里面的功能GridView里一样都不少,只是形式变化了一下,仔细研究一下发现它们是换汤不换药啊。

(一)DataKeyName属性

(1)DataKeyNames一般都是用来对当前行做唯一标示的,所以一般为数据库的ID。

(2)GridView.DataKeys[e.RowIndex],e.RowIndex是获取事件对应的行,GridView.DataKeys[e.RowIndex]就是获取对应行的唯一标示也就是DataKeyNames所指定列的值。

(3)DataList和Repeater是没有的该属性的。

在代码中这样使用:(定义的'该函数在下面都需要调用)

/// 实现数据绑定功能 ///

private void BindToDataGird { SqlConnection con = DB.CreateCon(); SqlDataAdapter sda = new SqlDataAdapter(); sda.SelectCommand = new SqlCommand(“select employeeID,FirstName,LastName,Title,BirthDate from employees ”, con); DataSet ds = new DataSet(); sda.Fill(ds, “emp”); //将查询到的数据添加到DataSet中。 this.GridView1.DataKeyNames =new string[]{ “employeeID”}; //DataKeyNames的使用 this.GridView1.DataSource = ds.Tables[“emp”]; this.DataBind(); }

如何取值?

DataKey key = GridView1.DataKeys[e.RowIndex];//其中e为GridViewDelete(或者Edit)EventArgs e string empID = key[0].ToString();

(二)分页

由于GridView中封装了分页的功能。这里实现起来很容易。先需要设置属性:AllowPaging/PageSize/PageSetting。然后编写事件代码:

protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.GridView1.PageIndex = e.NewPageIndex; this.BindToDataGird(); }

(三)排序

首先设置AllowSorting属性为true.事件代码:

protected void GridView1_Sorting(object sender, GridViewSortEventArgs e) { if (ViewState[“order”] == null) //使用ViewState设置双向排序。 { ViewState[“order”] = “ASC”; } else { if (ViewState[“order”].ToString() == “ASC”) { ViewState[“order”] = “DESC”; } else { ViewState[“order”] = “ASC”; } } //数据绑定显示 SqlConnection con = DB.CreateCon(); SqlDataAdapter sda = new SqlDataAdapter(); sda.SelectCommand = new SqlCommand(“select employeeID,FirstName,LastName,Title,BirthDate from employees ”, con); DataSet ds = new DataSet(); sda.Fill(ds, “emp”); ds.Tables[“emp”].DefaultView.Sort = e.SortExpression + “ ” + ViewState[“order”].ToString(); //设置排序 this.GridView1.DataSource = ds.Tables[“emp”].DefaultView; //将表的默认视图作为数据源。 this.DataBind(); }

(四)删除

这里需要注意一点:就是获取某一行的主键值。

protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e) { DataKey key = GridView1.DataKeys[e.RowIndex]; string empID = key[0].ToString(); SqlConnection con = DB.CreateCon(); SqlCommand cmd = new SqlCommand(“ from employees where employeeID= +empID+” , con); con.Open(); cmd.ExecuteNonQuery(); this.BindToDataGird(); }

(五)编辑(更新和取消)

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e) { this.GridView1.EditIndex = e.NewEditIndex; this.BindToDataGird(); } protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e) { this.GridView1.EditIndex = -1; //设置索引值为负取消编辑。 this.BindToDataGird(); } protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e) { DataKey key = GridView1.DataKeys[e.RowIndex]; string empID = key[0].ToString(); string lastName=((TextBox)(GridView1.Rows [e.RowIndex ] .Cells [2].Controls [0])).Text ; //将GridView中某列中控件强制转换为TextBox,然后取出它的值。 Response.Write(empID +“&” + lastName ); //用于测试。 this.GridView1.EditIndex = -1; this.BindToDataGird(); }

篇2:新教材使用总结

新教材使用总结

我们备课组的几位老师经过了差不多两年的新课改实验,在实验的过程中真切的感受了新课改的主旨和精神,理解了并能够按照新大纲和新教材的精神来指导自己的日常教学,初步形成了自己的教学风格。尤其是新教材进课堂后,如何用好它,我们下了一番苦功夫去讨论、适应。经过摸索,在教材的使用方面,我们慢慢地积累了一些经验,现总结如下:

一、以“要让学生成为学习的主体”的精神来指导教材的使用。

新教材的使用,是为了配合新课标的实施而改的。所以在使用新教材时,首先要明白和牢牢记住这样的原则。在平时的教学中,我们做到了转变观念,解放思想,明确课改的目的意义,能主动投入到课改中去,主动想办法解决课改中出现的问题当然也包括有关教材使用上的问题。在思想观念上,我们放弃以前陈旧落后的思想和方法,尽快适应了新的形势。无可否认,新教材在注重知识性与人文性方面,有其显著的优点,但是教材虽好,教好学生却不容易!所以我们认为说一千,道一万,最重要的还是要让学生成为学习的主体,即学习的主人。为了让学生成为学习的主体,我们在教学中强调师生应在平等对话的过程中进行。主动为学生创设良好的自主学习情境,激发学生的学习兴趣,注重培养学生自主学习的意识和习惯,尊重学生的个体差异,引导和鼓励学生选择适合自己的学习方式。我们教师只是作为学习活动的组织者和引导者。如以语文阅读教学为例,以前的教学,我们多是采用以教师的分析及教学参考书作为教学主要依据的教学方法。但阅读教学是学生、教师、文本之间对话的过程,更是学生的个性化行为,是学生个性化体验的过程。所以,在教学中,我们非常珍惜每个学生对阅读文本的独特体验。指导学生从阅读中体会文章语言文字运用的精妙之处,从阅读中领悟作者的思想感情,从阅读中感受自然和社会生活的情趣。通过这样使文本所表达的思想,所运用的语言逐渐内化,从而在语言实践的过程中提高学生的人文素养及语文素养。学生阅读文本的过程中,我们注重扮演“引导者”的角色,在引导学生进入作者所描述的世界,指导学生对文本进行探究,拓展学生的思维和想象空间。

二、用新教材培养学生良好的读书学习习惯。

新教材的.变化较大,课后练习少了,题型也简单了。但是我们觉得教学并没有因此而轻松。我们认为新教材的根本目的是使学生养成良好的读书学习习惯。因此,在使用教材时一直强调做到这一点,多引导学生养成良好的学习习惯。虽然新教材的变化减轻了学生负担,但我们的教学要求没有降低甚至是提高了。在教学过程中,我们做到了加强研讨和交流,力争做到新教材有新教法。

三、使用新教材的几个注意。

在平时的教学中,我们总结出几点注意是:

一、使用新教材要注意深入并充分地了解学生。新教材关注学生的学习兴趣和生活经验,并主张在这一基础上教学。这就要求教师转变观念,改革教学模式。深入并充分地了解自己的学生,探明学生现在的智力基础、生活经验、个性差异等等,从学生的实际出发,引导学生主动积极地学习。

二、使用新教材要注意别被教材束缚住。教材的价值在于能作用于学生充分发展,在于能有效地激活学生积极主动地学习。因此不能为了教教材而教教材,而是以教材为重要的而不是唯一的课程资源,要用教材教,但不是教教材。在用的过程中为学生创设活动、提供机会,促其情感愉悦、态度主动,促其获得方法、提高技能。

三、利用新教材创造学习资源。再好的教材也会有局限性,也会有不适应性。我们要做教材的主人,而不是教材的奴隶。通过我们去再创造、去内化、去升华,能够创造出许多相关的教学资源,全面提高学生的素质。

篇3:SQLITE3 使用总结

前序:

这里要注明,我是一个跨平台专注者,并不喜欢只用 windows平台。我以前的工作就是为 unix平台写代码。下面我所写的东西,虽然没有验证,但是我已尽量不使用任何 windows 的东西,只使用标准 C 或标准C++。但是,我没有尝试过在别的系统、别的编译器下编译,因此下面的叙述如果不正确,则留待以后修改。

下面我的代码仍然用 VC 编写,因为我觉得VC是一个很不错的IDE,可以加快代码编写速度(例如配合 Vassist )。下面我所说的编译环境,是VC。如果读者觉得自己习惯于 unix 下用 vi 编写代码速度较快,可以不用管我的说明,只需要符合自己习惯即可,因为我用的是标准 C 或 C++ 。不会给任何人带来不便。

一、版本

从 www.sqlite.org 网站可下载到最新的 sqlite 代码和编译版本。我写此文章时,最新代码是 3.3.17 版本。

很久没有去下载 sqlite 新代码,因此也不知道 sqlite 变化这么大。以前很多文件,现在全部合并成一个 sqlite3.c 文件。如果单独用此文件,是挺好的,省去拷贝一堆文件还担心有没有遗漏。但是也带来一个问题:此文件太大,快接近7万行代码,VC开它整个机器都慢下来了。如果不需要改它代码,也就不需要打开 sqlite3.c 文件,机器不会慢。但是,下面我要写通过修改 sqlite 代码完成加密功能,那时候就比较痛苦了。如果个人水平较高,建议用些简单的编辑器来编辑,例如UltraEdit 或 Notepad 。速度会快很多。

二、基本编译

这个不想多说了,在 VC 里新建 dos 控制台空白工程,把 sqlite3.c 和 sqlite3.h 添加到工程,再新建一个 main.cpp文件。在里面写:

extern “C”{#include “./sqlite3.h”};int main( int , char** ){return 0;}

为什么要 extern “C” ?如果问这个问题,我不想说太多,这是C++的基础。要在 C++ 里使用一段 C 的代码,必须要用 extern “C” 括起来。C++跟 C虽然语法上有重叠,但是它们是两个不同的东西,内存里的布局是完全不同的,在C++编译器里不用extern “C”括起C代码,会导致编译器不知道该如何为 C 代码描述内存布局。

可能在 sqlite3.c 里人家已经把整段代码都 extern “C” 括起来了,但是你遇到一个 .c 文件就自觉的再括一次,也没什么不好。

基本工程就这样建立起来了。编译,可以通过。但是有一堆的 warning。可以不管它。

三、SQLITE操作入门

sqlite提供的是一些C函数接口,你可以用这些函数操作数据库。通过使用这些接口,传递一些标准 sql 语句(以 char * 类型)给 sqlite 函数,sqlite 就会为你操作数据库。

sqlite 跟MS的access一样是文件型数据库,就是说,一个数据库就是一个文件,此数据库里可以建立很多的表,可以建立索引、触发器等等,但是,它实际上得到的就是一个文件。备份这个文件就备份了整个数据库。

sqlite 不需要任何数据库引擎,这意味着如果你需要 sqlite 来保存一些用户数据,甚至都不需要安装数据库(如果你做个小软件还要求人家必须装了sqlserver 才能运行,那也太黑心了)。

下面开始介绍数据库基本操作。

1 基本流程(1)关键数据结构

sqlite 里最常用到的是 sqlite3 * 类型。从数据库打开开始,sqlite就要为这个类型准备好内存,直到数据库关闭,整个过程都需要用到这个类型。当数据库打开时开始,这个类型的变量就代表了你要操作的数据库。下面再详细介绍。

(2)打开数据库

int sqlite3_open( 文件名, sqlite3 ** );

用这个函数开始数据库操作。

需要传入两个参数,一是数据库文件名,比如:c://DongChunGuang_Database.db。

文件名不需要一定存在,如果此文件不存在,sqlite 会自动建立它。如果它存在,就尝试把它当数据库文件来打开。

sqlite3 ** 参数即前面提到的关键数据结构。这个结构底层细节如何,你不要关它。

函数返回值表示操作是否正确,如果是 SQLITE_OK 则表示操作正常。相关的返回值sqlite定义了一些宏。具体这些宏的含义可以参考 sqlite3.h 文件。里面有详细定义(顺便说一下,sqlite3 的代码注释率自称是非常高的,实际上也的确很高。只要你会看英文,sqlite 可以让你学到不少东西)。

下面介绍关闭数据库后,再给一段参考代码。

(3)关闭数据库

int sqlite3_close(sqlite3 *);

前面如果用 sqlite3_open 开启了一个数据库,结尾时不要忘了用这个函数关闭数据库。

下面给段简单的代码:

extern “C”{#include “./sqlite3.h”};int main( int , char** ){ sqlite3 * db = NULL; //声明sqlite关键结构指针 int result;//打开数据库//需要传入 db 这个指针的指针,因为 sqlite3_open 函数要为这个指针分配内存,还要让db指针指向这个内存区 result = sqlite3_open( “c://Dcg_database.db”, &db ); if( result != SQLITE_OK ) { //数据库打开失败return -1;}//数据库操作代码//…//数据库打开成功//关闭数据库sqlite3_close( db );return 0;}

这就是一次数据库操作过程。

2 SQL语句操作

本节介绍如何用sqlite 执行标准 sql 语法。

(1)执行sql语句

int sqlite3_exec(sqlite3*, const char *sql, sqlite3_callback, void *, char **errmsg );

这就是执行一条 sql 语句的函数。

第1个参数不再说了,是前面open函数得到的指针。说了是关键数据结构。

第2个参数const char *sql 是一条 sql 语句,以/0结尾。

第3个参数sqlite3_callback 是回调,当这条语句执行之后,sqlite3会去调用你提供的这个函数。(什么是回调函数,自己找别的资料学习)

第4个参数void * 是你所提供的指针,你可以传递任何一个指针参数到这里,这个参数最终会传到回调函数里面,如果不需要传递指针给回调函数,可以填NULL。等下我们再看回调函数的写法,以及这个参数的使用。

第5个参数char ** errmsg 是错误信息。注意是指针的指针。sqlite3里面有很多固定的错误信息。执行 sqlite3_exec 之后,执行失败时可以查阅这个指针(直接 printf(“%s/n”,errmsg))得到一串字符串信息,这串信息告诉你错在什么地方。sqlite3_exec函数通过修改你传入的指针的指针,把你提供的指针指向错误提示信息,这样sqlite3_exec函数外面就可以通过这个 char*得到具体错误提示。

说明:通常,sqlite3_callback 和它后面的 void * 这两个位置都可以填 NULL。填NULL表示你不需要回调。比如你做insert 操作,做 delete 操作,就没有必要使用回调。而当你做 select 时,就要使用回调,因为 sqlite3 把数据查出来,得通过回调告诉你查出了什么数据。

(2)exec 的回调

typedef int (*sqlite3_callback)(void*,int,char**, char**);

你的回调函数必须定义成上面这个函数的类型。下面给个简单的例子:

//sqlite3的回调函数 // sqlite 每查到一条记录,就调用一次这个回调int LoadMyInfo( void * para, int n_column, char ** column_value, char ** column_name ){ //para是你在 sqlite3_exec 里传入的 void * 参数 //通过para参数,你可以传入一些特殊的指针(比如类指针、结构指针),然后在这里面强制转换成对应的类型(这里面是void*类型,必须强制转换成你的类型才可用)。然后操作这些数据 //n_column是这一条记录有多少个字段 (即这条记录有多少列) // char ** column_value 是个关键值,查出来的数据都保存在这里,它实际上是个1维数组(不要以为是2维数组),每一个元素都是一个 char * 值,是一个字段内容(用字符串来表示,以/0结尾) //char ** column_name 跟 column_value是对应的,表示这个字段的字段名称 //这里,我不使用 para 参数。忽略它的存在. int i;printf( “记录包含 %d 个字段/n”, n_column );for( i = 0 ; i < n_column; i ++ ){ printf( “字段名:%s ß>字段值:%s/n”, column_name[i], column_value[i] );}printf( “------------------/n“ ); return 0;}int main( int , char ** ){ sqlite3 * db; int result; char * errmsg = NULL; result = sqlite3_open( “c://Dcg_database.db”, &db ); if( result != SQLITE_OK ) { //数据库打开失败return -1;}//数据库操作代码//创建一个测试表,表名叫 MyTable_1,有2个字段: ID 和 name。其中ID是一个自动增加的类型,以后insert时可以不去指定这个字段,它会自己从0开始增加result = sqlite3_exec( db, “create table MyTable_1( ID integer primary key autoincrement, name nvarchar(32) )”, NULL, NULL, errmsg );if(result != SQLITE_OK ){ printf( “创建表失败,错误码:%d,错误原因:%s/n”, result, errmsg );}//插入一些记录result = sqlite3_exec( db, “insert into MyTable_1( name ) values ( ‘走路‘ )”, 0, 0, errmsg );if(result != SQLITE_OK ){ printf( “插入记录失败,错误码:%d,错误原因:%s/n”, result, errmsg );}result = sqlite3_exec( db, “insert into MyTable_1( name ) values ( ‘骑单车‘ )”, 0, 0, errmsg );if(result != SQLITE_OK ){ printf( “插入记录失败,错误码:%d,错误原因:%s/n”, result, errmsg );}result = sqlite3_exec( db, “insert into MyTable_1( name ) values ( ‘坐汽车‘ )”, 0, 0, errmsg );if(result != SQLITE_OK ){ printf( “插入记录失败,错误码:%d,错误原因:%s/n”, result, errmsg );}//开始查询数据库result = sqlite3_exec( db, “select * from MyTable_1”, LoadMyInfo, NULL, errmsg );//关闭数据库sqlite3_close( db );return 0;}

通过上面的例子,应该可以知道如何打开一个数据库,如何做数据库基本操作。

有这些知识,基本上可以应付很多数据库操作了。

(3)不使用回调查询数据库

上面介绍的 sqlite3_exec 是使用回调来执行 select 操作。还有一个方法可以直接查询而不需要回调。但是,我个人感觉还是回调好,因为代码可以更加整齐,只不过用回调很麻烦,你得声明一个函数,如果这个函数是类成员函数,你还不得不把它声明成 static 的(要问为什么?这又是C++基础了。C++成员函数实际上隐藏了一个参数:this,C++调用类的成员函数的时候,隐含把类指针当成函数的第一个参数传递进去。结果,这造成跟前面说的 sqlite 回调函数的参数不相符。只有当把成员函数声明成 static 时,它才没有多余的隐含的this参数)。

虽然回调显得代码整齐,但有时候你还是想要非回调的 select 查询。这可以通过 sqlite3_get_table 函数做到。

int sqlite3_get_table(sqlite3*, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg );

第1个参数不再多说,看前面的例子。

第2个参数是 sql 语句,跟 sqlite3_exec 里的 sql 是一样的。是一个很普通的以/0结尾的char *字符串。

第3个参数是查询结果,它依然一维数组(不要以为是二维数组,更不要以为是三维数组)。它内存布局是:第一行是字段名称,后面是紧接着是每个字段的值。下面用例子来说事。

第4个参数是查询出多少条记录(即查出多少行)。

第5个参数是多少个字段(多少列)。

第6个参数是错误信息,跟前面一样,这里不多说了。

下面给个简单例子:

int main( int , char ** ){ sqlite3 * db; int result; char * errmsg = NULL; char **dbResult; //是 char ** 类型,两个*号 int nRow, nColumn; int i , j; int index; result = sqlite3_open( “c://Dcg_database.db”, &db ); if( result != SQLITE_OK ) { //数据库打开失败 return -1; } //数据库操作代码 //假设前面已经创建了 MyTable_1 表 //开始查询,传入的 dbResult 已经是 char **,这里又加了一个 & 取地址符,传递进去的就成了 char *** result = sqlite3_get_table( db, “select * from MyTable_1”, &dbResult, &nRow, &nColumn, &errmsg ); if( SQLITE_OK == result ) { //查询成功 index = nColumn; //前面说过 dbResult 前面第一行数据是字段名称,从 nColumn 索引开始才是真正的数据 printf( “查到%d条记录/n”, nRow ); for( i = 0; i < nRow ; i++ ) { printf( “第 %d 条记录/n”, i+1 ); for( j = 0 ; j < nColumn; j++ ) { printf( “字段名:%s ß>字段值:%s/n”, dbResult[j], dbResult [index] ); ++index; // dbResult 的字段值是连续的,从第0索引到第 nColumn - 1索引都是字段名称,从第 nColumn 索引开始,后面都是字段值,它把一个二维的表(传统的行列表示法)用一个扁平的形式来表示 } printf( “-------/n” ); } } //到这里,不论数据库查询是否成功,都释放 char** 查询结果,使用 sqlite 提供的功能来释放 sqlite3_free_table( dbResult ); //关闭数据库 sqlite3_close( db ); return 0;}

到这个例子为止,sqlite3 的常用用法都介绍完了。

用以上的方法,再配上 sql 语句,完全可以应付绝大多数数据库需求。

但有一种情况,用上面方法是无法实现的:需要insert、select 二进制。当需要处理二进制数据时,上面的方法就没办法做到。下面这一节说明如何插入二进制数据

3 操作二进制

sqlite 操作二进制数据需要用一个辅助的数据类型:sqlite3_stmt * 。

这个数据类型记录了一个“sql语句”。为什么我把 “sql语句” 用双引号引起来?因为你可以把 sqlite3_stmt * 所表示的内容看成是 sql语句,但是实际上它不是我们所熟知的sql语句。它是一个已经把sql语句解析了的、用sqlite自己标记记录的内部数据结构。

正因为这个结构已经被解析了,所以你可以往这个语句里插入二进制数据。当然,把二进制数据插到 sqlite3_stmt 结构里可不能直接 memcpy ,也不能像 std::string 那样用 + 号。必须用 sqlite 提供的函数来插入。

(1)写入二进制

下面说写二进制的步骤。

要插入二进制,前提是这个表的字段的类型是 blob 类型。我假设有这么一张表:

create table Tbl_2( ID integer, file_content blob )

首先声明

sqlite3_stmt * stat;

然后,把一个 sql 语句解析到 stat 结构里去:

sqlite3_prepare( db, “insert into Tbl_2( ID, file_content) values( 10, ? )”, -1, &stat, 0 );

上面的函数完成 sql 语句的解析。第一个参数跟前面一样,是个 sqlite3 * 类型变量,第二个参数是一个 sql 语句。

这个 sql 语句特别之处在于 values 里面有个 ? 号。在sqlite3_prepare函数里,?号表示一个未定的值,它的值等下才插入。

第三个参数我写的是-1,这个参数含义是前面 sql 语句的长度。如果小于0,sqlite会自动计算它的长度(把sql语句当成以/0结尾的字符串)。

第四个参数是 sqlite3_stmt 的指针的指针。解析以后的sql语句就放在这个结构里。

第五个参数我也不知道是干什么的。为0就可以了。

如果这个函数执行成功(返回值是 SQLITE_OK 且 stat 不为NULL ),那么下面就可以开始插入二进制数据。

sqlite3_bind_blob( stat, 1, pdata, (int)(length_of_data_in_bytes), NULL ); // pdata为数据缓冲区,length_of_data_in_bytes为数据大小,以字节为单位

这个函数一共有5个参数。

第1个参数:是前面prepare得到的 sqlite3_stmt * 类型变量。

第2个参数:?号的索引。前面prepare的sql语句里有一个?号,假如有多个?号怎么插入?方法就是改变 bind_blob 函数第2个参数。这个参数我写1,表示这里插入的值要替换 stat 的第一个?号(这里的索引从1开始计数,而非从0开始)。如果你有多个?号,就写多个 bind_blob 语句,并改变它们的第2个参数就替换到不同的?号。如果有?号没有替换,sqlite为它取值null。

第3个参数:二进制数据起始指针。

第4个参数:二进制数据的长度,以字节为单位。

第5个参数:是个析够回调函数,告诉sqlite当把数据处理完后调用此函数来析够你的数据。这个参数我还没有使用过,因此理解也不深刻。但是一般都填NULL,需要释放的内存自己用代码来释放。

bind完了之后,二进制数据就进入了你的“sql语句”里了。你现在可以把它保存到数据库里:

int result = sqlite3_step( stat );

通过这个语句,stat 表示的sql语句就被写到了数据库里。

最后,要把 sqlite3_stmt 结构给释放:

sqlite3_finalize( stat ); //把刚才分配的内容析构掉

(2)读出二进制

下面说读二进制的步骤。

跟前面一样,先声明 sqlite3_stmt * 类型变量:

sqlite3_stmt * stat;

然后,把一个 sql 语句解析到 stat 结构里去:

sqlite3_prepare( db, “select * from Tbl_2”, -1, &stat, 0 );

当 prepare 成功之后(返回值是 SQLITE_OK ),开始查询数据。

int result = sqlite3_step( stat );

这一句的返回值是SQLITE_ROW 时表示成功(不是 SQLITE_OK )。

你可以循环执行sqlite3_step 函数,一次step查询出一条记录。直到返回值不为 SQLITE_ROW 时表示查询结束。

然后开始获取第一个字段:ID 的值。ID是个整数,用下面这个语句获取它的值:

int id = sqlite3_column_int( stat, 0 ); //第2个参数表示获取第几个字段内容,从0开始计算,因为我的表的ID字段是第一个字段,因此这里我填0

下面开始获取 file_content 的值,因为 file_content 是二进制,因此我需要得到它的指针,还有它的长度:

const void * pFileContent = sqlite3_column_blob( stat, 1 );int len = sqlite3_column_bytes( stat, 1 );

这样就得到了二进制的值。

把 pFileContent 的内容保存出来之后,不要忘了释放 sqlite3_stmt 结构:

sqlite3_finalize( stat ); //把刚才分配的内容析构掉

(3)重复使用 sqlite3_stmt 结构

如果你需要重复使用 sqlite3_prepare 解析好的 sqlite3_stmt 结构,需要用函数: sqlite3_reset。

result = sqlite3_reset(stat);

这样, stat 结构又成为 sqlite3_prepare 完成时的状态,你可以重新为它 bind 内容。

4 事务处理

sqlite 是支持事务处理的。如果你知道你要同步删除很多数据,不仿把它们做成一个统一的事务。

通常一次 sqlite3_exec 就是一次事务,如果你要删除1万条数据,sqlite就做了1万次:开始新事务->删除一条数据->提交事务->开始新事务->… 的过程。这个操作是很慢的。因为时间都花在了开始事务、提交事务上。

你可以把这些同类操作做成一个事务,这样如果操作错误,还能够回滚事务。

事务的操作没有特别的接口函数,它就是一个普通的 sql 语句而已:

分别如下:

int result; result = sqlite3_exec( db, “begin transaction”, 0, 0, &zErrorMsg ); //开始一个事务result = sqlite3_exec( db, “commit transaction”, 0, 0, &zErrorMsg ); //提交事务result = sqlite3_exec( db, “rollback transaction”, 0, 0, &zErrorMsg ); //回滚事务

四、C/C++开发接口简介1 总览

SQLite3是SQLite一个全新的版本,它虽然是在SQLite 2.8.13的代码基础之上开发的,但是使用了和之前的版本不兼容的数据库格式和API. SQLite3是为了满足以下的需求而开发的:

支持UTF-16编码.

用户自定义的文本排序方法.

可以对BLOBs字段建立索引.

因此为了支持这些特性我改变了数据库的格式,建立了一个与之前版本不兼容的3.0版. 至于其他的兼容性的改变,例如全新的API等等,都将在理论介绍之后向你说明,这样可以使你最快的一次性摆脱兼容性问题.

3.0版的和2.X版的API非常相似,但是有一些重要的改变需要注意. 所有API接口函数和数据结构的前缀都由“sqlite_”改为了“sqlite3_”. 这是为了避免同时使用SQLite 2.X和SQLite 3.0这两个版本的时候发生链接冲突.

由于对于C语言应该用什么数据类型来存放UTF-16编码的字符串并没有一致的规范. 因此SQLite使用了普通的void* 类型来指向UTF-16编码的字符串. 客户端使用过程中可以把void*映射成适合他们的系统的任何数据类型.

2 C/C++接口

SQLite 3.0一共有83个API函数,此外还有一些数据结构和预定义(#defines). (完整的API介绍请参看另一份文档.) 不过你们可以放心,这些接口使用起来不会像它的数量所暗示的那么复杂. 最简单的程序仍然使用三个函数就可以完成: sqlite3_open, sqlite3_exec(), 和 sqlite3_close(). 要是想更好的控制数据库引擎的执行,可以使用提供的sqlite3_prepare()函数把SQL语句编译成字节码,然后在使用sqlite3_step()函数来执行编译后的字节码. 以sqlite3_column_开头的一组API函数用来获取查询结果集中的信息. 许多接口函数都是成对出现的,同时有UTF-8和UTF-16两个版本. 并且提供了一组函数用来执行用户自定义的SQL函数和文本排序函数.

(1)如何打开关闭数据库

typedef struct sqlite3 sqlite3; int sqlite3_open(const char*, sqlite3**); int sqlite3_open16(const void*, sqlite3**); int sqlite3_close(sqlite3*); const char *sqlite3_errmsg(sqlite3*); const void *sqlite3_errmsg16(sqlite3*); int sqlite3_errcode(sqlite3*);

sqlite3_open() 函数返回一个整数错误代码,而不是像第二版中一样返回一个指向sqlite3结构体的指针. sqlite3_open() 和sqlite3_open16() 的不同之处在于sqlite3_open16() 使用UTF-16编码(使用本地主机字节顺序)传递数据库文件名. 如果要创建新数据库, sqlite3_open16() 将内部文本转换为UTF-16编码, 反之sqlite3_open() 将文本转换为UTF-8编码.

打开或者创建数据库的命令会被缓存,直到这个数据库真正被调用的时候才会被执行. 而且允许使用PRAGMA声明来设置如本地文本编码或默认内存页面大小等选项和参数.

sqlite3_errcode() 通常用来获取最近调用的API接口返回的错误代码. sqlite3_errmsg() 则用来得到这些错误代码所对应的文字说明. 这些错误信息将以 UTF-8 的编码返回,并且在下一次调用任何SQLite API函数的时候被清除. sqlite3_errmsg16() 和sqlite3_errmsg() 大体上相同,除了返回的错误信息将以 UTF-16 本机字节顺序编码.

SQLite3的错误代码相比SQLite2没有任何的改变,它们分别是:

#define SQLITE_OK0 /* Successful result */#define SQLITE_ERROR 1 /* SQL error or missing database */#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */#define SQLITE_PERM 3 /* Access permission denied */#define SQLITE_ABORT 4 /* Callback routine requested an abort */#define SQLITE_BUSY 5 /* The database file is locked */#define SQLITE_LOCKED 6 /* A table in the database is locked */#define SQLITE_NOMEM 7 /* A malloc() failed */#define SQLITE_READONLY 8 /* Attempt to write a readonly database */#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */#define SQLITE_CORRUPT 11 /* The database disk image is malformed */#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */#define SQLITE_FULL 13 /* Insertion failed because database is full */#define SQLITE_CANTOPEN 14 /* Unable to open the database file */#define SQLITE_PROTOCOL 15 /* Database lock protocol error */#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */#define SQLITE_SCHEMA 17 /* The database schema changed */#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */#define SQLITE_MISMATCH 20 /* Data type mismatch */#define SQLITE_MISUSE 21 /* Library used incorrectly */#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */#define SQLITE_AUTH 23 /* Authorization denied */#define SQLITE_ROW 100 /* sqlite_step() has another row ready */#define SQLITE_DONE 101 /* sqlite_step() has finished executing */

(2)执行 SQL 语句

typedef int (*sqlite_callback)(void*,int,char**, char**);

int sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void*, char**);

sqlite3_exec 函数依然像它在SQLite2中一样承担着很多的工作. 该函数的第二个参数中可以编译和执行零个或多个SQL语句. 查询的结果返回给回调函数. 更多地信息可以查看API 参考.

在SQLite3里,sqlite3_exec一般是被准备SQL语句接口封装起来使用的.

typedef struct sqlite3_stmt sqlite3_stmt;int sqlite3_prepare(sqlite3*, const char*, int, sqlite3_stmt**, const char**);int sqlite3_prepare16(sqlite3*, const void*, int, sqlite3_stmt**, const void**);int sqlite3_finalize(sqlite3_stmt*);int sqlite3_reset(sqlite3_stmt*);

sqlite3_prepare 接口把一条SQL语句编译成字节码留给后面的执行函数. 使用该接口访问数据库是当前比较好的的一种方法.

sqlite3_prepare() 处理的SQL语句应该是UTF-8编码的. 而sqlite3_prepare16() 则要求是UTF-16编码的. 输入的参数中只有第一个SQL语句会被编译. 第四个参数则用来指向输入参数中下一个需要编译的SQL语句存放的SQLite statement对象的指针,任何时候如果调用 sqlite3_finalize() 将销毁一个准备好的SQL声明. 在数据库关闭之前,所有准备好的声明都必须被释放销毁. sqlite3_reset() 函数用来重置一个SQL声明的状态,使得它可以被再次执行.

SQL声明可以包含一些型如“?” 或 “?nnn” 或 “:aaa”的标记, 其中“nnn” 是一个整数,“aaa” 是一个字符串. 这些标记代表一些不确定的字符值(或者说是通配符),可以在后面用sqlite3_bind 接口来填充这些值. 每一个通配符都被分配了一个编号(由它在SQL声明中的位置决定,从1开始),此外也可以用 “nnn” 来表示 “?nnn” 这种情况. 允许相同的通配符在同一个SQL声明中出现多次, 在这种情况下所有相同的通配符都会被替换成相同的值. 没有被绑定的通配符将自动取NULL值.

int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));int sqlite3_bind_double(sqlite3_stmt*, int, double);int sqlite3_bind_int(sqlite3_stmt*, int, int);int sqlite3_bind_int64(sqlite3_stmt*, int, long long int);int sqlite3_bind_null(sqlite3_stmt*, int);int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, void(*)(void*));int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);

以上是 sqlite3_bind 所包含的全部接口,它们是用来给SQL声明中的通配符赋值的. 没有绑定的通配符则被认为是空值.绑定上的值不会被sqlite3_reset()函数重置. 但是在调用了sqlite3_reset()之后所有的通配符都可以被重新赋值.

在SQL声明准备好之后(其中绑定的步骤是可选的), 需要调用以下的方法来执行:

int sqlite3_step(sqlite3_stmt*);

如果SQL返回了一个单行结果集,sqlite3_step() 函数将返回 SQLITE_ROW , 如果SQL语句执行成功或者正常将返回SQLITE_DONE , 否则将返回错误代码. 如果不能打开数据库文件则会返回 SQLITE_BUSY . 如果函数的返回值是SQLITE_ROW, 那么下边的这些方法可以用来获得记录集行中的数据:

const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);int sqlite3_column_bytes(sqlite3_stmt*, int iCol);int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);int sqlite3_column_count(sqlite3_stmt*);const char *sqlite3_column_decltype(sqlite3_stmt *, int iCol);const void *sqlite3_column_decltype16(sqlite3_stmt *, int iCol);double sqlite3_column_double(sqlite3_stmt*, int iCol);int sqlite3_column_int(sqlite3_stmt*, int iCol);long long int sqlite3_column_int64(sqlite3_stmt*, int iCol);const char *sqlite3_column_name(sqlite3_stmt*, int iCol);const void *sqlite3_column_name16(sqlite3_stmt*, int iCol);const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);int sqlite3_column_type(sqlite3_stmt*, int iCol);

sqlite3_column_count()函数返回结果集中包含的列数. sqlite3_column_count() 可以在执行了 sqlite3_prepare()之后的任何时刻调用. sqlite3_data_count()除了必需要在sqlite3_step()之后调用之外,其他跟sqlite3_column_count() 大同小异. 如果调用sqlite3_step() 返回值是 SQLITE_DONE 或者一个错误代码, 则此时调用sqlite3_data_count() 将返回 0 ,然而sqlite3_column_count() 仍然会返回结果集中包含的列数.

返回的记录集通过使用其它的几个 sqlite3_column_***() 函数来提取, 所有的这些函数都把列的编号作为第二个参数. 列编号从左到右以零起始. 请注意它和之前那些从1起始的参数的不同.

sqlite3_column_type()函数返回第N列的值的数据类型. 具体的返回值如下:

#define SQLITE_INTEGER 1#define SQLITE_FLOAT 2#define SQLITE_TEXT 3#define SQLITE_BLOB 4#define SQLITE_NULL 5

sqlite3_column_decltype() 则用来返回该列在 CREATE TABLE 语句中声明的类型. 它可以用在当返回类型是空字符串的时候. sqlite3_column_name() 返回第N列的字段名. sqlite3_column_bytes() 用来返回 UTF-8 编码的BLOBs列的字节数或者TEXT字符串的字节数. sqlite3_column_bytes16() 对于BLOBs列返回同样的结果,但是对于TEXT字符串则按 UTF-16 的编码来计算字节数. sqlite3_column_blob() 返回 BLOB 数据. sqlite3_column_text() 返回 UTF-8 编码的 TEXT 数据. sqlite3_column_text16() 返回 UTF-16 编码的 TEXT 数据. sqlite3_column_int() 以本地主机的整数格式返回一个整数值. sqlite3_column_int64() 返回一个64位的整数. 最后, sqlite3_column_double() 返回浮点数.

不一定非要按照sqlite3_column_type()接口返回的数据类型来获取数据. 数据类型不同时软件将自动转换.

(3)用户自定义函数

可以使用以下的方法来创建用户自定义的SQL函数:

typedef struct sqlite3_value sqlite3_value;int sqlite3_create_function( sqlite3 *, const char *zFunctionName, int nArg, int eTextRep, void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); int sqlite3_create_function16( sqlite3*, const void *zFunctionName, int nArg, int eTextRep, void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); #define SQLITE_UTF8 1 #define SQLITE_UTF16 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16LE 4 #define SQLITE_ANY 5

nArg 参数用来表明自定义函数的参数个数. 如果参数值为0,则表示接受任意个数的参数. 用 eTextRep 参数来表明传入参数的编码形式. 参数值可以是上面的五种预定义值. SQLite3 允许同一个自定义函数有多种不同的编码参数的版本. 数据库引擎会自动选择转换参数编码个数最少的版本使用.

普通的函数只需要设置 xFunc 参数,而把 xStep 和 xFinal 设为NULL. 聚合函数则需要设置 xStep 和 xFinal 参数,然后把 xFunc 设为NULL. 该方法和使用sqlite3_create_aggregate() API一样.

sqlite3_create_function16()和sqlite_create_function()的不同就在于自定义的函数名一个要求是 UTF-16 编码,而另一个则要求是 UTF-8.

请注意自定函数的参数目前使用了sqlite3_value结构体指针替代了SQLite version 2.X中的字符串指针. 下面的函数用来从sqlite3_value结构体中提取数据:

const void *sqlite3_value_blob(sqlite3_value*); int sqlite3_value_bytes(sqlite3_value*); int sqlite3_value_bytes16(sqlite3_value*); double sqlite3_value_double(sqlite3_value*); int sqlite3_value_int(sqlite3_value*); long long int sqlite3_value_int64(sqlite3_value*); const unsigned char *sqlite3_value_text(sqlite3_value*); const void *sqlite3_value_text16(sqlite3_value*); int sqlite3_value_type(sqlite3_value*);

上面的函数调用以下的API来获得上下文内容和返回结果:

void *sqlite3_aggregate_context(sqlite3_context*, int nbyte); void *sqlite3_user_data(sqlite3_context*); void sqlite3_result_blob(sqlite3_context*, const void*, int n, void(*)(void*)); void qlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int64(sqlite3_context*, long long int); void sqlite3_result_null(sqlite3_context*); void sqlite3_result_text(sqlite3_context*, const char*, int n, void(*)(void*)); void sqlite3_result_text16(sqlite3_context*, const void*, int n, void(*)(void*)); void sqlite3_result_value(sqlite3_context*, sqlite3_value*); void *sqlite3_get_auxdata(sqlite3_context*, int); void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));

(4)用户自定义排序规则

下面的函数用来实现用户自定义的排序规则:

sqlite3_create_collation(sqlite3*, const char *zName, int eTextRep, void*,int(*xCompare)(void*,int,const void*,int,const void*));sqlite3_create_collation16(sqlite3*, const void *zName, int eTextRep, void*,int(*xCompare)(void*,int,const void*,int,const void*));sqlite3_collation_needed(sqlite3*, void*,void(*)(void*,sqlite3*,int eTextRep,const char*));sqlite3_collation_needed16(sqlite3*, void*,void(*)(void*,sqlite3*,int eTextRep,const void*));

sqlite3_create_collation() 函数用来声明一个排序序列和实现它的比较函数. 比较函数只能用来做文本的比较. eTextRep 参数可以取如下的预定义值 SQLITE_UTF8, SQLITE_UTF16LE, SQLITE_UTF16BE, SQLITE_ANY,用来表示比较函数所处理的文本的编码方式. 同一个自定义的排序规则的同一个比较函数可以有 UTF-8, UTF-16LE 和 UTF-16BE 等多个编码的版本. sqlite3_create_collation16()和sqlite3_create_collation() 的区别也仅仅在于排序名称的编码是 UTF-16 还是 UTF-8.

可以使用 sqlite3_collation_needed() 函数来注册一个回调函数,当数据库引擎遇到未知的排序规则时会自动调用该函数. 在回调函数中可以查找一个相似的比较函数,并激活相应的sqlite_3_create_collation()函数. 回调函数的第四个参数是排序规则的名称,同样sqlite3_collation_needed采用 UTF-8 编码. sqlite3_collation_need16() 采用 UTF-16 编码.

五、给数据库加密

前面所说的内容网上已经有很多资料,虽然比较零散,但是花点时间也还是可以找到的,

现在要说的这个――数据库加密,资料就很难找。也可能是我操作水平不够,找不到对应资料。但不管这样,我还是通过网上能找到的很有限的资料,探索出了给sqlite数据库加密的完整步骤。

这里要提一下,虽然 sqlite 很好用,速度快、体积小巧。但是它保存的文件却是明文的。若不信可以用 NotePad 打开数据库文件瞧瞧,里面 insert 的内容几乎一览无余。这样赤裸裸的展现自己,可不是我们的初衷。当然,如果你在嵌入式系统、智能手机上使用 sqlite,最好是不加密,因为这些系统运算能力有限,你做为一个新功能提供者,不能把用户有限的运算能力全部花掉。

Sqlite为了速度而诞生。因此Sqlite本身不对数据库加密,要知道,如果你选择标准AES算法加密,那么一定有接近50%的时间消耗在加解密算法上,甚至更多(性能主要取决于你算法编写水平以及你是否能使用cpu提供的底层运算能力,比如MMX或sse系列指令可以大幅度提升运算速度)。

Sqlite免费版本是不提供加密功能的,当然你也可以选择他们的收费版本,那你得支付块钱,而且是USD。我这里也不是说支付钱不好,如果只为了数据库加密就去支付2000块,我觉得划不来。因为下面我将要告诉你如何为免费的Sqlite扩展出加密模块――自己动手扩展,这是Sqlite允许,也是它提倡的。

那么,就让我们一起开始为 sqlite3.c 文件扩展出加密模块。

1 必要的宏

通过阅读 Sqlite 代码(当然没有全部阅读完,6万多行代码,没有一行是我习惯的风格,我可没那么多眼神去看),我搞清楚了两件事:

Sqlite是支持加密扩展的;

需要 #define 一个宏才能使用加密扩展。

这个宏就是 SQLITE_HAS_CODEC。

你在代码最前面(也可以在 sqlite3.h 文件第一行)定义:

#ifndef SQLITE_HAS_CODEC

#define SQLITE_HAS_CODEC

#endif

如果你在代码里定义了此宏,但是还能够正常编译,那么应该是操作没有成功。因为你应该会被编译器提示有一些函数无法链接才对。如果你用的是 VC 2003,你可以在“解决方案”里右键点击你的工程,然后选“属性”,找到“C/C++”,再找到“命令行”,在里面手工添加“/D “SQLITE_HAS_CODEC””。

定义了这个宏,一些被 Sqlite 故意屏蔽掉的代码就被使用了。这些代码就是加解密的接口。

尝试编译,vc会提示你有一些函数无法链接,因为找不到他们的实现。

如果你也用的是VC2003,那么会得到下面的提示:

error LNK: 无法解析的外部符号 _sqlite3CodecGetKey ,该符号在函数 _attachFunc 中被引用

error LNK2019: 无法解析的外部符号 _sqlite3CodecAttach ,该符号在函数 _attachFunc 中被引用

error LNK2019: 无法解析的外部符号 _sqlite3_activate_see ,该符号在函数 _sqlite3Pragma 中被引用

error LNK2019: 无法解析的外部符号 _sqlite3_key ,该符号在函数 _sqlite3Pragma 中被引用

fatal error LNK1120: 4 个无法解析的外部命令

这是正常的,因为Sqlite只留了接口而已,并没有给出实现。

下面就让我来实现这些接口。

2自己实现加解密接口函数

如果真要我从一份 www.sqlite.org 网上down下来的 sqlite3.c 文件,直接摸索出这些接口的实现,我认为我还没有这个能力。

好在网上还有一些代码已经实现了这个功能。通过参照他们的代码以及不断编译中vc给出的错误提示,最终我把整个接口整理出来。

实现这些预留接口不是那么容易,要重头说一次怎么回事很困难。我把代码都写好了,直接把他们按我下面的说明拷贝到 sqlite3.c 文件对应地方即可。我在下面也提供了sqlite3.c 文件,可以直接参考或取下来使用。

这里要说一点的是,我另外新建了两个文件:crypt.c和crypt.h。

其中crypt.h如此定义:

#ifndef DCG_SQLITE_CRYPT_FUNC_#define DCG_SQLITE_CRYPT_FUNC_/***********董淳光写的 SQLITE 加密关键函数库***********//***********关键加密函数***********/int My_Encrypt_Func( unsigned char * pData, unsigned int data_len, const char * key, unsigned int len_of_key );/***********关键解密函数***********/int My_DeEncrypt_Func( unsigned char * pData, unsigned int data_len, const char * key, unsigned intlen_of_key );#endif其中的 crypt.c 如此定义:#include “./crypt.h”#include “memory.h”/***********关键加密函数***********/int My_Encrypt_Func( unsigned char * pData, unsigned int data_len, const char * key, unsigned int len_of_key ){return 0;}/***********关键解密函数***********/int My_DeEncrypt_Func( unsigned char * pData, unsigned int data_len, const char * key, unsigned intlen_of_key ){return 0;}

这个文件很容易看,就两函数,一个加密一个解密。传进来的参数分别是待处理的数据、数据长度、密钥、密钥长度。

处理时直接把结果作用于 pData 指针指向的内容。

你需要定义自己的加解密过程,就改动这两个函数,其它部分不用动。扩展起来很简单。

这里有个特点,data_len 一般总是 1024 字节。正因为如此,你可以在你的算法里使用一些特定长度的加密算法,比如AES要求被加密数据一定是128位(16字节)长。这个1024不是碰巧,而是 Sqlite 的页定义是1024字节,在sqlite3.c文件里有定义:

# define SQLITE_DEFAULT_PAGE_SIZE 1024

你可以改动这个值,不过还是建议没有必要不要去改它。

上面写了两个扩展函数,如何把扩展函数跟 Sqlite 挂接起来,这个过程说起来比较麻烦。我直接贴代码。

分3个步骤。

首先,在 sqlite3.c 文件顶部,添加下面内容:

#ifdef SQLITE_HAS_CODEC#include “./crypt.h”/***********

用于在 sqlite3 最后关闭时释放一些内存

***********/void sqlite3pager_free_codecarg(void *pArg);#endif

这个函数之所以要在 sqlite3.c 开头声明,是因为下面在 sqlite3.c 里面某些函数里要插入这个函数调用。所以要提前声明。

其次,在sqlite3.c文件里搜索“sqlite3PagerClose”函数,要找到它的实现代码(而不是声明代码)。

实现代码里一开始是:

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to ** malloc() must have already been made by this thread before it gets ** to this point. This means the ThreadData must have been allocated already ** so that ThreadData.nAlloc can be set. */ ThreadData *pTsd = sqlite3ThreadData(); assert( pPager ); assert( pTsd && pTsd->nAlloc );#endif

需要在这部分后面紧接着插入:

#ifdef SQLITE_HAS_CODEC sqlite3pager_free_codecarg(pPager->pCodecArg);#endif

这里要注意,sqlite3PagerClose 函数大概也是 3.3.17版本左右才改名的,以前版本里是叫 “sqlite3pager_close”。因此你在老版本sqlite代码里搜索“sqlite3PagerClose”是搜不到的。

类似的还有“sqlite3pager_get”、“sqlite3pager_unref”、“sqlite3pager_write”、“sqlite3pager_pagecount”等都是老版本函数,它们在 pager.h 文件里定义。新版本对应函数是在 sqlite3.h 里定义(因为都合并到 sqlite3.c和sqlite3.h两文件了)。所以,如果你在使用老版本的sqlite,先看看 pager.h 文件,这些函数不是消失了,也不是新蹦出来的,而是老版本函数改名得到的。

最后,往sqlite3.c 文件下找。找到最后一行:

/************** End of main.c ************************************************/

在这一行后面,接上本文最下面的代码段。

这些代码很长,我不再解释,直接接上去就得了。

唯一要提的是 DeriveKey 函数。这个函数是对密钥的扩展。比如,你要求密钥是128位,即是16字节,但是如果用户只输入 1个字节呢?2个字节呢?或输入50个字节呢?你得对密钥进行扩展,使之符合16字节的要求。

DeriveKey 函数就是做这个扩展的。有人把接收到的密钥求md5,这也是一个办法,因为md5运算结果固定16字节,不论你有多少字符,最后就是16字节。这是md5算法的特点。但是我不想用md5,因为还得为它添加包含一些 md5 的.c或.cpp文件。我不想这么做。我自己写了一个算法来扩展密钥,很简单的算法。当然,你也可以使用你的扩展方法,也而可以使用md5 算法。只要修改 DeriveKey 函数就可以了。

在 DeriveKey 函数里,只管申请空间构造所需要的密钥,不需要释放,因为在另一个函数里有释放过程,而那个函数会在数据库关闭时被调用。参考我的 DeriveKey 函数来申请内存。

这里我给出我已经修改好的 sqlite3.c 和 sqlite3.h 文件。

如果太懒,就直接使用这两个文件,编译肯定能通过,运行也正常。当然,你必须按我前面提的,新建 crypt.h 和crypt.c 文件,而且函数要按我前面定义的要求来做。

3 加密使用方法

现在,你代码已经有了加密功能。

你要把加密功能给用上,除了改 sqlite3.c 文件、给你工程添加 SQLITE_HAS_CODEC 宏,还得修改你的数据库调用函数。

前面提到过,要开始一个数据库操作,必须先 sqlite3_open 。

加解密过程就在 sqlite3_open 后面操作。

假设你已经 sqlite3_open 成功了,紧接着写下面的代码:

int i;

//添加、使用密码

i = sqlite3_key( db, “dcg”, 3 );

//修改密码

i = sqlite3_rekey( db, “dcg”, 0 );

用 sqlite3_key 函数来提交密码。

第1个参数是 sqlite3 * 类型变量,代表着用 sqlite3_open 打开的数据库(或新建数据库)。

第2个参数是密钥。

第3个参数是密钥长度。

用 sqlite3_rekey 来修改密码。参数含义同 sqlite3_key。

实际上,你可以在sqlite3_open函数之后,到 sqlite3_close 函数之前任意位置调用 sqlite3_key 来设置密码。

但是如果你没有设置密码,而数据库之前是有密码的,那么你做任何操作都会得到一个返回值:SQLITE_NOTADB,并且得到错误提示:“file is encrypted or is not a database”。

只有当你用 sqlite3_key 设置了正确的密码,数据库才会正常工作。

如果你要修改密码,前提是你必须先 sqlite3_open 打开数据库成功,然后 sqlite3_key 设置密钥成功,之后才能用sqlite3_rekey 来修改密码。

如果数据库有密码,但你没有用 sqlite3_key 设置密码,那么当你尝试用 sqlite3_rekey 来修改密码时会得到SQLITE_NOTADB 返回值。

如果你需要清空密码,可以使用:

//修改密码

i = sqlite3_rekey( db, NULL, 0 );

来完成密码清空功能。

4 sqlite3.c 最后添加代码段

/***董淳光定义的加密函数***/#ifdef SQLITE_HAS_CODEC/***加密结构***/#define CRYPT_OFFSET 8typedef struct _CryptBlock{BYTE* ReadKey; // 读数据库和写入事务的密钥BYTE* WriteKey; // 写入数据库的密钥int PageSize; // 页的大小BYTE* Data;} CryptBlock, *LPCryptBlock;#ifndef DB_KEY_LENGTH_BYTE /*密钥长度*/#define DB_KEY_LENGTH_BYTE 16 /*密钥长度*/#endif#ifndef DB_KEY_PADDING /*密钥位数不足时补充的字符*/#define DB_KEY_PADDING 0x33 /*密钥位数不足时补充的字符*/#endif/*** 下面是编译时提示缺少的函数 ***//** 这个函数不需要做任何处理,获取密钥的部分在下面 DeriveKey 函数里实现 **/void sqlite3CodecGetKey(sqlite3* db, int nDB, void** Key, int* nKey){return ;}/*被sqlite 和 sqlite3_key_interop 调用, 附加密钥到数据库.*/int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen);/**这个函数好像是 sqlite 3.3.17前不久才加的,以前版本的sqlite里没有看到这个函数这个函数我还没有搞清楚是做什么的,它里面什么都不做直接返回,对加解密没有影响**/void sqlite3_activate_see(const char* right ){ return;}int sqlite3_key(sqlite3 *db, const void *pKey, int nKey);int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey);/***下面是上面的函数的辅助处理函数***/// 从用户提供的缓冲区中得到一个加密密钥// 用户提供的密钥可能位数上满足不了要求,使用这个函数来完成密钥扩展static unsigned char * DeriveKey(const void *pKey, int nKeyLen);//创建或更新一个页的加密算法索引.此函数会申请缓冲区.static LPCryptBlock CreateCryptBlock(unsigned char* hKey, Pager *pager, LPCryptBlock pExisting);//加密/解密函数, 被pager调用void * sqlite3Codec(void *pArg, unsigned char *data, Pgno nPageNum, int nMode);//设置密码函数int __stdcall sqlite3_key_interop(sqlite3 *db, const void *pKey, int nKeySize);// 修改密码函数int __stdcall sqlite3_rekey_interop(sqlite3 *db, const void *pKey, int nKeySize);//销毁一个加密块及相关的缓冲区,密钥.static void DestroyCryptBlock(LPCryptBlock pBlock);static void * sqlite3pager_get_codecarg(Pager *pPager);void sqlite3pager_set_codec(Pager *pPager,void *(*xCodec)(void*,void*,Pgno,int),void *pCodecArg );//加密/解密函数, 被pager调用void * sqlite3Codec(void *pArg, unsigned char *data, Pgno nPageNum, int nMode){LPCryptBlock pBlock = (LPCryptBlock)pArg;unsigned int dwPageSize = 0;if (!pBlock) return data;// 确保pager的页长度和加密块的页长度相等.如果改变,就需要调整.if (nMode != 2){ PgHdr *pageHeader; pageHeader = DATA_TO_PGHDR(data); if (pageHeader->pPager->pageSize != pBlock->PageSize) { CreateCryptBlock(0, pageHeader->pPager, pBlock); }}switch(nMode){case 0: // Undo a “case 7” journal file encryptioncase 2: //重载一个页case 3: //载入一个页 if (!pBlock->ReadKey) break; dwPageSize = pBlock->PageSize; My_DeEncrypt_Func(data, dwPageSize, pBlock->ReadKey, DB_KEY_LENGTH_BYTE ); /*调用我的解密函数*/ break;case 6: //加密一个主数据库文件的页 if (!pBlock->WriteKey) break; memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; dwPageSize = pBlock->PageSize; My_Encrypt_Func(data , dwPageSize, pBlock->WriteKey, DB_KEY_LENGTH_BYTE ); /*调用我的加密函数*/ break;case 7: //加密事务文件的页 /*在正常环境下, 读密钥和写密钥相同. 当数据库是被重新加密的,读密钥和写密钥未必相同. 回滚事务必要用数据库文件的原始密钥写入.因此,当一次回滚被写入,总是用数据库的读密钥, 这是为了保证与读取原始数据的密钥相同. */ if (!pBlock->ReadKey) break; memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; dwPageSize = pBlock->PageSize; My_Encrypt_Func( data, dwPageSize, pBlock->ReadKey, DB_KEY_LENGTH_BYTE ); /*调用我的加密函数*/ break;}return data;}//销毁一个加密块及相关的缓冲区,密钥.static void DestroyCryptBlock(LPCryptBlock pBlock){//销毁读密钥.if (pBlock->ReadKey){ sqliteFree(pBlock->ReadKey);}//如果写密钥存在并且不等于读密钥,也销毁.if (pBlock->WriteKey && pBlock->WriteKey != pBlock->ReadKey){ sqliteFree(pBlock->WriteKey);}if(pBlock->Data){ sqliteFree(pBlock->Data);}//释放加密块.sqliteFree(pBlock);}static void * sqlite3pager_get_codecarg(Pager *pPager){return (pPager->xCodec) ? pPager->pCodecArg: NULL;}// 从用户提供的缓冲区中得到一个加密密钥static unsigned char * DeriveKey(const void *pKey, int nKeyLen){unsigned char * hKey = NULL;int j;if( pKey == NULL || nKeyLen == 0 ){ return NULL;}hKey = sqliteMalloc( DB_KEY_LENGTH_BYTE + 1 );if( hKey == NULL ){ return NULL;}hKey[ DB_KEY_LENGTH_BYTE ] = 0;if( nKeyLen < DB_KEY_LENGTH_BYTE ){ memcpy( hKey, pKey, nKeyLen ); //先拷贝得到密钥前面的部分 j = DB_KEY_LENGTH_BYTE - nKeyLen; //补充密钥后面的部分 memset( hKey + nKeyLen, DB_KEY_PADDING, j );}else{ //密钥位数已经足够,直接把密钥取过来 memcpy( hKey, pKey, DB_KEY_LENGTH_BYTE );}return hKey;}//创建或更新一个页的加密算法索引.此函数会申请缓冲区.static LPCryptBlock CreateCryptBlock(unsigned char* hKey, Pager *pager, LPCryptBlock pExisting){LPCryptBlock pBlock;if (!pExisting) //创建新加密块{ pBlock = sqliteMalloc(sizeof(CryptBlock)); memset(pBlock, 0, sizeof(CryptBlock)); pBlock->ReadKey = hKey; pBlock->WriteKey = hKey; pBlock->PageSize = pager->pageSize; pBlock->Data = (unsigned char*)sqliteMalloc(pBlock->PageSize + CRYPT_OFFSET);}else //更新存在的加密块{ pBlock = pExisting; if ( pBlock->PageSize != pager->pageSize && !pBlock->Data){ sqliteFree(pBlock->Data); pBlock->PageSize = pager->pageSize; pBlock->Data = (unsigned char*)sqliteMalloc(pBlock->PageSize + CRYPT_OFFSET); }}memset(pBlock->Data, 0, pBlock->PageSize + CRYPT_OFFSET);return pBlock;}/*** Set the codec for this pager*/void sqlite3pager_set_codec( Pager *pPager, void *(*xCodec)(void*,void*,Pgno,int), void *pCodecArg ){pPager->xCodec = xCodec;pPager->pCodecArg = pCodecArg;}int sqlite3_key(sqlite3 *db, const void *pKey, int nKey){return sqlite3_key_interop(db, pKey, nKey);}int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey){return sqlite3_rekey_interop(db, pKey, nKey);}/*被sqlite 和 sqlite3_key_interop 调用, 附加密钥到数据库.*/int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen){ int rc = SQLITE_ERROR; unsigned char* hKey = 0; //如果没有指定密匙,可能标识用了主数据库的加密或没加密. if (!pKey || !nKeyLen) { if (!nDb) {return SQLITE_OK; //主数据库, 没有指定密钥所以没有加密. } else //附加数据库,使用主数据库的密钥. {//获取主数据库的加密块并复制密钥给附加数据库使用LPCryptBlock pBlock = (LPCryptBlock)sqlite3pager_get_codecarg(sqlite3BtreePager(db->aDb[0].pBt));if (!pBlock) return SQLITE_OK; //主数据库没有加密if (!pBlock->ReadKey) return SQLITE_OK; //没有加密memcpy(pBlock->ReadKey, &hKey, 16); } } else //用户提供了密码,从中创建密钥. { hKey = DeriveKey(pKey, nKeyLen); } //创建一个新的加密块,并将解码器指向新的附加数据库. if (hKey) { LPCryptBlock pBlock = CreateCryptBlock(hKey, sqlite3BtreePager(db->aDb[nDb].pBt), NULL); sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock); rc = SQLITE_OK; } return rc;}// Changes the encryption key for an existing database.int __stdcall sqlite3_rekey_interop(sqlite3 *db, const void *pKey, int nKeySize){Btree *pbt = db->aDb[0].pBt;Pager *p = sqlite3BtreePager(pbt);LPCryptBlock pBlock = (LPCryptBlock)sqlite3pager_get_codecarg(p);unsigned char * hKey = DeriveKey(pKey, nKeySize);int rc = SQLITE_ERROR;if (!pBlock && !hKey) return SQLITE_OK;//重新加密一个数据库,改变pager的写密钥, 读密钥依旧保留.if (!pBlock) //加密一个未加密的数据库{ pBlock = CreateCryptBlock(hKey, p, NULL); pBlock->ReadKey = 0; // 原始数据库未加密 sqlite3pager_set_codec(sqlite3BtreePager(pbt), sqlite3Codec, pBlock);}else // 改变已加密数据库的写密钥{ pBlock->WriteKey = hKey;}// 开始一个事务rc = sqlite3BtreeBeginTrans(pbt, 1);if (!rc){ // 用新密钥重写所有的页到数据库。 Pgno nPage = sqlite3PagerPagecount(p); Pgno nSkip = PAGER_MJ_PGNO(p); void *pPage; Pgno n; for(n = 1; rc == SQLITE_OK && n <= nPage; n ++) { if (n == nSkip) continue; rc = sqlite3PagerGet(p, n, &pPage); if(!rc) { rc = sqlite3PagerWrite(pPage); sqlite3PagerUnref(pPage); } }}// 如果成功,提交事务。if (!rc){ rc = sqlite3BtreeCommit(pbt);}// 如果失败,回滚。if (rc){ sqlite3BtreeRollback(pbt);}// 如果成功,销毁先前的读密钥。并使读密钥等于当前的写密钥。if (!rc){ if (pBlock->ReadKey) { sqliteFree(pBlock->ReadKey); } pBlock->ReadKey = pBlock->WriteKey;}else// 如果失败,销毁当前的写密钥,并恢复为当前的读密钥。{ if (pBlock->WriteKey) { sqliteFree(pBlock->WriteKey); } pBlock->WriteKey = pBlock->ReadKey;}// 如果读密钥和写密钥皆为空,就不需要再对页进行编解码。// 销毁加密块并移除页的编解码器if (!pBlock->ReadKey && !pBlock->WriteKey){ sqlite3pager_set_codec(p, NULL, NULL); DestroyCryptBlock(pBlock);}return rc;}/***下面是加密函数的主体***/int __stdcall sqlite3_key_interop(sqlite3 *db, const void *pKey, int nKeySize){ return sqlite3CodecAttach(db, 0, pKey, nKeySize);}// 释放与一个页相关的加密块void sqlite3pager_free_codecarg(void *pArg){if (pArg) DestroyCryptBlock((LPCryptBlock)pArg);}#endif //#ifdef SQLITE_HAS_CODEC

五、性能优化

很多人直接就使用了,并未注意到SQLite也有配置参数,可以对性能进行调整。有时候,产生的结果会有很大影响。

主要通过pragma指令来实现。

比如: 空间释放、磁盘同步、Cache大小等。

不要打开。前文提高了,Vacuum的效率非常低!

1 auto_vacuum

PRAGMA auto_vacuum;

PRAGMA auto_vacuum = 0 | 1;

查询或设置数据库的auto-vacuum标记。

正常情况下,当提交一个从数据库中删除数据的事务时,数据库文件不改变大小。未使用的文件页被标记并在以后的添加操作中再次使用。这种情况下使用VACUUM命令释放删除得到的空间。

当开启auto-vacuum,当提交一个从数据库中删除数据的事务时,数据库文件自动收缩, (VACUUM命令在auto-vacuum开启的数据库中不起作用)。数据库会在内部存储一些信息以便支持这一功能,这使得数据库文件比不开启该选项时稍微大一些。

只有在数据库中未建任何表时才能改变auto-vacuum标记。试图在已有表的情况下修改不会导致报错。

2 cache_size

建议改为8000

PRAGMA cache_size;

PRAGMA cache_size = Number-of-pages;

查询或修改SQLite一次存储在内存中的数据库文件页数。每页使用约1.5K内存,缺省的缓存大小是2000. 若需要使用改变大量多行的UPDATE或DELETE命令,并且不介意SQLite使用更多的内存的话,可以增大缓存以提高性能。

当使用cache_size pragma改变缓存大小时,改变仅对当前对话有效,当数据库关闭重新打开时缓存大小恢复到缺省大小。 要想永久改变缓存大小,使用default_cache_size pragma.

3 case_sensitive_like

打开。不然搜索中文字串会出错。

PRAGMA case_sensitive_like;

PRAGMA case_sensitive_like = 0 | 1;

LIKE运算符的缺省行为是忽略latin1字符的大小写。因此在缺省情况下‘a‘ LIKE ‘A‘的值为真。可以通过打开case_sensitive_like pragma来改变这一缺省行为。当启用case_sensitive_like,‘a‘ LIKE ‘A‘为假而 ‘a‘ LIKE ‘a‘依然为真。

4 count_changes

打开。便于调试

PRAGMA count_changes;

PRAGMA count_changes = 0 | 1;

查询或更改count-changes标记。正常情况下INSERT, UPDATE和DELETE语句不返回数据。 当开启count-changes,以上语句返回一行含一个整数值的数据――该语句插入,修改或删除的行数。 返回的行数不包括由触发器产生的插入,修改或删除等改变的行数。

5 page_size

PRAGMA page_size;

PRAGMA page_size = bytes;

查询或设置page-size值。只有在未创建数据库时才能设置page-size。页面大小必须是2的整数倍且大于等于512小于等于8192。 上限可以通过在编译时修改宏定义SQLITE_MAX_PAGE_SIZE的值来改变。上限的上限是32768.

6 synchronous

如果有定期备份的机制,而且少量数据丢失可接受,用OFF

PRAGMA synchronous;

PRAGMA synchronous = FULL; (2)

PRAGMA synchronous = NORMAL; (1)

PRAGMA synchronous = OFF; (0)

查询或更改“synchronous”标记的设定。第一种形式(查询)返回整数值。 当synchronous设置为FULL (2), SQLite数据库引擎在紧急时刻会暂停以确定数据已经写入磁盘。 这使系统崩溃或电源出问题时能确保数据库在重起后不会损坏。FULL synchronous很安全但很慢。 当synchronous设置为NORMAL, SQLite数据库引擎在大部分紧急时刻会暂停,但不像FULL模式下那么频繁。 NORMAL模式下有很小的几率(但不是不存在)发生电源故障导致数据库损坏的情况。但实际上,在这种情况下很可能你的硬盘已经不能使用,或者发生了其他的不可恢复的硬件错误。 设置为synchronous OFF (0)时,SQLite在传递数据给系统以后直接继续而不暂停。若运行SQLite的应用程序崩溃, 数据不会损伤,但在系统崩溃或写入数据时意外断电的情况下数据库可能会损坏。另一方面,在synchronous OFF时 一些操作可能会快50倍甚至更多。

在SQLite 2中,缺省值为NORMAL.而在3中修改为FULL.

7 temp_store

使用2,内存模式。

PRAGMA temp_store;

PRAGMA temp_store = DEFAULT; (0)

PRAGMA temp_store = FILE; (1)

PRAGMA temp_store = MEMORY; (2)

查询或更改“temp_store”参数的设置。当temp_store设置为DEFAULT (0),使用编译时的C预处理宏 TEMP_STORE来定义储存临时表和临时索引的位置。当设置为MEMORY (2)临时表和索引存放于内存中。 当设置为FILE (1)则存放于文件中。temp_store_directorypragma 可用于指定存放该文件的目录。当改变temp_store设置,所有已存在的临时表,索引,触发器及视图将被立即删除。

经测试,在类BBS应用上,通过以上调整,效率可以提高2倍以上。

六、后记

(原文后记)

写此教程,可不是一个累字能解释。

但是我还是觉得欣慰的,因为我很久以前就想写 sqlite 的教程,一来自己备忘,二而已造福大众,大家不用再走弯路。

本人第一次写教程,不足的地方请大家指出。

本文可随意、修改、引用。但无论是转载、修改、引用,都请附带我的名字:董淳光。以示对我劳动的肯定。

(补充后记)

篇4:专项资金使用总结

根据省环境保护厅统一安排,芜湖县环境保护监测站于20xx年9月申报了《安徽省20xx年中央财政主要污染物减排专项资金项目建设方案》,共计总资金93。4万元。同年10月16日,财政部以财建〔20xx〕676号《财政部关于下达20xx年主要污染物减排专项资金项目预算的通知》的文件,安排了我县52万元的专项资金,随即安徽省环境保护厅以皖环传〔20xx〕19号下达了《关于召开20xx年监测能力建设项目实施工作会议的通知》,并于12月9日召开了专题会议,进一步规范环境监测能力建设专项资金使用,要求不得挪用、挤占或截留,仅限用于规定的环境监测仪器和设备。

会后,芜湖县环境保护局高度重视,确定监测站站长为项目落实的首要责任人,具体落实项目实施。县环境监测站非常重视专项资金的使用,按照省环保厅的要求,于20xx年2月23日上报了20xx年中央财政主要污染物减排专项资金项目采购计划,并附所采购的仪器设备名称、数量及产品技术参数及要求,在得到省环境监测中心站同意后进入招标采购程序,并与县政府招标采购中心取得联系,进行公开招标采购。为考虑采购方便,经与采购中心协商,本次专项资金共分四个包进行采购,一是环境空气监测仪器,二是水质理化、采样及其他仪器,三是电脑,四是环境监测车,预算总资金52万元。采购工作分别于20xx年4月12日——4月29日完成,并在招标中心的鉴证下签订相关合同,完成了53万元的采购任务。所采购的仪器设备分别于20xx年6月2日——7月21日送达到监测站,并进行相关验收工作,对于大型仪器,生产厂家也即时进行了现场培训。

本次仪器设备的采购得到了省环境监测中心站的大力支持,专项资金所采购的仪器设备部分补充了我站仪器设备的不足,提高了我县环境监测能力,对照《全国环境监测站建设标准》,目前我县监测站与标准仍存在很大的差距,特别是缺乏应急监测仪器和装备,望得到上级进一步支持和关心,我们将用好资金,发挥专项资金应有的作用,为环境管理和环境监督提供更好更快的监测数据。

篇5:mysqlslap 使用总结

mysqlslap 可以用于模拟服务器的负载,并输出计时信息,其被包含在 MySQL 5.1 的发行包中。测试时,可以指定并发连接数,可以指定 SQL 语句。如果没有指定 SQL 语句,mysqlslap 会自动生成查询 schema 的 SELECT 语句。

1. 查看帮助信息。

[root@Betty libmysql]# mysqlslap --helpmysqlslap Ver 1.0 Distrib 5.6.10, for Linux (x86_64)Copyright (c) , , Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Run a query multiple times against the server.Usage: mysqlslap [OPTIONS]Default options are read from the following files in the given order:/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf The following groups are read: mysqlslap clientThe following options may be given as the first argument:--print-defaults Print the program argument list and exit.--no-defaults Don't read default options from any option file,except for login file.--defaults-file=# Only read default options from the given file #.--defaults-extra-file=# Read this file after the global files are read.--defaults-group-suffix=#Also read groups with concat(group, suffix)--login-path=# Read this path from the login file. -?, --help Display this help and exit. -a, --auto-generate-sql 自动生成测试表和数据 Generate SQL where not supplied by file or command line. --auto-generate-sql-add-autoincrement 增加auto_increment一列 Add an AUTO_INCREMENT column to auto-generated tables. --auto-generate-sql-execute-number=# 自动生成的查询的个数 Set this number to generate a set number of queries to run. --auto-generate-sql-guid-primary 增加基于GUID的主键 Add GUID based primary keys to auto-generated tables. --auto-generate-sql-load-type=name 测试语句的类型。取值包括:read,key,write,update和mixed(默认) read:查询 write:插入 key:读主键 update:更新主键 mixed:一半插入一半查询 Specify test load type: mixed, update, write, key, or read; default is mixed. --auto-generate-sql-secondary-indexes=# 增加二级索引的个数,默认是0 Number of secondary indexes to add to auto-generated tables. --auto-generate-sql-unique-query-number=# 不同查询的数量,默认值是10 Number of unique queries to generate for automatic tests. --auto-generate-sql-unique-write-number=# 不同插入的数量,默认是100 Number of unique queries to generate for auto-generate-sql-write-number. --auto-generate-sql-write-number=# Number of row inserts to perform. for each thread (default is 100). --commit=# 多少条DML后提交一次 Commit records every X number of statements. -C, --compress如果服务器和客户端支持都压缩,则压缩信息传递 Use compression in server/client protocol. -c, --concurrency=name 模拟N个客户端并发执行select。可指定多个值,以逗号或者 --delimiter 参数指定的值做为分隔符 Number of clients to simulate for query to run. --create=name 指定用于创建表的.sql文件或者字串 File or string to use create tables. --create-schema=name 指定待测试的数据库名,MySQL中schema也就是database,默认是mysqlslap Schema to run tests in. --csv[=name] Generate CSV output to named file or to stdout if no file is named. -#, --debug[=#] This is a non-debug version. Catch this and exit. --debug-check Check memory and open file usage at exit. -T, --debug-info 打印内存和CPU的信息 Print some debug info at exit. --default-auth=name Default authentication client-side plugin to use. -F, --delimiter=name 文件中的SQL语句使用分割符号 Delimiter to use in SQL statements supplied in file or command line. --detach=# 每执行完N个语句,先断开再重新打开连接 Detach (close and reopen) connections after X number of requests. --enable-cleartext-plugin Enable/disable the clear text authentication plugin. -e, --engine=name 创建测试表所使用的存储引擎,可指定多个 Storage engine to use for creating the table. -h, --host=name Connect to host. -i, --iterations=# 迭代执行的次数 Number of times to run the tests. --no-drop Do not drop the schema after the test. -x, --number-char-cols=name 自动生成的测试表中包含多少个字符类型的列,默认1 Number of VARCHAR columns to create in table if specifying --auto-generate-sql. -y, --number-int-cols=name 自动生成的测试表中包含多少个数字类型的列,默认1 Number of INT columns to create in table if specifying --auto-generate-sql. --number-of-queries=# 总的测试查询次数(并发客户数×每客户查询次数) Limit each client to this number of queries (this is not exact). --only-print 只输出模拟执行的结果,不实际执行 Do not connect to the databases, but instead print out what would have been done. -p, --password[=name] Password to use when connecting to server. If password is not given it's asked from the tty. --plugin-dir=name Directory for client-side plugins. -P, --port=# Port number to use for connection. --post-query=name 测试完成以后执行的SQL语句的文件或者字符串 这个过程不影响时间计算 Query to run or file containing query to execute after tests have completed. --post-system=name 测试完成以后执行的系统语句 这个过程不影响时间计算 system string to execute after tests have completed. --pre-query=name 测试执行之前执行的SQL语句的文件或者字符串 这个过程不影响时间计算 Query to run or file containing query to execute before running tests. --pre-system=name 测试执行之前执行的系统语句 这个过程不影响时间计算 system() string to execute before running tests. --protocol=name The protocol to use for connection (tcp, socket, pipe, memory). -q, --query=name 指定自定义.sql脚本执行测试。例如可以调用自定义的一个存储过程或者sql语句来执行测试 Query to run or file containing query to run. -s, --silent 不输出 Run program in silent mode - no output. -S, --socket=name The socket file to use for connection. --ssl Enable SSL for connection (automatically enabled with other flags). --ssl-ca=name CA file in PEM format (check OpenSSL docs, implies --ssl). --ssl-capath=name CA directory (check OpenSSL docs, implies --ssl). --ssl-cert=name X509 cert in PEM format (implies --ssl). --ssl-cipher=name SSL cipher to use (implies --ssl). --ssl-key=nameX509 key in PEM format (implies --ssl). --ssl-crl=nameCertificate revocation list (implies --ssl). --ssl-crlpath=name Certificate revocation list path (implies --ssl). --ssl-verify-server-cert Verify server's “Common Name” in its cert against hostname used when connecting. This option is disabled by default. -u, --user=name User for login if not current user. -v, --verbose 输出更多的信息 More verbose output; you can use this multiple times to get even more verbose output. -V, --version Output version information and exit.[root@Betty libmysql]#

2. 以自动生成测试表和数据的形式,分别模拟 50 和 100 个客户端并发连接处理 1000 个 query 的情况。

[root@Betty libmysql]# mysqlslap -a --concurrency=50,100 --number-of-queries=1000 Benchmark Average number of seconds to run all queries: 0.148 seconds Minimum number of seconds to run all queries: 0.148 seconds Maximum number of seconds to run all queries: 0.148 seconds Number of clients running queries: 50 Average number of queries per client: 20Benchmark Average number of seconds to run all queries: 0.246 seconds Minimum number of seconds to run all queries: 0.246 seconds Maximum number of seconds to run all queries: 0.246 seconds Number of clients running queries: 100 Average number of queries per client: 10[root@Betty libmysql]#

3.增加 --debug-info 选项,可以输出内存和CPU信息。

[root@Betty libmysql]# mysqlslap -a --concurrency=50,100 --number-of-queries=1000 --debug-infoBenchmark Average number of seconds to run all queries: 0.202 seconds Minimum number of seconds to run all queries: 0.202 seconds Maximum number of seconds to run all queries: 0.202 seconds Number of clients running queries: 50 Average number of queries per client: 20Benchmark Average number of seconds to run all queries: 0.193 seconds Minimum number of seconds to run all queries: 0.193 seconds Maximum number of seconds to run all queries: 0.193 seconds Number of clients running queries: 100 Average number of queries per client: 10User time 0.09, System time 0.05Maximum resident set size 7848, Integral resident set size 0Non-physical pagefaults 4221, Physical pagefaults 0, Swaps 0Blocks in 0 out 0, Messages in 0 out 0, Signals 0Voluntary context switches 7314, Involuntary context switches 1400

4. 增加 --iterations 选项,可以重复执行 5 次

[root@Betty libmysql]# [root@Betty libmysql]# mysqlslap -a --concurrency=50,100 --number-of-queries=1000 --iterations=5 --debug-infoBenchmark Average number of seconds to run all queries: 0.168 seconds Minimum number of seconds to run all queries: 0.147 seconds Maximum number of seconds to run all queries: 0.217 seconds Number of clients running queries: 50 Average number of queries per client: 20Benchmark Average number of seconds to run all queries: 0.209 seconds Minimum number of seconds to run all queries: 0.156 seconds Maximum number of seconds to run all queries: 0.280 seconds Number of clients running queries: 100 Average number of queries per client: 10User time 0.47, System time 0.25Maximum resident set size 9848, Integral resident set size 0Non-physical pagefaults 16880, Physical pagefaults 0, Swaps 0Blocks in 0 out 0, Messages in 0 out 0, Signals 0Voluntary context switches 35954, Involuntary context switches 6583[root@Betty libmysql]#

5. 可以针对远程主机上的 mysql 进行测试。

[root@Betty Shell]# mysqlslap -a --concurrency=50,100 --number-of-queries=1000 -h 172.16.81.99 -P 3306 -pEnter password: Benchmark Average number of seconds to run all queries: 2.009 seconds Minimum number of seconds to run all queries: 2.009 seconds Maximum number of seconds to run all queries: 2.009 seconds Number of clients running queries: 50 Average number of queries per client: 20Benchmark Average number of seconds to run all queries: 4.519 seconds Minimum number of seconds to run all queries: 4.519 seconds Maximum number of seconds to run all queries: 4.519 seconds Number of clients running queries: 100 Average number of queries per client: 10[root@Betty Shell]#

6. 使用 --only-print 选项,可以查看 mysqlslap 在测试过程中如何执行的 sql 语句。在这种方式下,仅会对数据库进行模拟操作。如下显示的自动产生测试表和数据的情况下,mysqlslap 的执行过程:创建一个临时的库 mysqlslap ,并在测试结束是会将其删除。

[root@Betty libmysql]# mysqlslap -a --only-print DROP SCHEMA IF EXISTS `mysqlslap`;CREATE SCHEMA `mysqlslap`;use mysqlslap;CREATE TABLE `t1` (intcol1 INT(32) ,charcol1 VARCHAR(128));INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');INSERT INTO t1 VALUES (100669,'qnMdipW5KkXdTjGCh2PNzLoeR0527frpQDQ8uw67Ydk1K06uuNHtkxYBxT5w8plb2BbpzhwYBgPNYX9RmICWGkZD6fAESvhMzH3yqzMtXoH4BQNylbK1CmEIPGYlC6');SELECT intcol1,charcol1 FROM t1;INSERT INTO t1 VALUES (73673339,'BN3152Gza4GW7atxJKACYwJqDbFynLxqc0kh30YTwgz3FktQ43XTrqJ4PQ25frn7kXhfXD8RuzN1j8Rf3y8ugKy6es3IbqPJM6ylCyD6xS7YcQCfHKZxYNvB7yTahm');SELECT intcol1,charcol1 FROM t1;INSERT INTO t1 VALUES (1759592334,'3lkoxjtvgLu5xKHSTTtJuGE5F5QqmCcppCTmvFZScRZQgim93gSxwb24gKmIPEzEQStMjQiCu7WapGbkw4ilXch3xRLMhKSzgLDOovSi2qGj6rKvnuYAWDDJgaZDu2');SELECT intcol1,charcol1 FROM t1;INSERT INTO t1 VALUES (95275444,'bNIrBDBl81tjzdvuOpQRCXgX37xGtzLKEXBIcE3k7xK7aFtqxC99jqYnpTviK83bf6lGDgsKd4R3KLmHPnI8TqnIKj1gjw7N2sXFZNS2Svyg8cpZN7atxL39w4igsp');SELECT intcol1,charcol1 FROM t1;INSERT INTO t1 VALUES (866596855,'naQuzhMt1IrZIJMkbLAKBNNKKK2sCknzI5uHeGAgQuDd5SLgpN0smODyc7qorTo1QaI5qLl97qmCIzl0Mds81x7TxpIoJyqlY0iEDRNKA1PS0AKEn5NhuMAr3KgEIM');SELECT intcol1,charcol1 FROM t1;INSERT INTO t1 VALUES (364531492,'qMa5SuKo4M5OM7ldvisSc6WK9rsG9E8sSixocHdgfa5uiiNTGFxkDJ4EAwWC2e4NL1BpAgWiFRcp1zIH6F1BayPdmwphatwnmzdwgzWnQ6SRxmcvtd6JRYwEKdvuWr');DROP SCHEMA IF EXISTS `mysqlslap`;[root@Betty libmysql]#

7. 实际测试中的复杂情况,

使用 --defaults-file 选项,指定从配置文件中读取选项配置。

使用 --number-int-cols 选项,指定表中会包含 4 个 int 型的列。

使用 --number-char-cols 选项,指定表中会包含 35 个 char 型的列。

使用 --engine 选项,指定针对何种存储引擎进行测试。

[root@Betty ~]# mysqlslap --defaults-file=/etc/my.cnf --concurrency=50,100,200 --iterations=1 --number-int-cols=4 --number-char-cols=35 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=mixed --engine=myisam,innodb --number-of-queries=200 --debug-info -S /tmp/mysql.sockBenchmark Running for engine myisam Average number of seconds to run all queries: 0.015 seconds Minimum number of seconds to run all queries: 0.015 seconds Maximum number of seconds to run all queries: 0.015 seconds Number of clients running queries: 50 Average number of queries per client: 4Benchmark Running for engine myisam Average number of seconds to run all queries: 0.024 seconds Minimum number of seconds to run all queries: 0.024 seconds Maximum number of seconds to run all queries: 0.024 seconds Number of clients running queries: 100 Average number of queries per client: 2Benchmark Running for engine myisam Average number of seconds to run all queries: 0.028 seconds Minimum number of seconds to run all queries: 0.028 seconds Maximum number of seconds to run all queries: 0.028 seconds Number of clients running queries: 200 Average number of queries per client: 1Benchmark Running for engine innodb Average number of seconds to run all queries: 0.112 seconds Minimum number of seconds to run all queries: 0.112 seconds Maximum number of seconds to run all queries: 0.112 seconds Number of clients running queries: 50 Average number of queries per client: 4Benchmark Running for engine innodb Average number of seconds to run all queries: 0.042 seconds Minimum number of seconds to run all queries: 0.042 seconds Maximum number of seconds to run all queries: 0.042 seconds Number of clients running queries: 100 Average number of queries per client: 2Benchmark Running for engine innodb Average number of seconds to run all queries: 0.105 seconds Minimum number of seconds to run all queries: 0.105 seconds Maximum number of seconds to run all queries: 0.105 seconds Number of clients running queries: 200 Average number of queries per client: 1User time 0.05, System time 0.06Maximum resident set size 8332, Integral resident set size 0Non-physical pagefaults 5388, Physical pagefaults 0, Swaps 0Blocks in 0 out 0, Messages in 0 out 0, Signals 0Voluntary context switches 7484, Involuntary context switches 2839[root@Betty ~]#

8. 使用存储过程进行测试。

========== 我是分割线=============

mysqlslap 运行分三个阶段:

创建 schema,table 和任何用来测试的已经存储了的程序和数据。这个阶段使用单客户端连接;

进行负载测试。这个阶段使用多客户端连接;

清除(断开连接,删除指定表)。这个阶段使用单客户端连接。

例子:

a. 提供你自己的创建 SQL 语句和查询 SQL 语句,有 50 个客户端查询,每个查询 200 次(在单行上输入命令):

[root@Betty ~]# mysqlslap --delimiter=“;” --create=“CREATE TABLE a (b int);INSERT INTO a VALUES (23)” --query=“SELECT * FROM a” --concurrency=50 --iterations=200Benchmark Average number of seconds to run all queries: 0.005 seconds Minimum number of seconds to run all queries: 0.003 seconds Maximum number of seconds to run all queries: 0.007 seconds Number of clients running queries: 50 Average number of queries per client: 1[root@Betty ~]#

b. 让 mysqlslap 创建查询的 SQL 语句,使用的表有 2 个 INT 行和 3 个 VARCHAR 行。使用 5 个客户端,每一个查询 20 次!不要创建表或插入数据。(换言之,用之前测试的模式和数据):

[root@Betty ~]# mysqlslap --concurrency=5 --iterations=20 --number-int-cols=2 --number-char-cols=3 --auto-generate-sqlBenchmark Average number of seconds to run all queries: 0.025 seconds Minimum number of seconds to run all queries: 0.012 seconds Maximum number of seconds to run all queries: 0.084 seconds Number of clients running queries: 5 Average number of queries per client: 0[root@Betty ~]#

c. 告诉程序从指定的 create.sql 文件去加载 create,insert 和查询等 SQL 语句。该文件有多个表的 create 和insert 语句, 它们都是通过“;”分隔开的。query.sql 文件则有多个查询语句, 分隔符也是“;”。执行所有的加载语句,然后通过查询文件执行所有的查询语句,分别在 5 个客户端上每个执行 5 次:

[root@Betty ~]# mysqlslap --concurrency=5 --iterations=5 --query=query.sql --create=create.sql --delimiter=“;”

========== 我是分割线=============

mysqlslap 对于模拟多个用户同时对 MySQL 发起“进攻”提供了方便。同时详细的提供了“高负荷攻击 MySQL”的详细数据报告。

来自:my.oschina.net/moooofly/blog/152547

篇6:怎样学习和使用成语

前面已经谈到,成语的文字非常简炼,又有固定的形式,本身具有易学易记的特点。所以无论学习、或者使用成语,都不很困难。但是如果想要很好地掌握它,也有应该注意的几点:

(1)彻底理解学习和使用成语,跟学习和使用字、词一样,首先要彻底理解它的涵义,不能“不求甚解“。如果对某一个成语的意思还没有理解透彻,或者对成语中某个字的音义还说不准确,就随便拿来使用,那就难免用得不恰当,甚至闹出笑话。

成语的来源不一,有的容易懂,有的比较难懂,可是其中以容易懂的占多数。有些成语从字面上就可以看出它的意思来,如“千言万语““心直口快““苦口婆心“等等,都很容易懂。“如一发千钧“(意思是一根头发负担着千钧的重量。“钧“是我国古时的重量单位,一钧大约等于三十斤。这个成语是形容情势非常危险。)“啼饥号寒“(意思是饿得哭泣,冻得叫喊。“啼“是“哭“,“号“是“叫喊“,这个成语是形容挨饿受冻的悲惨景象。)“不速之客“(意思是没有邀请就突然来到的客人。“速“当“邀请“讲。)等等,就比较难懂。但是只要把个别生字如“钧““啼““号““寒““速“弄清楚了,整个成语的意思就不难理解。至于象“瓜田李下“这个成语,就应该算是难懂的。先要知道古乐府诗《古君子行》里有“瓜田不纳履,李下不整冠“两句话。这是告诉人们处在嫌疑的地位要注意。在古书里,也把这个意思写作“瓜李之嫌“(见《唐书•柳公权传》)。无论是“瓜田李下“或“瓜李之嫌“,如果不知道它的出处,只从字面上作解释,那就很难懂得它的意思。又如“管窥蠡测“这个成语,如果仅仅知道管是“竹管“,窥是“从孔隙里看“,“蠡“是“瓠瓢“,测是“测量“,也不容易懂得整个成语的意思。如果知道这四个字是从“以管窥天,以蠡测海“八个字里截取下来的,那就不难知道这个成语比喻的是:所见甚小,看不到事物的全面。至于那些由历史事实来的成语,如“八公山上,草木皆屏“,“项庄舞剑,意在沛公“之类,从寓言传说来的成语如“叶公好龙““含沙射影“之类,如果不知道它们的出处,当然也是无法理解。以上所说的这类比较难懂的和很难懂的成语,大部分见于古书中,想要理解这类成语,可以翻阅《辞源》《辞海》等有关的书籍。

有些成语,懂得了字面的意思,还要特别注意它的习惯上的用法。例如“一个巴掌拍不响“和“孤掌难鸣“这两个成语,只从字面上看,好象一个是白话,一个是文言,意思没有什么两样。可是仔细想想,“一个巴掌拍不响“,是说事情的发生不是由于单方面引起来的,使用这个成语,有各打五十板的意味。“孤掌难鸣“是说只有一个人的力量很难成事。对如此处境的人,有同情的意味。两个成语的意思并无共同之处。(有的人,在某一特定的环境下,也把“孤掌难鸣“当做“一个巴掌拍不响“来用,但究竟是不够妥当的。)所谓彻底理解,也包括连这些地方都要加以辨析,彻底弄清楚。

(2)用得场合恰当使用成语,应当力求用得场合恰当,不应当滥用。郭沫若同志曾经举过一个例子,现在不妨引在这里。他说:

“现在有些文章有个毛病,就是爱堆砌形容词……如    六万万人正以排山倒海、乘风破浪之势……’这样的句子就有点不恰当。把山移开、海翻过来,那是多么大的形势,同    乘风破浪    不能相比。所以既然已有    排山倒海    ,就不应再用    乘风破浪    了。“(《文风问答》)

这个错误,就是由于不顾场合,硬把“乘风破浪“这个成语塞进句子里造成的。

此外,还有一种情况,使用成语时也应该特别注意,即它的历来的用法。“如“日理万机“这个成语,旧日只用于皇帝、国王,意思是每天处理的国家大事很多。现在也有人用于毛主席、周总理,说他们“日理万机“,这也未尝不可。但是如果再用之于省长、县长等人,就不很恰当    尽管他们每天做的事情很多。

对于在某一场合看起来好象都可以使用的几个成语,更要仔细地辨别它们的不同之处,体味文章所需要表达的意思是什么,选用哪个最恰当。例如“千头万绪“和“千变万化“这两个成语,有时候在一个句子里好象都可以用,可是如果说“这本小说的情节真是千头万绪,我越看越觉得有味“。那就不如不用“千头万绪“,而用“千变万化“。

(3)分清褒义贬义成语里面,也的除了表示本身的意义之外,还表示人们的喜爱或者憎恶的感情。表示喜爱的,通常说它含有褒义;表示憎恶的,通常说它含有贬义。这两类成语千万不可误用。比如,我们不能说“敌军的先头部队,勇往直前地冲上来“,因为“勇往直前“是形容勇敢地向前进,含有褒义。而这里说的是敌人的情形,我们对他们当然是不会有什么好感,所以应当用含有贬义的词语,把“勇往直前“改为“不顾死活“,那就比较合适些。又如“无微不至“跟“无所不至“两个成语的意思有些相近,但是“无微不至“多指关怀,含有褒义;“无所不至“多系斥责,含有贬义。因此“帝国主义者对殖民地劳苦人民的剥削压榨真是无微不至“这个句子,就有毛病。应该把“无微不至“改为“无所不至“,那才比较妥当。又如成语“擢发难数“,就是含有贬义的。一般是指某人所犯的罪恶之多,    原作者采取了夸张的手法。不能单纯地把它当作“不胜枚举“之类的意思来讲。比如“今年市场繁荣,百货品种多得真是擢发难数“,把擢发难数用在这里,就觉得可笑,把它改为“不胜枚举“就行了。

(4)注意成语的规范化前边说过,成语是固定的词组或句子,一般不能随便换字或改变它的结构。不过有少数成语,也有从早就有两三种不同的说法的。如的“一发千钧“也作“千钧一发“,“含沙射影“也作“含沙射人“、“鹬蚌相持,渔人得利“,“持“也作“争“,“人“也作“翁“,等等。这是多年来形成的差异,我们只能根据“约定俗成“的原则,承认几种说法都可以。又如“捕风捉影“这个成语,原是“系风捕影“,见《汉书•郊祀志》。成语“每况愈下“,原作“每下愈况“,见《庄子•知北游》。可是由于误用已久,现在我们也不必恢复它的原来面目。还有一种情况,有时为了增强语势、加强表达效果,也可以适当的在成语中插入几个字,例如:

天下何曾太平

鱼目岂能混珠

理直而后气壮

这样借用原有的成语略加改动,也完全可以。但是我们自己使用成语,除非为了取得修辞的效果,对某一成语确有改变的必要时,都应该注意成语的规范化,也就是尽量地照原来的文字使用,保持语文的纯洁和健康。有人把“变本加厉“写成“变本加利“,把“奋不顾身“写成“愤不顾生“,把“焕然一新“写成“换然一新“,把“至理名言“写成“真理名言“等,都是不妥当的。因为这样改变起来,就容易造成语文中的混乱现象,甚至使人误解。

前边说过,在必要的情况下,也可以改造成语,使它更好地为我们的语言服务。除此以外,作诗的时候为了押韵,也可以把成语的结构略加改动。例如郭沫若同志有一首《向地球开战》的诗,最后几句是:

别的星球或许也有人类更加进步,

我们要交流经验,争取宇宙大同。

同志们,这是不是幻想呢?

不,这正是马克思主义的造极登峰。

但我并不想多用力来歌颂明天,

我只想多用力来在今天把你们歌颂。

赶快向地球开战吧,同志们,

无论在天涯海角,让我们陷阵冲锋。

这里为了押韵,把成语“登峰造极“改为“造极登峰“,报“冲锋陷阵“改为“陷阵冲锋“,这完全是可以的。

又如《红楼梦》第八十六回的回目是:

人亡物在公子填词

蛇影杯弓颦卿绝粒

成语原来是“杯弓蛇影“,出于《晋书•乐广传》。故事是这样:乐广有位亲近的客人,很久没有到他那里,乐广问他原因,客人说,“前次你请我喝酒,我正要喝,看进酒杯里有条蛇,心里很厌恶,喝酒以后就病了。“这时候乐广办公厅的墙壁上挂着一张弓,弓背上画着蛇,涂着明亮的油漆。乐广心想,杯中的蛇就是弓上的影子。于是又在原地方摆上酒,问那位客人:“酒里边是否还见什么东西?“客人说:“跟前次一样。“乐广把原因告诉了客人,客人忽然醒悟,很久没有治好的心病,立刻消失了。《红楼梦》的回目把的“杯弓蛇影“改为“舌影杯弓“,这是为了要使回目的平仄协调。回目的上联“人亡物在,公子填词“,用的是“平平仄仄,仄仄平平“的格式(“公“虽然是平声字,但是它放在后半句的第一个字上,这样也可以)。下联应作“仄仄平平,平平仄仄“,作者想要在这里用“杯弓蛇影“跟“人亡物在“对仗,可是“杯弓蛇影“是“平平平仄“,于是就把它改为“蛇影杯弓“,使它合于“仄仄平平“的格式(“蛇“虽然是平声字,但是它放在第一个字上是无妨的)。为了这类原因,改动成语也是可以的。

(5)成语的灵活运用一般说来,成语是“固定词组“,有一定的固定性。可是,我们不能就认为它是一成不变的。在实际运用方面,是有它的极大的灵活性的。前面有些例子,已足以说明这个问题。现在我们再举几个例子来看:

杞忧心事知多少,愿把兴亡责匹夫。

这两句诗里,就包含着两个成语:①“杞人忧天“,②“匹夫有责“。可是诗的句子里,并没有完整地把这两个成语写出来,而是把成语融化在诗句之中。又如清代新安处士刘四新答吴三桂诗:

李陵心事久风尘,三十年来讵卧薪?

“卧薪“就是成语“卧薪尝胆“的缩写    当然,“卧薪“二字也可以看做是用典。又如,有句格言似的话:

苟有恒,何必五更起三更眠?最无益,莫如一日曝十日寒。

这就又把成语“一曝十寒“的“一“、“十“后面,各加上了一个“日“字。

要想能够把成语用得灵活,必须把成语的精神实质真正地吸收、消化,才能融会贯通,左右逢源。

篇7:英语学习:主动“使用英语”

Well I know in some countries, people shake hands to greet each other.In some coubtries, people bow to greet each other.In some countries, people hug or kiss the cheek to greet each other

我们练就了这样的主动“使用英语”的语言能力,就算平时“没有英语使用环境”,我们也照样可以不依赖外部语言环境“自己跟自己说口语”!

如果我们想进一步自我训练“使用英语”能力,我们还可以做下面的“使用英语”训练(能力薄弱的可以忽略这一步):

读到to shake hands, to bow,to hug, to kiss on the cheek, to pat on the back时,你会“想起”,其实是“使用”到什么英语?

body language这个词,不是吗?

Well I know people in different countries use different body languages when they greet each other.

这样充分发挥人的英语学习的“主观能动性”的“使用英语”的学习,是不是一种快乐?

最后,我们可以做以下“使用英语”的补充训练:

还是读到Greetings from around the world.

Handshake:Canada,Peru,English.Bow:Japan,Korea,Indonesia. A kiss on the cheek:Brazil,France,Italy. A hug:the United States,Denmark,Egypt. A pat on the back:Greece,Russia,Mexico时,我们这样“使用英语”:

What is greeting?

Well I know greeting is when we meet each other, we do something such as to shake hands, to bow,to kiss on the cheek, to hug, or to pat on the back.

你是“使用英语”和“积累”这些英语shake hands, to bow,to kiss on the cheek, to hug, or to pat on the back来记住greeting这个词,而不是“使用中文”“打招呼”记住它:这就是“使用英语学英语”的一个重要内容。

OK, so much for today’s training. Thank you for watching.And good bye till next time.

篇8:android shape使用总结

今天使用到shape,这个里面有很多属性,在这里我记录一下各个属性的使用的情况以及所代表的意思

复制代码

xmlns:android=“schemas.android.com/apk/res/android”

android:shape=[“rectangle” | “oval” | “line” | “ring”] >

android:radius=“integer”

android:topLeftRadius=“integer”

android:topRightRadius=“integer”

android:bottomLeftRadius=“integer”

android:bottomRightRadius=“integer” />

android:angle=“integer”

android:centerX=“integer”

android:centerY=“integer”

android:centerColor=“integer”

android:endColor=“color”

android:gradientRadius=“integer”

android:startColor=“color”

android:type=[“linear” | “radial” | “sweep”]

android:useLevel=[“true” | “false”] />

android:left=“integer”

android:top=“integer”

android:right=“integer”

android:bottom=“integer” />

android:width=“integer”

android:height=“integer” />

android:color=“color” />

android:width=“integer”

android:color=“color”

android:dashWidth=“integer”

android:dashGap=“integer” />

复制代码

上面这段就是shape使用的格式,来看一下如何使用:

定义这是一个GradientDrawable,必须作为根元素,

android:shape

定义shape的值,必须是下面的之一:

“rectangle”  矩阵,这也是默认的shape

“oval”  椭圆

“line”  一条水平的直线。这种shape必须使用 元素来定义这条线的宽度

“ring”  圆环

下面的属性只有当 android:shape=“ring”才使用:

android:innerRadius

尺寸。 内环的半径。一个尺寸值(dip等等)或者一个尺寸资源。

android:innerRadiusRatio

Float类型。这个值表示内部环的比例,例如,如果android:innerRadiusRatio = “ 5 ”,那么内部的半径等于环的宽度除以5。这个值会被android:innerRadius重写。 默认值是9。

android:thickness

尺寸。环的厚度,是一个尺寸值或尺寸的资源。

android:thicknessRatio

Float类型。厚度的比例。例如,如果android:thicknessRatio= “ 2 ”,然后厚度等于环的宽度除以2。这个值是被android:innerRadius重写, 默认值是3。

android:useLevel

Boolean类型。如果用在 LevelListDrawable里,那么就是true。如果通常不出现则为false。

为Shape创建一个圆角,只有shape是rectangle时候才使用。

android:radius

Dimension。圆角的半径。会被下面每个特定的圆角属性重写。

android:topLeftRadius

Dimension。top-left 设置左上角的半径

android:topRightRadius

Dimension。top-right 设置右上角的半径

android:bottomLeftRadius

Dimension。 设置右下角的半径

android:bottomRightRadius

Dimension。设置左下角的半径

指定这个shape的渐变颜色。

android:angle

Integer。渐变的角度。 0 代表从 left 到 right。90 代表bottom到 top。必须是45的倍数,默认为0

android:centerX

Float。渐变中心的相对X坐标,在0到1.0之间。

android:centerY

Float。渐变中心的相对Y坐标,在0到1.0之间。

android:centerColor

Color。可选的颜色值。基于startColor和endColor之间。

android:endColor

Color。 结束的颜色。

android:gradientRadius

Float 。渐变的半径。只有在 android:type=“radial”才使用

android:startColor

Color。开始的颜色值。

android:type

Keyword。渐变的模式,下面值之一:

“linear”  线形渐变,

这也是默认的模式

“radial”  辐射渐变。startColor即辐射中心的颜色

“sweep”  扫描线渐变。

android:useLevel

Boolean。如果在LevelListDrawable中使用,则为true

内容与视图边界的距离

android:left

Dimension。左边填充距离.

android:top

Dimension。顶部填充距离.

android:right

Dimension。右边填充距离.

android:bottom

Dimension。底部填充距离.

这个shape的大小。

android:height

Dimension。这个shape的高度。

android:width

Dimension。这个shape的宽度。

注意:默认情况下,这个shape会缩放到与他所在容器大小成正比。当你在一个ImageView中使用这个shape,你可以使用 android:scaleType=“center”来限制这种缩放。

填充这个shape的纯色

android:color

Color。颜色值,十六进制数,或者一个Color资源

这个shape使用的笔画,当android:shape=“line”的时候,必须设置改元素。

android:width

Dimension。笔画的粗细。

android:color

Color。笔画的颜色

android:dashGap

Dimension。每画一条线就间隔多少。只有当android:dashWidth也设置了才有效。

android:dashWidth

Dimension。每画一条线的长度。只有当 android:dashGap也设置了才有效。

android:dashGap和android:dashWidth设置这条线为虚线的,其中android:dashWidth表示'-'这样一个横线的宽度,android:dashGap表示之间隔开的距离,

使用别人的一段代码:

button_bg.xml

复制代码

android:width=“2dp”

android:color=“#fad3cf” />

android:bottomLeftRadius=“5dp”

android:bottomRightRadius=“5dp”

android:topLeftRadius=“5dp”

android:topRightRadius=“5dp” />

android:bottom=“10dp”

android:left=“10dp”

android:right=“10dp”

android:top=“10dp” />

复制代码

button_pressed_bg.xml的内容如下:

复制代码

android:endColor=“#FFFFFF”

android:gradientRadius=“50”

android:startColor=“#ff8c00”

android:type=“radial” />

android:dashGap=“3dp”

android:dashWidth=“5dp”

android:width=“2dp”

android:color=“#dcdcdc” />

android:bottom=“10dp”

android:left=“10dp”

android:right=“10dp”

android:top=“10dp” />

复制代码

如何使用,看下面的代码:

复制代码

复制代码

篇9:房地产DM使用总结

传单对于房地产营销推广来说是最常见的一种方式,由于其制作成本和派发成本低廉,能够图文并茂的介绍项目或品牌信息,具有一定的阅览关注时效和保存期限,所以经常使用与营销的前期、中期和后期等各环节,可谓是物美价廉的推广利器,

如何将传单派发的效果发挥的淋漓尽致,主要是要重视传单派发过程中的两点:设计过程和派发过程。

把握好了这两点,传单就不会被拒接或接收后匆匆一瞥,继而成为城市污染源、环卫工人打扫的老大难问题和废品回收站磅秤上的常客。

一、传单的设计形式

通常来说传单的设计形式可分为常规式或非常规式。

常规式的传单尺寸为:16开(260 mmX184mm);32开(184 mmX130mm)。选用纸张材质大多为120至200克铜版纸,也有使用快印的A4纸。

非常规式的传单可根据项目的规划设计特点、项目所在地的风土人情、派发区域的人群特征来进行各种别出心裁的创新,以达到从被动派发到主动索取的目的。

非常规的形式主要有名片式、扇子式、扑克牌式、节日贺卡式、小年历式、优惠券式和VIP金卡式等。

常规式的形式大家相信见过较多在此不做赘述,分别就非常规的各种形式给大家举曾操作过的案例以供参考。

1、名片式:

朋友所处公司在某南方一线大城市,开发一针对年轻白领阶层的小户型精装修公寓,在营销推广中拟使用派发传单的形式进行辅助宣传,在沟通中建议其以名片大小格式剪裁采用活泼轻快的色调设计星座系列项目卡。

针对所开发的12种户型分别以颜色和星座搭配设计,在内容上以时尚、简洁、突显项目个性、户型特点为主。

通过在高档写字楼附近和以扫楼的形式大量派发,结果该传单形式大受欢迎,不仅丢失率小还有不少主动索取的客户,给项目带去了不少的意向客户。

2、扇子式:

南方夏日炎热酷暑难耐,北方客户每到南方时总被大太阳烤得汗流浃背,这时传单可以以结合地域的特点形式来进行设计和派发,从而更深受客户的喜爱。

海南房地产市场主要特点是面向岛外客户群体,每年到海南旅游的北方游客,不仅给当地的旅游业带来极大的发展,还纷纷的在沙幼水蓝的大海湾畔安下冬季度假休闲的幸福家,不仅极大的带动了房地产市场还拉动了整体的房价。

笔者在参观朋友在三亚的一个项目的时候,看到北方客户每汗流浃背的进入售楼部就靠近空调机位置吹风驱热,手拿太阳帽不停的扑扇,不仅脑海中有了一个奇思妙想,马上建议朋友针对项目靠海的地理优势,设计出独特的大海清凉系列的扇子式传单。

通过在天涯海角、南山寺、鹿回头公园、亚龙湾、三亚湾等主要旅游景点,针对游客和旅行团进行大量的派发,不仅受到游客们的欢迎,还给项目带去大量的客源,实现了项目的在同一时期比周边项目更好的销售业绩,

3、扑克牌式:

随着斗地主和升级扑克游戏的玩家群体日益庞大,扑克牌也成了大家平时消遣休闲的主要娱乐工具。

扑克牌式的传单即将项目的规划设计、优势特点、户型设计、实景照片、物业服务和环境配套等图文资料印刷在扑克牌的背面,通过平时的游戏消遣在不经意中使项目信息得到最大化的推广,同时扑克牌式的传单也易于在派发时接收和保存。

笔者一朋友在成都开发有项目,沟通中曾感叹成都人安逸享受的生活慢节奏,平日喜好麻将扑克牌娱乐,笔者当即建议其大量印制一批扑克牌式传单,免费赠送给各 馆茶室和在闹市区免费派发。

他照此进行了设计并派员进行了派发,派发一个星期后兴奋的来电告知笔者,此方法简单成本低廉但行之有效,认购时客户将售楼处挤得水泄不通,还排起了长龙。

4、节日贺卡式:

中国人好面子讲人情,礼多人不怪,节日的问候祝福总是会让人心里感到贴心和温暖。

在传统或现代的节假日,如春节、圣诞节和情人节等节庆日,印制贺卡式的传单派发,不仅不被拒接排斥,还有利于增加接收者对公司和项目的好感度,软化推销的硬性特点,从而使接收者在不知不觉中拉近和推荐项目的距离,进而更好的接收项目宣传的信息。

5、小年历式:

将传单设计成便于查询的全年年历,不仅实用性强,接收后保存时间长,而且在派发时不易受到拒绝,特别适合在过年前后派发使用,是种非常实用的传单形式。

根据年历版面的大小,设计以项目宣传还是公司的品牌形象宣传为主题的内容,宣传的有效期在接收者的手中长达一年之久。

6、优惠券式:

此种传单形式一般是在短期的促销活动开展时使用较多,过多使用会影响项目宣传的品质,给人以无人问津只好以优惠的形式销售的感觉,所以在使用时要注意使用。

可根据促销活动的特点,推出如“持单抵XXXX元房款”、“持单每平米送XXX元精装修”和“持单享受赠送XX平米面积”等的优惠。

优惠券式传单的特点是将优惠内容和联系方式重点介绍突出,优惠内容应具有极强的鼓动性,使人阅后有占了大便宜想一探究竟甚至是购买的冲动,还应注意的是一定要标明活动的有效期限,以免给人误会活动为长期进行,导致在活动结束后还出现客户持单在售楼处理论是非的尴尬局面,最后别忘了注明一句“活动解释权归开发商所有”,看似简单但其实可以化解很多不必要的纠缠或法律纠纷。

篇10:HibernateHQL语句使用总结

1. 查询整个映射对象所有字段

//直接from查询出来的是一个映射对象,即:查询整个映射对象所有字段 String hql = “from Users”; Query query = session.createQuery(hql); Listusers = query.list;for(Users user : users){ System.out.println(user.getName() + “ : ” + user.getPasswd() + “ : ” + user.getId()); } 输出结果为: name1 : password1 : 1 name2 : password2 : 2 name3 : password3 : 3

2.查询字段

//查询其中几个字段 String hql = “ select name,passwd from Users”; Query query = session.createQuery(hql); //默认查询出来的list里存放的是一个Object数组 Listlist = query.list(); for(Object[] object : list){ String name = (String)object[0]; String passwd = (String)object[1]; System.out.println(name + “ : ” + passwd); } 输出结果为:name1 : password1 name2 : password2 name3 : password3

3.修改默认查询结果(query.list())不以Object[]数组形式返回,以List形式返回

//查询其中几个字段,添加new list(),注意list里的l是小写的,

HibernateHQL语句使用总结

。也不需要导入包,这样通过query.list()出来的list里存放的不再是默认的Object数组了,而是List集合了 String hql = “ select new list(name,passwd) from Users”; Query query = session.createQuery(hql); //默认查询出来的list里存放的是一个Object数组,但是在这里list里存放的不再是默认的Object数组了,而是List集合了 List list = query.list(); for(List user : list){ String name = (String)user.get(0); String passwd = (String)user.get(1); System.out.println(name + “ : ”+ passwd); } /** 输出结果为: name1 : password1 name2 : password2 name3 : password3 */

4.修改默认查询结果(query.list())不以Object[]数组形式返回,以Map形式返回

//查询其中几个字段,添加new map(),注意map里的m是小写的。也不需要导入包,这样通过query.list()出来的list里存放的不再是默认的Object数组了,而是map集合了 String hql = “ select new map(name,passwd) from Users”; Query query = session.createQuery(hql); //默认查询出来的list里存放的是一个Object数组,但是在这里list里存放的不再是默认的Object数组了,而是Map集合了 List

list = query.list(); for(Map user : list){ //一条记录里所有的字段值都是map里的一个元素,key是字符串0,1,2,3....,value是字段值 //如果将hql改为:String hql = “ select new map(name as username,passwd as password) from Users”;,那么key将不是字符串0,1,2...了,而是“username”,“password”了 String name = (String)user.get(“0”);//get(“0”);是get(key),注意:0,1,2...是字符串,而不是整形 String passwd = (String)user.get(“1”);System.out.println(name + “ : ” + passwd); } /** 输出结果为: name1 : password1 name2 : password2 name3 : password3 */    5.修改默认查询结果(query.list())不以Object[]数组形式返回,以自定义类型返回    6.条件查询//条件查询,参数索引值从0开始,索引位置,电脑资料通过setString,setParameter设置参数 String hql =“from Users where name=? and passwd=?”; Query query = session.createQuery(hql); //第1种方式 // query.setString(0, “name1”); // query.setString(1, “password1”); //第2种方式query.setParameter(0, “name1”,Hibernate.STRING); query.setParameter(1,“password1”,Hibernate.STRING); Listlist = query.list(); for(Users users : list){System.out.println(users.getId()); }//条件查询,自定义索引名(参数名):username,:password.通过setString,setParameter设置参数String hql = “from Users where name=:username and passwd=:password”; Query query = session.createQuery(hql); //第1种方式 // query.setString(“username”, “name1”); // query.setString(“password”, “password1”); //第2种方式,第3个参数确定类型query.setParameter(“username”, “name1”,Hibernate.STRING); query.setParameter(“password”,“password1”,Hibernate.STRING); Listlist = query.list(); for(Users users : list){System.out.println(users.getId()); }//条件查询,通过setProperties设置参数 String hql = “from Users where name=:username and passwd=:password”; Query query = session.createQuery(hql); //MyUser类的2个属性必须和:username和:password对应 MyUser myUser = new MyUser(“name1”,“password1”);query.setProperties(myUser); Listlist = query.list(); for(Users users : list){System.out.println(users.getId()); }

7.update 数据

执行SQL语句(为什么要用SQL语句,我想是为了执行某些复杂的SQL语句吧)

String sql=“update Table set field = 'test'” Session session = HibernateSessionFactory.getSession(); session.createSQLQuery(sql).executeUpdate();ts.commit();

执行HQL语句

String hql=“update Table set field = 'test'”Session session = HiberanteSessionFactory.getSession(); Transaction ts = session.beginTransaction(); Query query = session.createQuery(hql); query.executeUpdate();ts.commit();

篇11:班班通使用总结

8月24-25日本人参加了在实验中学举行的“班班通电子白板培训”, 虽然这次培训的时间很短,但对我来说受益匪浅,充分认识到了现代教育教学媒体的特点和重要性。培训使教师的眼界开阔了、思考问题的角度改变了,许多疑问得到了解决或者启发。当然,还会有很多的不解和困惑,下面就此次培训活动总结如下:

一、培训有序 学有所获

培训过程中,我倾听认真,积极投入。通过培训老师的实际操作、演示、介绍之后组织了相互交流等环节的学习,使我长了许多见识,教学思路灵活了,兴趣浓了,对自己的教学也有了新的目标和方向。为教学进一步提升奠定了基础。

1、电子白板在传统黑板的基础上更胜一筹

电子白板具有替代黑板的功能:与黑板相同的书写、绘画和擦除功能,这些功能很大程度上已使白板替代了黑板的使用;部分特殊效果的简单使用:如拉幕、探照灯、拍照等,这些功能简单易学。此功能的应用,使老师们心中会有安全感,可以保证课程按照自己原有已习惯的方法进行,不会出现大问题。更有老师当时就提出,电子白板比黑板好,减少了老师和学生受粉笔灰污染的机会。

2、电子白板便于记录保存教学过程

利用“互动式电子白板”,可以将老师在电子白板上所书写的全部内容完整记录并保存,课后可以即时打印输出,作为笔记保留。同时将教师的授课内容及讲课录音合成记录到网站上,使学生在不同的时间、地点都可以重温课堂内容或补习所缺课程。

总之,交互式电子白板是实现传统与现代教育结合的一款全新的、功能强大的高科技教学工具,它既继承了普通黑板这一教学手段的优点,又整合了现代多媒体教学的优势,特别是它在交互式学习、合作式学习、启发式学习等方面具有独特优势。它的多功能性为教师授课和学生学习提供了崭新的舞台,发挥交互式电子白板的辅助教学优势,将更有利于实现课堂教学方式的变革和教师自身专业化的成长。但是它毕竟只是一种工具,一种协助师生教学相长的工具。作为教师,我们需要学习的东西还很多很多,为了让我们能更好的使用电子白板,我们还应加强自身的学习!

二、加强交流,更好使用班班通

今后我们学校将结合培训知识做好以下工作:

1、在日常工作中把信息化教学作为日常教学的内容,交流学习,不断提高教师的教学能力和信息素养。

2、积极开展信息技术和学科课程整合的实践,探索适合我们学校实际的教学模式。提高学校现有资源的利用效率。

三、设备使用中的困惑

1、设备配备的书写笔质量太差,虽说可以配备无线鼠标和无线键盘进行弥补其部分功能,但是它毕竟不能完全代替书写笔,如拉幕、画图、书写等功能其他工具是无法取代的。

2、设备在不断地使用过程中往往也会出现一些意想不到的问题,如死机、不灵敏等问题,还有待于在以后的使用过程中慢慢摸索。

网络班班通工程是我市教育系统投资巨大的工程,这个工程的实施,为我们农村的孩子改善了学习的环境与条件。我们一定要好好利用这些资源,来改变我们农村教育的现状。回去以后我首先要将所学到的知识运用到我们学校,通过网络班班通使教师受益学生受益学校发展。

docker使用的个人学习总结

卡机联动加油机使用总结

培养词典使用策略加强英语词汇学习

安全学习总结

期末考试学习总结

下载GridView使用学习总结(共11篇)
GridView使用学习总结.doc
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档
点击下载本文文档