D19:数据库:SQLite, 数据库的工作, EGORefresh

目录

一. 数据库的介绍

  1. 常用的数据库
  2. 数据库存储数据的形式
  3. 表的操作

二. sqlite3(FMDatabase)

  1. 始建导航, 在视图控制器中创建tableView
  2. 开创模型类
  3. 创立数据库管理的单例类, 其中富含”开首化数据库对象”的法门
  4. 增: 向数据库中添加一条数据
  5. 查: 查询数据
  6. 改: 修改数据
  7. 左滑删除

三. 数据库的业务(Transaction)

  • 一个数据库事务平日包含了一个连串的对数据库的读/写操作。它的存在包含有以下四个目标:
  • ACID性质
  1. 假如我们要向数据库中加上10000条简单多少
  1. 是不是使用Transaction
  2. 行使工作的测试耗时为0.1s左右, 未使用工作的耗时约为30s

四. EGORefresh

在Day15的爱限免项指标”LimitFreeController.m”中添加上拉下拉刷新效能


一. 数据库的介绍

数据库是用来储存数据的文件
在尚未网络的状态下, 需要出示数据, 在客户端本地加一个数据库文件,
用来囤积数据到地头
数据库文件存储的数额绝对相比较多, 数据的团伙更有规律, 操作起来更有利于

  1. ##### 常用的数据库

客户端: SQLite3
服务器: Oracle(Sun), Sybase, SQLserver, MySQL, DB2

  1. ##### 数据库存储数据的法门

表(table): 用来储存同类数据, 平常对应一个模型类
记录: 表格中的一行

  1. ##### 表的操作

    • 创设表格:
      create table student (name varchar(255), age integer);
      报表名字:student
      报表中有两个字段, 字段名字是name和age
      字段类型:name类型varchar(255) -> 字符串 age类型integer
      -> int
    • 增:
      insert into student(name,age) values(“张三”,30)
    • 删:
      delete from student where name = “张三”
    • 改:
      update student set age=40 where name = “张三”
    • 查:
      select * from student where name = “张三”

二. sqlite3(FMDatabase)

