一、代码下载

代码下载地址

二、实例效果展示



imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="效果图二.png" title="">

imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="效果图三.png" title="">

三、实例项目简单介绍

这个实例主要是封装sqlite3数据库工具,并用这个工具实现记录、删除、改动、查询学生信息的功能。另外一个附属的功能就是依据学生的姓名首字母分组并加入索引。

对于数据库。我做了两层封装。

第一层是对数据库的基本操作进行抽象。第二层是对学生数据的操作进行抽象。这样的分层的思想不仅能使处于底层的功能得到多次重用,调高效率。并且这样做逻辑清晰,易于定位问题,故意于维护与跟新。

四、实例项目分析

1、首先抽象出数据库基本操作工具类,而数据库的基本操作有:打开、关闭、建表、增、删、改、查……基于这些操作,我封装出例如以下五个方法来提供数据库的操作:

 *  打开数据库
*
* @param path 数据库路径
* @param success 打开成功的回调
* @param falure 打开失败的回调
*/
+ (void)openDBPath:(NSString *)path succesefulBlock:(void (^)(sqlite3 *db))success andFailureBlock:(void (^)(NSString *msg))failure
{
sqlite3 *database = NULL;
int result = sqlite3_open(path.UTF8String, &database);
if (result == SQLITE_OK) {
if (success) {
success(database);
}
}
else
{
if (failure) {
const char *msg = sqlite3_errmsg(database);
failure([NSString stringWithUTF8String:msg]);
} if (database) {
[self closeDB:database succesefulBlock:nil andFailureBlock:nil];
}
}
} /**
* 关闭数据库
*
* @param database 数据库链接
* @param succese 成功的回调
* @param failure 失败的回调
*/
+ (void)closeDB:(sqlite3 *)database succesefulBlock:(void (^)())succese andFailureBlock:(void (^)(NSString *msg))failure
{
int result = sqlite3_close(database);
if (result == SQLITE_OK) {
if (succese) {
succese();
}
}
else
{
if (failure) {
failure([NSString stringWithUTF8String:sqlite3_errmsg(database)]);
}
}
} /**
* 运行SQL语句(不适应查询语句和blob(NSData)二进制数据类型的操作)
*
* @param sqStr SQL语句
* @param database 数据库链接
* @param succese 成功的回调
* @param failure 失败的回调
*/
+ (void)executeSql:(NSString *)sqStr toDatabase:(sqlite3 *)database succesefulBlock:(void (^)())succese andFailureBlock:(void (^)(NSString *msg))failure
{
DebugLog(@"%@", sqStr);
char *msg = NULL;
int result = sqlite3_exec(database, sqStr.UTF8String, NULL, NULL, &msg);
if (result == SQLITE_OK) {
if (succese) {
succese();
}
}
else
{
if (failure) {
failure([NSString stringWithUTF8String:msg]);
}
}
} /**
* 准备须要sqlite3_stmt结果集的SQL语句
*
* @param sqStr SQL语句
* @param database 数据库连接
* @param succese 成功的回调
* @param failure 失败的回调
*/
+ (void)prepareSql:(NSString *)sqStr fromDatabase:(sqlite3 *)database succesefulBlock:(void (^)(sqlite3_stmt *stmt))succese andFailureBlock:(void (^)(NSString *msg))failure
{
DebugLog(@"%@", sqStr);
sqlite3_stmt *stmt = NULL;
int result = sqlite3_prepare_v2(database, sqStr.UTF8String, -1, &stmt, NULL);
if (result == SQLITE_OK) {
if (succese) {
succese(stmt);
}
}
else
{
if (failure) {
failure(@"SQL语句是非法的。");
}
}
}

2、接着就是抽象学生数据功能类了。依据须要我抽象出了例如以下五个方法

