一、代码下载

代码下载地址

二、实例效果展示



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. C#中相关结构的用法及用途

    C#中Dictionary的用法及用途 http://www.cnblogs.com/linzheng/archive/2010/12/13/1904709.html C#中的Dictionary字典 ...

  2. Java从零开始学三十二(正则表达式)

    一.为什么要有正则 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆份.替换功能. 例如:现在要求判断一个字符串是否由数字组成,则可以有以下的两种做法: 不使用正则完成 使用正则完 ...

  3. Android OpenGL ES(四)----调整屏幕的宽高比

    1.宽高比问题 我们如今相当熟悉这样一个事实,在OpenGL里,我们要渲染的一切物体都要映射到X轴和Y轴上[-1,1]的范围内,对于Z轴也一样.这个范围内的坐标被称为归一化设备坐标,其独立于屏幕实际尺 ...

  4. 用Python读取大文件

    通常我们在读取文件的时候,会用到read(), readline(), readlines(). 通常可能会有这样的用法: def test1(): with open("/tmp/test ...

  5. global语句(python学习手册422页)

    # -*- coding: cp936 -*- #python 27 #xiaodeng #global语句(python学习手册422页) #实际上就是一个名为__builtin__的模块,但是必须 ...

  6. iOS开发之复制字符串到剪贴板

    概述 一般有邀请复制链接需求功能,把字符串复制到系统剪贴板,供用户粘贴使用链接. 详细 代码下载:http://www.demodashi.com/demo/10714.html 一.主要思路 1.在 ...

  7. oracle-imp导入小错filesize设置

    ***********************************************声明*************************************************** ...

  8. spring.net aop 讲解

    spring.net aop几个术语: 切面:针对类 切点:针对方法 object.xml <?xml version="1.0" encoding="utf-8& ...

  9. 【LeetCode】24. Swap Nodes in Pairs (3 solutions)

    Swap Nodes in Pairs Given a linked list, swap every two adjacent nodes and return its head. For exam ...

  10. 【LeetCode】154. Find Minimum in Rotated Sorted Array II (3 solutions)

    Find Minimum in Rotated Sorted Array II Follow up for "Find Minimum in Rotated Sorted Array&quo ...