sqlite3数据库文件是C语言, 使用起来相比麻烦
FMDatabase 用对象的不二法门来操作数据库(需要采用非ARC编译,
链接libsqlite3.dylib)

  1. ##### 创制导航, 在视图控制器中创设tableView

  2. ##### 创立模型类

  3. ##### 创制数据库管理的单例类, 其中含有”起头化数据库对象”的法门

    • DBManager.m

        #import "DBManager.h"
        #import "FMDatabase.h"
      
        @implementation DBManager
        {
            // 数据库对象
            FMDatabase *_database;
        }
      
        // 获取单例
        + (DBManager *)sharedInstance
        {
            static DBManager *manager = nil;
      
            @synchronized(self) {
                if (nil == manager) {
                    manager = [[DBManager alloc] init];
                }
            }
            return manager;
        }
      
        // 重新实现初始化方法
        - (instancetype)init
        {
            self = [super init];
            if (self) {
                // 初始化数据库对象
                [self createDataBase];
            }
            return self;
        }
      
        // 初始化数据库对象
        - (void)createDataBase
        {
            NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/user.db"];
            NSLog(@"path: %@", path);
            // 1. 初始化数据库对象
            _database = [[FMDatabase alloc] initWithPath:path];
            // 2. 打开数据库
            BOOL ret = [_database open];
            if (!ret) {
                NSLog(@"数据库打开失败");
            } else {
                // 成功打开数据库
                // 创建表
        #warning  if not exists
                // if not exists     表格不存在时才创建
                // primary key      表示是主键, 主键的值唯一
                // autoincrement    主键值会自动增长, 不需要代码设置值
                NSString *createSql = @"create table if not exists user(userId integer primary key autoincrement,username varchar(255),age integer,headImage blob)";
      
                BOOL flag = [_database executeUpdate:createSql];
                if (!flag) {
                    NSLog(@"创建表失败: %@", _database.lastErrorMessage);
                }
      
            }
        }
      
  4. ##### 增: 向数据库中添加一条数据

    • DBManager.m

      • (void)addUserModel:(UserModel *)model
        {
        // sql
        // “?”: 占位符, 表示需要一个参数
        NSString *insertSql = @”insert into
        user(username,age,headImage) values (?,?,?)”;
        // 数据库存储图片的是二进制类型
        NSData *data = UIImagePNGRepresentation(model.headImage);
        BOOL ret = [_database executeUpdate:insertSql, model.username,
        @(model.age), data];
        if (!ret) {
        NSLog(@”添加记录退步: %@”, _database.lastErrorMessage);
        }
        }
    • DetailViewController.m中点击按钮”保存”调用的点子

      • (void)saveAction:(id)sender
        {
        // 获取对象属性值内容
        UserModel *model = [[UserModel alloc] init];
        model.username = _nameTextField.text;
        model.age = _ageTextField.text.intValue;
        #warning 获取背景图片
        sqlite,model.headImage = [_imageBtn
        backgroundImageForState:UIControlStateNormal];

            // 保存
                // 添加
                DBManager *manager = [DBManager sharedInstance];
                [manager addUserModel:model];
        }
        
  5. ##### 查: 查询数据

    • DBManager.m

      • (NSArray *)searchAllUsers
        {
        // sql
        // select * from user where userId = 10;
        NSString *selectSql = @”select * from user”;

            // 执行查询操作
            FMResultSet *rs = [_database executeQuery:selectSql];
        
            // 遍历结果集里面的数据, 放到数组中
            NSMutableArray *array= [NSMutableArray array];
            while ([rs next]) {
                // 获取当前的这一条记录
                // 创建对象
                UserModel *model = [[UserModel alloc] init];
                model.userId = [rs intForColumn:@"userId"];
                model.username = [rs stringForColumn:@"username"];
                model.age = [rs intForColumn:@"age"];
        
                // 头像(图片的二进制数据)
                NSData *data = [rs dataForColumn:@"headImage"];
                model.headImage = [UIImage imageWithData:data];
        
                [array addObject:model];
            }
            return array;
        }  
        
    • ViewController.m

      • (void)viewWillAppear:(BOOL)animated
        {
        [super viewWillAppear:animated];

            // 查询数据
            NSArray *array = [[DBManager sharedInstance] searchAllUsers];
        
            _dataArray = [NSMutableArray arrayWithArray:array];
        
            // 刷新表格
            [self.tableView reloadData];
        }  
        
  6. ##### 改: 修改数据

    • DBManager.m

      • (void)updateUserId:(int)userId model:(UserModel *)model
        {
        // 判断数据是否留存
        BOOL flag = [self isUserExists:userId];
        if (flag == 0) {
        NSLog(@”数据不存在”);
        return;
        }

            // sql
            NSString *sql = @"update user set username=?,age=?,headImage=? where userId=?";
            // 修改
            NSData *data = UIImagePNGRepresentation(model.headImage);
            BOOL ret = [_database executeUpdate:sql,model.username,@(model.age),data,@(userId)];
            if (!ret) {
                NSLog(@"修改数据失败: %@", _database.lastErrorMessage);
            }
        }
        
        // 判断一条记录是否存在
        - (BOOL)isUserExists:(int)userId
        {
            // sql
            NSString *sql = @"select * from where userId=?";
            FMResultSet *rs = [_database executeQuery:sql, @(userId)];
        
            if ([rs next]) {
                return YES;
            }
        
            return NO;
        }  
        
    • DetailViewController.h中添加属性
      @property (nonatomic, strong) UserModel *model;
      在DetailViewController.m中:

      • (void)viewDidLoad {
        ………………………………………………
        // 假使是修改界面
        if (self.model) {
        _nameTextField.text = self.model.username;
        _ageTextField.text = [NSString stringWithFormat:@”%d”,
        self.model.age];
        [_imageBtn setBackgroundImage:self.model.headImage
        forState:UIControlStateNormal];
        }
        }

      • 保存按钮调用的法门需要修改

        • (void)saveAction:(id)sender
          {
          ………………………………………………

              // 保存
              if (self.model) {
                  // 修改
                  [[DBManager sharedInstance] updateUserId:self.model.userId model:model];
              } else {
                  // 添加
                  DBManager *manager = [DBManager sharedInstance];
                  [manager addUserModel:model];
              }
          }
          
    • ViewController.m

      • (void)tableView:(UITableView *)tableView
        didSelectRowAtIndexPath:(NSIndexPath *)indexPath
        {
        // 进入修改界面
        DetailViewController *dCtrl = [[DetailViewController alloc]
        init];
        dCtrl.model = self.dataArray[indexPath.row];
        [self.navigationController pushViewController:dCtrl
        animated:YES];
        }
  7. ##### 左滑删除

    • DBManager.m中

        // 删除一条数据
        - (void)deleteUserId:(int)userId
        {
            // sql
            NSString *deleteSql = @"delete from user where userId = ?";
      
            // 执行删除操作
            BOOL ret = [_database executeUpdate:deleteSql, @(userId)];
            if (!ret) {
                NSLog(@"删除数据失败: %@", _database.lastErrorMessage);
            }
        }
      
    • ViewController.m中

        // 左滑删除
        - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
        {
            // 数据库删除
            UserModel *model = self.dataArray[indexPath.row];
            [[DBManager sharedInstance] deleteUserId:model.userId];
      
            // 删除数据
            [_dataArray removeObjectAtIndex:indexPath.row];
      
            [_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        }
      

三. 数据库的政工(Transaction)

摘录自维基百科

1. 一个数据库事务平日包含了一个序列的对数据库的读/写操作。它的留存包含有以下多少个目标:

  1. 为数据库操作连串提供了一个从失败中回复到健康状态的章程,同时提供了数据库固然在特别情状下仍是可以保全一致性的艺术。
  1. 当六个应用程序在产出访问数据库时,可以在这么些应用程序之间提供一个割裂措施,以防范互相的操作相互烦扰。

当工作被提交给了DBMS(数据库管理连串),则DBMS(数据库管理连串)需要保证该工作中的所有操作都事业有成做到且其结果被永久保存在数据库中,假如工作中有的操作没有中标做到,则事务中的所有操作都亟待被回滚,回到工作执行前的事态;同时,该业务对数据库或者此外作业的实施无影响,所有的政工都类似在单身的周转。

但在现实情形下,战败的高风险很高。在一个数据库事务的举办过程中,有可能会遇上作业操作败北、数据库系统/操作系统失利,甚至是存储介质失利等状态。这便需要DBMS对一个进行破产的事务执行恢复生机操作,将其数据库状态復苏到平等状态(数据的一致性得到保证的情形)。为了促成将数据库状态恢复生机到同样状态的效用,DBMS平日需要维护工作日志以追踪工作中有所影响数据库数据的操作。

2. ACID性质

毫不自由的对数据库的操作序列都是数据库事务。数据库事务有着以下五个特性,习惯上被称之为ACID特性。

  1. 原子性(Atomicity):事务作为一个完整被实践,包含在里头的对数据库的操作依然全体被执行,要么都不举行。
  1. 一致性(Consistency):事务应确保数据库的情况从一个一律状态转变为另一个一致状态。一致状态的意义是数据库中的数据应满意完整性约束。

  2. 隔离性(Isolation):多少个工作并发执行时,一个工作的实践不应影响另外作业的实践。

  3. 持久性(Durability):已被交付的业务对数据库的修改应该永久保存在数据库中。

  4. ##### 假如我们要向数据库中添加10000条简单多少

         #import "ViewController.h"
         #import "FMDatabase.h"
    
         @interface ViewController ()
         {
             FMDatabase *_database;
         }
    
         @end
    
         @implementation ViewController
    
         - (void)viewDidLoad {
             [super viewDidLoad];
             // Do any additional setup after loading the view, typically from a nib.
    
             //数据库的事务
             //有时候操作很多条sql语句时,会执行很长的时间,我们把这些语句放到一个事务中,可以提高效率
    
             NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/test.db"];
             _database = [[FMDatabase alloc] initWithPath:path];
    
             BOOL flag = [_database open];
             if (!flag) {
                 NSLog(@"打开数据库失败");
             }else{
                 //创建表
                 NSString *sql = @"create table if not exists user(username varchar(255),age integer)";
    
                 BOOL ret = [_database executeUpdate:sql];
                 if (!ret) {
                     NSLog(@"创建表失败");
                 }
             }
    
            // 插入数据(transaction)
            NSDate *date1 = [NSDate date];
            [self insertDataWithNum:10000 isUseTransaction:YES];
    
            NSDate *date2 = [NSDate date];
    
            NSTimeInterval time = [date2 timeIntervalSinceDate:date1];
            NSLog(@"%lf", time);
    
            // 插入数据(非transaction)
            NSDate *date3 = [NSDate date];
            [self insertDataWithNum:10000 isUseTransaction:NO];
    
            NSDate *date4 = [NSDate date];
    
            NSTimeInterval time2 = [date4 timeIntervalSinceDate:date3];
            NSLog(@"%lf", time2);
        }
    
  5. ##### 是否利用Transaction

     /*
      @param num:插入的条数
      @param useTransaction:是否使用事物
      */
     - (void)insertDataWithNum:(int)num isUserTransaction:(BOOL)useTransaction
     {
         if (useTransaction) {
    
             //使用事物
             BOOL isError = NO;
    
             @try {
                 //开启事物
                 [_database beginTransaction];
    
                 //执行插入操作
                 for (int i=0; i<num; i++) {
    
                     NSString *name = [NSString stringWithFormat:@"第%d个用户",i];
                     int age = arc4random()%20+20;
    
                     NSString *insertSql = @"insert into user (username,age) values (?,?)";
    
                     BOOL ret = [_database executeUpdate:insertSql,name,@(age)];
                     if (!ret) {
                         NSLog(@"%@",_database.lastErrorMessage);
                     }
                 }
             }
             @catch (NSException *exception) {
                 //出错
                 isError = YES;
    
                 //回滚
                 [_database rollback];
             }
             @finally {
    
                 if (!isError) {
                     //提交事物
                     NSLog(@"success");
                     [_database commit];
                 }
             }
         }else{
    
             //不使用事物
             for (int i=0; i<num; i++) {
    
                 NSString *name = [NSString stringWithFormat:@"第%d个用户",i];
                 int age = arc4random()%20+20;
    
                 NSString *insertSql = @"insert into user (username,age) values (?,?)";
    
                 BOOL ret = [_database executeUpdate:insertSql,name,@(age)];
                 if (!ret) {
                     NSLog(@"%@",_database.lastErrorMessage);
                 }
             }
         }
     }
    
     @end  
    
  6. ##### 使用工作的测试耗时为0.1s左右, 未使用工作的耗时约为30s


四. EGORefresh

  • ##### 在Day15的爱限免项目标”LimitFreeController.m”中添加上拉下拉刷新功效

      @interface LimitFreeController () <…………………………………………………………, EGORefreshTableDelegate>   
    
      …………………………………………………………
      // 下拉刷新
      @property (nonatomic, strong) EGORefreshTableHeaderView *headView;
      @property (nonatomic, strong) EGORefreshTableFooterView *footView;
      @property (nonatomic, assign) NSInteger curPage;
      // 是否正在加载
      @property (nonatomic, assign) BOOL isLoading;
    
      @end
    
      @implementation LimitFreeController
    
      - (void)viewDidLoad {
          …………………………………………………………    
          _curPage = 1;
      }
    
      - (void)downloadData
      {
          self.isLoading = YES;
    
          NSURLConnection *conn = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:kUrl, self.curPage]]] delegate:self];
          // 遵守协议, 实现方法
      }
    
      // 创建表格视图
      - (void)createTableView
      {
          …………………………………………………………      
    
          // 下拉刷新
          _headView = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0, -_tbView.bounds.size.height, _tbView.bounds.size.width, _tbView.bounds.size.height)];
          _headView.delegate = self;
          [_tbView addSubview:self.headView];
          _footView = [[EGORefreshTableFooterView alloc] initWithFrame:CGRectZero];
          _footView.delegate = self;
          [self.tbView addSubview:self.footView];
      }
    
      // 修改footer的frame
      - (void)resetFooterFrame
      {
          CGFloat height = MAX(self.tbView.bounds.size.height, self.tbView.contentSize.height);
    
          self.footView.frame = CGRectMake(0, height, self.tbView.bounds.size.width, 0);
      }
    
      - (void)viewDidAppear:(BOOL)animated
      {
          [super viewDidAppear:animated];
    
          [self resetFooterFrame];
      }
    
      #pragma mark - EGORefreshTable代理
      - (BOOL)egoRefreshTableDataSourceIsLoading:(UIView *)view
      {
          return self.isLoading;
      }
    
      - (NSDate *)egoRefreshTableDataSourceLastUpdated:(UIView *)view
      {
          return [NSDate date];
      }
    
      // 触发刷新数据的操作
      - (void)egoRefreshTableDidTriggerRefresh:(EGORefreshPos)aRefreshPos
      {
          if (aRefreshPos == EGORefreshHeader) {
              // 下拉刷新
              self.curPage = 1;
    
              [self downloadData];
          } else if (aRefreshPos == EGORefreshFooter) {
              // 上拉
              self.curPage++;
    
              [self downloadData];
          }
      }
    
      - (void)scrollViewDidScroll:(UIScrollView *)scrollView
      {
          [self.headView egoRefreshScrollViewDidScroll:scrollView];
          [self.footView egoRefreshScrollViewDidScroll:scrollView];
      }
    
      - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
      {
          [self.headView egoRefreshScrollViewDidEndDragging:scrollView];
          [self.footView egoRefreshScrollViewDidEndDragging:scrollView];
      }
    
      …………………………………………………………      
      …………………………………………………………      
      …………………………………………………………     
    
      // 下载结束调用
      - (void)connectionDidFinishLoading:(NSURLConnection *)connection
      {
          // 处理下载数据
          // JSON解析
    
          if (self.curPage == 1) {
              [self.dataArray removeAllObjects];
          }
    
          …………………………………………………………     
          [self.tbView reloadData];
    
          [self.headView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tbView];
          [self.footView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tbView];
          [self resetFooterFrame];
    
          self.isLoading = NO;
      }
    
      @end
    
网站地图xml地图