/**
* 获取全部学生
*
* @param callBack 回调
*/
+ (void)getAllStudents:(void (^)(NSArray *students, NSString *msg))callBack; /**
* 加入学生
*
* @param studentModel 学生模型
* @param succese 加入成功回调
* @param failure 加入失败回调
*/
+ (void)addStudent:(StudentModel *)studentModel succesefulBlock:(void (^)(StudentModel *studentModel))succese andFailureBlock:(void (^)(NSString *msg))failure; /**
* 更新学生
*
* @param studentModel 学生模型
* @param succese 更新成功回调
* @param failure 更新失败回调
*/
+ (void)updateStudent:(StudentModel *)studentModel succesefulBlock:(void (^)(StudentModel *studentModel))succese andFailureBlock:(void (^)(NSString *msg))failure; /**
* 按条件搜索学生
*
* @param condition 条件
* @param callBack 搜索回调
*/
+ (void)searchStudents:(NSString *)condition andCallBack:(void (^)(NSArray *students, NSString *msg))callBack; /**
* 删除学生
*
* @param studentModel 学生模型
* @param succese 删除成功回调
* @param failure 删除失败回调
*/
+ (void)deleteStudent:(StudentModel *)studentModel succesefulBlock:(void (^)(StudentModel *studentModel))succese andFailureBlock:(void (^)(NSString *msg))failure;

细节分析

- 因为该功能类都是使用类方法,所以不能以实例变量来存储数据,因此声明全局变量static sqlite3 *database来存储数据库的链接。并以static关键字修饰来避免其它源文件对其訪问。

- 类方法initialize是在手动调用累中不论什么方法前调用一次,所以在这种方法中打开数据库并创建学生表是很合适的。

/**
* 在手动调用类里的不论什么方法前自己主动调用一次
*/
+ (void)initialize
{
[SqliteDBAccess openDBPath:SqlitePathStr succesefulBlock:^(sqlite3 *db) {
DebugLog(@"数据库打开成功。");
[SqliteDBAccess executeSql:[NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (identifier integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, studentNumber text NOT NULL UNIQUE, photo blob, age integer NOT NULL, address text, describe text);", StudentTableName] toDatabase:db succesefulBlock:^{
database = db;
DebugLog(@"学生表创建成功!");
} andFailureBlock:^(NSString *msg) {
DebugLog(@"学生表创建失败。%@", msg);
}];
} andFailureBlock:^(NSString *msg) {
DebugLog(@"数据库打开失败,%@", msg);
}];
}
  • 在学生数据功能类的内部能够封装一个不公开的方法来从sqlite3_stmt结果集中获取学生模型对象
/**
* 从sqlite3_stmt中获取学生数据
*
* @param stmt sqlite3_stmt结果集
*
* @return 学生数组
*/
+ (NSArray *)getStudentsFromStatement:(sqlite3_stmt *)stmt
{
NSMutableArray *students = [NSMutableArray arrayWithCapacity:1];
StudentModel *studentModel;
while (sqlite3_step(stmt) == SQLITE_ROW) {
studentModel = [[StudentModel alloc] init];
studentModel.identifier = sqlite3_column_int(stmt, 0);
char *name = (char *)sqlite3_column_text(stmt, 1);
char *studentNumber = (char *)sqlite3_column_text(stmt, 2);
void *photo = (void *)sqlite3_column_blob(stmt, 3);
studentModel.name = name ? [NSString stringWithUTF8String:name] : nil;
studentModel.studentNumber = studentNumber ? [NSString stringWithUTF8String:studentNumber] : nil;
studentModel.photo = photo ? [UIImage imageWithData:[NSData dataWithBytes:photo length:sqlite3_column_bytes(stmt, 3)]] : nil;
studentModel.age = sqlite3_column_int(stmt, 4);
char *address = (char *)sqlite3_column_text(stmt, 5);
char *describe = (char *)sqlite3_column_text(stmt, 6);
studentModel.address = address ? [NSString stringWithUTF8String:address] : nil;
studentModel.describe = describe ? [NSString stringWithUTF8String:describe] : nil; [students addObject:studentModel];
} return students;
}
  • 因为表中存在二进制数据,所以插入跟新二进制数据时使用sqlite3_exec函数运行SQL语句是有问题的,须要使用sqlite3_step函数来运行SQL语句。

