sqliteD19:数据库: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 获取背景图片
        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地图