/**
* 更新学生
*
* @param studentModel 学生模型
* @param succese 更新成功回调
* @param failure 更新失败回调
*/
+ (void)updateStudent:(StudentModel *)studentModel succesefulBlock:(void (^)(StudentModel *studentModel))succese andFailureBlock:(void (^)(NSString *msg))failure
{
[SqliteDBAccess prepareSql:[NSString stringWithFormat:@"UPDATE %@ SET name = ?, studentNumber = ?, photo = ?, age = ?, address = ?, describe = ? WHERE identifier = ?;", StudentTableName] fromDatabase:database succesefulBlock:^(sqlite3_stmt *stmt) {
NSData *data = UIImagePNGRepresentation(studentModel.photo);
sqlite3_bind_text(stmt, 1, studentModel.name.UTF8String, -1, NULL);
sqlite3_bind_text(stmt, 2, studentModel.studentNumber.UTF8String, -1, NULL);
sqlite3_bind_blob(stmt, 3, [data bytes], (int)[data length], NULL);
sqlite3_bind_int(stmt, 4, studentModel.age);
sqlite3_bind_text(stmt, 5, studentModel.address.UTF8String, -1, NULL);
sqlite3_bind_text(stmt, 6, studentModel.describe.UTF8String, -1, NULL);
sqlite3_bind_int(stmt, 7, studentModel.identifier);
//运行完毕
if (sqlite3_step(stmt) == SQLITE_DONE) {
if (succese) {
succese(studentModel);
}
}
else
{
if (failure) {
failure([NSString stringWithFormat:@"更新学生失败。%@", [NSString stringWithUTF8String:sqlite3_errmsg(database)]]);
}
} //在遍历完结果集后,调用sqlite3_finalize以释放和预编译的语句相关的资源。 sqlite3_finalize(stmt);
} andFailureBlock:^(NSString *msg) {
if (failure) {
failure([NSString stringWithFormat:@"更新学生失败。%@", msg]);
}
}];
}

五、问题与补充

1.sqlite3事务:是并发控制的基本单位。所谓的事务。它是一个操作序列,这些操作要么都运行。要么都不运行,它是一个不可切割的工作单位。比如,银行转账工作:从一个账号扣款并使还有一个账号增款,这两个操作要么都运行,要么都不运行。所以,应该把它们看成一个事务。事务是数据库维护数据一致性的单位,在每一个事务结束时,都能保持数据一致性。 针对上面的描写叙述能够看出,事务的提出主要是为了解决并发情况下保持数据一致性的问题。

事务的语句:

- 開始事物:BEGIN TRANSACTION

- 提交事物:COMMIT TRANSACTION

- 回滚事务:ROLLBACK TRANSACTION

项目中加入学生数据的时候,并没有设置identifer主键。可是主键是实用的,在插入成功后须要查出来,因此加入学生就涉及两步操作:插入数据,查询数据。并且这两个操作必须要同一时候成功才干算是学生加入成功。所以在这里,我就开启一个事务。先插入学生数据,再查询此学生数据,仅仅要有一个步骤错误发生就回滚事务,全部成功则提交事务:

/**
* 加入学生
*
* @param studentModel 学生模型
* @param succese 加入成功回调
* @param failure 加入失败回调
*/
+ (void)addStudent:(StudentModel *)studentModel succesefulBlock:(void (^)(StudentModel *studentModel))succese andFailureBlock:(void (^)(NSString *msg))failure
{
//开启事务
[SqliteDBAccess executeSql:@"BEGIN TRANSACTION" toDatabase:database succesefulBlock:^{
DebugLog(@"事务启动成功。"); [SqliteDBAccess prepareSql:[NSString stringWithFormat:@"INSERT INTO %@ (name, studentNumber, photo, age, address, describe) VALUES(?, ? , ? , ?, ?, ?);", StudentTableName] fromDatabase:database succesefulBlock:^(sqlite3_stmt *stmt) {
NSData *data = UIImagePNGRepresentation(studentModel.photo);
sqlite3_bind_text(stmt, 1, studentModel.name.UTF8String, -1, NULL);
sqlite3_bind_text(stmt, 2, studentModel.studentNumber.UTF8String, -1, NULL);
sqlite3_bind_blob(stmt, 3, [data bytes], (int)[data length], NULL);
sqlite3_bind_int(stmt, 4, studentModel.age);
sqlite3_bind_text(stmt, 5, studentModel.address.UTF8String, -1, NULL);
sqlite3_bind_text(stmt, 6, studentModel.describe.UTF8String, -1, NULL);
if (sqlite3_step(stmt) == SQLITE_DONE) {
[SqliteDBAccess prepareSql:[NSString stringWithFormat:@"SELECT * FROM %@ WHERE studentNumber = ? ;", StudentTableName] fromDatabase:database succesefulBlock:^(sqlite3_stmt *stmt) {
sqlite3_bind_text(stmt, 1, studentModel.studentNumber.UTF8String, -1, NULL);
StudentModel *model = [[self getStudentsFromStatement:stmt] firstObject];
if (studentModel) {
studentModel.identifier = model.identifier;
if (succese) {
succese(studentModel);
} //提交事务
[SqliteDBAccess executeSql:@"COMMIT TRANSACTION" toDatabase:database succesefulBlock:^{
DebugLog(@"提交事务成功!");
} andFailureBlock:^(NSString *msg) {
DebugLog(@"提交事务失败:%@", msg);
}];
}
else
{
//回滚事务
[SqliteDBAccess executeSql:@"ROLLBACK TRANSACTION" toDatabase:database succesefulBlock:^{
DebugLog(@"回滚成功。");
} andFailureBlock:^(NSString *msg) {
DebugLog(@"回滚失败:%@", msg);
}];
} //在遍历完结果集后,调用sqlite3_finalize以释放和预编译的语句相关的资源。
sqlite3_finalize(stmt);
} andFailureBlock:^(NSString *msg) {
if (failure) {
failure(msg); //回滚事务
[SqliteDBAccess executeSql:@"ROLLBACK TRANSACTION" toDatabase:database succesefulBlock:^{
DebugLog(@"回滚成功。");
} andFailureBlock:^(NSString *msg) {
DebugLog(@"回滚失败:%@", msg);
}];
}
}];
}
else
{
if (failure) {
failure([NSString stringWithFormat:@"加入学生失败,%@", [NSString stringWithUTF8String:sqlite3_errmsg(database)]]);
}
} //在遍历完结果集后,调用sqlite3_finalize以释放和预编译的语句相关的资源。
sqlite3_finalize(stmt);
} andFailureBlock:^(NSString *msg) {
if (failure) {
failure([NSString stringWithFormat:@"加入学生失败。%@", msg]);
} //回滚事务
[SqliteDBAccess executeSql:@"ROLLBACK TRANSACTION" toDatabase:database succesefulBlock:^{
DebugLog(@"回滚成功。");
} andFailureBlock:^(NSString *msg) {
DebugLog(@"回滚失败:%@", msg);
}];
}];
} andFailureBlock:^(NSString *msg) {
DebugLog(@"事务启动失败:%@", msg);
}];
}

2.sqlite3注入漏洞:

举例:登录功能

1.用户输入登录名和密码:userName = ‘zhangsan or 1 = 1 or ” = ”’ password = ‘123456’

select * from t_user where name = ‘zhangsan or 1 = 1 or ” = ”’ and password = ‘123456’;

如此条件永远成立

解决方式:參数化查询

用?替换掉须要查询的条件

select * from t_user where name = ?

and passsword = ?

;

检查查询语句合法后。再绑定參数

sqlite3_bind_text(stmt, 1, “张三”, NULL);

3.sqlite3模糊查询:确定给定的字符串是否与指定的模式匹配。模式能够包括常规字符和通配符字符。

模式匹配过程中,常规字符必须与字符串中指定的字符全然匹配。然而,可 使用字符串的随意片段匹配通配符。与使用 = 和 != 字符串比較运算符相比,使用通配符可使 LIKE 运算符更加灵活。

- %:包括零个或很多其它字符的随意字符串。WHERE title LIKE ‘%computer%’ 将查找处于书名任何位置的包括单词 computer 的全部书名。

- _(下划线):不论什么单个字符。

WHERE au_fname LIKE ‘_ean’ 将查找以 ean 结尾的全部 4 个字母的名字(Dean、Sean 等)。

- [ ]:指定范围 ([a-f]) 或集合 ([abcdef]) 中的不论什么单个字符。WHERE au_lname LIKE ‘[C-P]arsen’ 将查找以arsen 结尾且以介于 C 与 P 之间的不论什么单个字符開始的作者姓氏,比如,Carsen、Larsen、Karsen 等。

- [^]:不属于指定范围 ([a-f]) 或集合 ([abcdef]) 的不论什么单个字符。WHERE au_lname LIKE ‘de[^l]%’ 将查找以 de 開始且其后的字母不为 l 的全部作者的姓氏。

/**
* 按条件搜索学生
*
* @param condition 条件
* @param callBack 搜索回调
*/
+ (void)searchStudents:(NSString *)condition andCallBack:(void (^)(NSArray *students, NSString *msg))callBack
{
int age = [condition intValue];
NSString *selectStr;
if (age != 0 || [condition isEqualToString:@"0"]) {
selectStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE name LIKE ? or studentNumber LIKE ? or age LIKE ? ;", StudentTableName];
}
else
{
selectStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE name LIKE ? or studentNumber LIKE ?;", StudentTableName];
}
[SqliteDBAccess prepareSql:selectStr fromDatabase:database succesefulBlock:^(sqlite3_stmt *stmt) {
sqlite3_bind_text(stmt, 1, [NSString stringWithFormat:@"%%%@%%", condition].UTF8String, -1, NULL);
sqlite3_bind_text(stmt, 2, [NSString stringWithFormat:@"%%%@%%", condition].UTF8String, -1, NULL);
if (age != 0 || [condition isEqualToString:@"0"]) {
sqlite3_bind_int(stmt, 3, age);
} if (callBack) {
callBack([self getStudentsFromStatement:stmt], @"搜索成功!");
} //在遍历完结果集后。调用sqlite3_finalize以释放和预编译的语句相关的资源。 sqlite3_finalize(stmt);
} andFailureBlock:^(NSString *msg) {
if (callBack) {
callBack(nil, msg);
}
}];
}

3.UITableView索引:

- 对数据进行分组排序

/**
* 按首字母分组排序
*
* @param sourceArr 目标数组
*
* @return 分好组的数组
*/
- (NSArray *)groupedByLetter:(NSArray *)sourceArr
{
UILocalizedIndexedCollation *collation = [UILocalizedIndexedCollation currentCollation]; //依照索引创建相应的数组
NSMutableArray *sectionsArr = [NSMutableArray arrayWithCapacity:collation.sectionTitles.count];
for (int index = 0; index < collation.sectionTitles.count; index++) {
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:1];
[sectionsArr addObject:arr];
} //设置StudentModel模型的组号。并装进相应数组中
for (StudentModel *studentModel in sourceArr) {
NSInteger section = [collation sectionForObject:studentModel collationStringSelector:@selector(name)];
studentModel.section = section;
[sectionsArr[section] addObject:studentModel];
} //对每组数据进行按名称首字母排序
NSMutableArray *resultArr = [NSMutableArray arrayWithCapacity:1];
for (NSArray *arr in sectionsArr) {
[resultArr addObject:[NSMutableArray arrayWithArray:[collation sortedArrayFromArray:arr collationStringSelector:@selector(name)]]];
} return resultArr;
}
  • 在UITableView的代理方法中设置组的标题和索引数组

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (tableView == self.tableView && [self.studentsArr[section] count] > 0) {
return [UILocalizedIndexedCollation currentCollation].sectionTitles[section];
} return nil;
}
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
if (tableView == self.tableView) {
NSMutableArray *resultArr = [NSMutableArray arrayWithCapacity:1];
for (NSArray *arr in self.studentsArr) {
if (arr.count > 0) {
NSInteger index = [self.studentsArr indexOfObject:arr];
[resultArr addObject:[UILocalizedIndexedCollation currentCollation].sectionTitles[index]];
}
}
[resultArr insertObject:UITableViewIndexSearch atIndex:0]; return resultArr;
}
else
{
return nil;
}
}
  • 在UITableView的代理方法中将索引与cell的组联系起来
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
NSInteger result = -1;
if (tableView == self.tableView) {
if (index == 0) {
[tableView scrollRectToVisible:tableView.tableHeaderView.frame animated:NO];
}
else
{
result = [[UILocalizedIndexedCollation currentCollation].sectionTitles indexOfObject:title];
}
} return result;
}

iOS之Sqlite3封装的更多相关文章

  1. ios在SQLite3基本操作

    iOS关于sqlite3操作 iPhone中支持通过sqlite3来訪问iPhone本地的数据库. 详细用法例如以下 1:加入开发包libsqlite3.0.dylib 首先是设置项目文件.在项目中加 ...

  2. 使用iOS原生sqlite3框架对sqlite数据库进行操作

    摘要: iOS中sqlite3框架可以很好的对sqlite数据库进行支持,通过面向对象的封装,可以更易于开发者使用. 使用iOS原生sqlite3框架对sqlite数据库进行操作 一.引言 sqlit ...

  3. ios对SQLite3的使用

    ios对SQLite3的使用 一.在Firefox中打开sqlite3(如果没有,选择工具->附加组件,添加即可)新建sqlite3数据库,Contacts, 建立一个members表,字段 i ...

  4. iOS蓝牙原生封装,助力智能硬件开发

    代码地址如下:http://www.demodashi.com/demo/12010.html 人工智能自1956年提出以来,一直默默无闻,近年来人工智能的发展得到重视逐渐发展起步,智能硬件.智能手环 ...

  5. iOS 瀑布流封装

    代码地址如下:http://www.demodashi.com/demo/12284.html 一.效果预览 功能描述:WSLWaterFlowLayout 是在继承于UICollectionView ...

  6. android 仿ios 对话框已封装成工具类

    对话框 在android中是一种非经常见的交互提示用户的方式,可是非常多产品狗都叫我们这些做android的仿ios,搞的我们android程序猿非常苦逼,凭什么效果老是仿ios,有没有一点情怀,只是 ...

  7. iOS关于sqlite3操作

    原文:http://hi.baidu.com/clickto/blog/item/0c6904f787c34125720eec87.html iPhone中支持通过sqlite3来访问iPhone本地 ...

  8. iOS使用sqlite3原生语法进行增删改查以及FMDB的使用

    首先要导入libsqlite3.dylib并且加入头文件#import <sqlite3.h>,在进行增删改查之前还要先把数据库搞进去. 一种方法是从外面拷贝到程序里:http://www ...

  9. iOS:转载sqlite3

     SQLITE3 使用总结 2012-08-21 13:48:28 分类: SQLite/嵌入式数据库 SQLITE3 使用总结 2009-09-16 07:36 2624人阅读 评论(10) 收藏  ...

随机推荐

  1. Java 之 Given final block not properly padded

    获取Cipher对象的时候一定要写成 Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding"); 不要写成 Cipher ci ...

  2. MVC的Filter应用小结

    一.概念定义 Filter是一种声明式编程方式,在Asp.net MVC中它只能限制于Action(或它的Controller). Filter用途广泛:(1)判断登录与否或用户权限:(2)决策输出缓 ...

  3. IOS学习笔记45--UITableView性能优化

    说实话,面试的时候已经被问到几次这个问题,然后就搜索了一下,看到了这篇优化文章,感觉不错,转来日后作为一种UITableView优化的方法. 使用不透明视图.      不透明的视图可以极大地提高渲染 ...

  4. 分离链接散列表C语言实现实例

    /* hash_sep.h */ #ifndef _HASH_SEP_H #define _HASH_SEP_H #define MIN_TABLE_SIZE 5 struct list_node; ...

  5. No configuration found for the specified action解决办法(转)

    使用Struts2,配置一切正常,使用常用tag也正常,但是在使用<s:form>标记时,发现控制台总是输出警告信息, 警告信息内容如下: 警告: No configuration fou ...

  6. 算法笔记_171:历届试题 小朋友排队(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 n 个小朋友站成一排.现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友. 每个小朋友都有一个不高兴的程度.开始的 ...

  7. Starting MySQL.. ERROR! The server quit without updating PID file (/gechong/mysqldata/10-9-23-119.pid).

    配置文件修改错误了,还原一下重启服务就OK了. # /etc/init.d/mysql start

  8. WebApi 数据保护操作未成功。这可能是由于未为当前线程的用户上下文加载用户配置文件导致的。当线程执行模拟时,可能会出现此情况。","ExceptionType":"System.Security.Cryptography.CryptographicException","StackTrace

    在调用System.Security.Cryptography.ProtectedData.Protect方法来保护私密信息时,IIS可能会报以下错误:CryptographicException: ...

  9. oracle 多字段去重查询

      oracle 多字段去重查询 CreationTime--2018年6月29日15点11分 Author:Marydon 1.情景展示 需要对表BASE_MRI_DEVICE的COMPNAME.F ...

  10. KNOCKOUTJS DOCUMENTATION-绑定(BINDINGS)-自定义绑定

    除了ko内建的绑定,还可以自定义绑定,灵活地封装复杂的行为使之可重用. 自定义绑定 注册自定义绑定 向 ko.bindingHandles添加一个子属性来注册一个绑定. ko.bindingHandl ...