mysql

Пример разработки для СУБД MySQL

Почему MySQL

Входит в состав серверов WAMP, AppServ, LAMP и в портативные сборки серверов Денвер, XAMPP. Обычно MySQL используется в качестве сервера, к которому обращаются локальные или удалённые клиенты, однако в дистрибутив входит библиотека внутреннего сервера, позволяющая включать MySQL в автономные программы.

MySQL является собственностью компании Oracle Corporation, получившей её вместе с поглощённой Sun Microsystems, осуществляющей разработку и поддержку приложения. Распространяется под GNU General Public License или под собственной коммерческой лицензией. Возможно именно по этой причине, вы не обнаружите в составе Mac OS Lion сервера MySQL, который был заменен на свободно распространяемый PostreSQL. Тем не менее, популярность данной СУБД, особенно в составе WEB серверов, может повлиять на необходимость написание клиентского приложения, использующего связь с сервером MySQL.

Итак, если в составе Вашей Mac OS X не установлен сервер MySQL, то скачайте и установите его с официального сайта ORACLE > MySQL, в качестве альтернативы, можно использовать MySQL сервер, входящий в состав MAMP (Очень удобное серверное приложение, для WEB разработки под Mac).

Чтобы иметь возможность использовать MySQL C API, необходимо также скачать с официального сайта ORACLE > MySQL > Connector/C коннектор с библиотеками для xcode под C. В состав коннектора входят библиотеки для подключения, расположены в папке /lib, а также заголовочные файлы в папке /include.

Определяемся, какую библиотеку (статическую или динамическую) будем использовать для связи с сервером. В случае статической добавляем к проекту libmysqlclient.a, в случае динамической libmysql.16.dylib.

Внимание! При динамическом связывании система будет искать libmysql.16.dylib по стандартным путям хранения динамических библиотек (/usr/lib), соответственно, данную библиотеку необходимо поместить в данную папку, а при распространении придется ее включать в состав дистрибутива и инсталировать при инсталяции приложения, до первого его запуска. При использовании коннектора несколькими приложениями это имеет прямой смысл, при однократном использовании или желании установки приложения простым перетаскиванием пакета в папку (Application) имеет смысл статическое связывание.

Добавляем к проекту в Framework выбранную библиотеку:

mysql framework

Далее для удобства методом Drag'n'drop перетаскиваем в инспектор файлов проекта файл "mysql.h" из каталога /include.

mysql.h

Теперь создадим класс обертку для методов mysql для подключения к базе данных.

Листинг mbMysqlDB.h

#import <Foundation/Foundation.h>
#import "mysql.h"

@interface mbMysqlDB : NSObject
{
  MYSQL* mysql;
  NSString* lastError;
}

- (void)connect; // Соединение с БД
- (void)mysqlError; // Вывод ошибки в консоль и сохранение в  *lastError
- (void)disconnect; // Отключение от БД
- (NSString*) r_escape:(NSString*)s; // Экранирование символов для SQL запросов
- (NSInteger) autoincrementID; // Получение последнего значения вставки Autoincriment
- (BOOL) connected; // Тест на соединение
- (void) errorMessage; // Вывод на экран NSAlert c последней ошибкой

@property (copy)NSString* socket;
@property (copy)NSString* serverName;
@property (copy)NSString* dbName;
@property NSInteger port;
@property (copy)NSString* userName;
@property (copy)NSString* password;
@property (readonly)MYSQL* mysql;
@end

Листинг mbMysqlDB.m

#import "mbMysqlDB.h"
@implementation mbMysqlDB

@synthesize socket;
@synthesize serverName;
@synthesize dbName;
@synthesize port;
@synthesize userName;
@synthesize password;
@synthesize mysql;

- (id)init
{
  self = [super init];
  if (self) {
    if (mysql_library_init(0, NULL, NULL)) {
      NSLog(@"База данных не подключена");
      return nil;
    }
  }
  return self;
}


- (void)finalize
{
  mysql_library_end();
}

- (void)connect
{
  mysql = mysql_init(NULL);
  const char* prms[5];
  if(socket)
    prms[0] = socket.UTF8String;
  else 
    prms[0] = NULL;
  if(serverName)
    prms[1] = serverName.UTF8String;
  else 
    prms[1] = "localhost";
  if(dbName)
    prms[2] = dbName.UTF8String;
  else 
    prms[2] = NULL;
  if(!port)
    port = 3306;
  if(userName)
    prms[3] = userName.UTF8String;
  else
    prms[3] = "root";
  if(password)
    prms[4] = password.UTF8String;
  else 
    prms[4] = "";
  if(!mysql_real_connect(mysql, prms[1], prms[3], prms[4], prms[2], port, prms[0], 0)){
    [self mysqlError];
  }
  // при использовании UTF-8
  if(mysql_set_character_set(mysql, "utf8"))
    [self mysqlError];
}

- (void)mysqlError
{
  const char* ch = mysql_error(mysql);
  if(ch){
    lastError = [NSString stringWithUTF8String:ch];
    if(lastError.length){
      NSLog(@"Ошибка подключения: %@",lastError);
      NSException* exc = [NSException exceptionWithName:@"Error MySQL database" reason:lastError userInfo:nil];
      @throw exc;
    }
  }
}

- (void)disconnect
{
  if(mysql){
    mysql_close(mysql);
    mysql = nil;
  }
}

- (NSString*) r_escape:(NSString*)s
{
  NSInteger len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  if(len){
    NSInteger l = (len<<1)+2; // максимально возможная длинна в UTF-8
    char toch[l];
    char* to = toch;
    memset(to, 0, l);
    mysql_real_escape_string(mysql, to, s.UTF8String,len);
    return [NSString stringWithUTF8String:to];
  }
  return s;
}

- (NSInteger) autoincrementID
{
  NSInteger result = mysql_insert_id(mysql);
  return result;
}

- (BOOL) connected
{
  if(mysql_stat(mysql))
    return YES;
  else 
    return NO;
}

- (void) errorMessage
{
  if(lastError){
    NSAlert* alert = [[NSAlert alloc] init];
    [alert addButtonWithTitle:@"OK"];
    [alert setMessageText:@"MySQL error"];
    [alert setInformativeText:lastError];
    [alert setAlertStyle:NSWarningAlertStyle];
    [alert runModal];
    lastError = nil;
  }
}
@end

Данный класс обеспечивает подключение к БД, указанной в свойстве dbName с кодировкой UTF-8.

Если вы подключаетесь к БД, работающей через MAMP, то в свойстве socket укажите путь к сокету MAMP ("/Applications/MAMP/tmp/mysql/mysql.sock"), и порт из настроек MAMP (по умолчанию 8889).

Теперь создадим класс для выполнения запросов к БД через вышеприведенный класс соединения с БД.

Листинг mbMysqlQuery.h

#import <Foundation/Foundation.h>

@class mbMysqlDB;

@interface mbMysqlQuery : NSObject
{
  mbMysqlDB* db;
  NSMutableArray* rowsArray;
  NSInteger num_fields;
}
- (id)initWithDatabase:(mbMysqlDB*)dbase; // инициализатор на базе класса mbMysqlDB
- (void)execQuery; // Выполнение запроса указанного в свойстве sql
- (NSInteger)recordCount; // кол-во строк, возвращенных после запроса
- (NSString*)stringValFromRow:(int)row Column:(int)col; // возвращает строковое значение из строки row и столбца col
- (NSInteger)integerValFromRow:(int)row Column:(int)col;//возвращает цело-численное 
                                           //значение из строки row и столбца col
- (double)doubleValFromRow:(int)row Column:(int)col; //возвращает значение с плав. точкой из строки row и столбца col

@property (copy)NSString* sql;

@end

Листинг mbMysqlQuery.m

#import "mbMysqlQuery.h"
#import "mbMysqlDB.h"

@implementation mbMysqlQuery
@synthesize sql;

- (id)initWithDatabase:(mbMysqlDB*)dbase
{
  self = [super init];
  if (self) {
    db = dbase;
    rowsArray = [NSMutableArray array];
  }
  return self;
}

-(void)execQuery
{
  [rowsArray removeAllObjects];
  num_fields = 0;
  if(mysql_query(db.mysql, sql.UTF8String))
    [db mysqlError];
  MYSQL_RES* res = mysql_use_result(db.mysql);
  if(res){
    num_fields = mysql_num_fields(res);
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(res))){
      for(NSInteger i=0;i<num_fields;i++){
        NSString* sField = [NSString stringWithUTF8String:row[i]];
        [rowsArray addObject:sField];
      }
    }
    
    mysql_free_result(res);
  }
}

- (NSInteger)recordCount
{
  NSInteger result;
  if(num_fields){
    result = rowsArray.count / num_fields;
  }
  else 
    result = 0;
  return result;
}

- (NSString*)stringValFromRow:(int)row Column:(int)col
{
  NSString* result = nil;
  if(num_fields && col < num_fields){
    NSInteger objidx = row * num_fields + col;
    result = [rowsArray objectAtIndex:objidx];
  }
  return result;
}

- (NSInteger)integerValFromRow:(int)row Column:(int)col
{
  NSString* s = [self stringValFromRow:row Column:col];
  return s.integerValue;
}

- (double)doubleValFromRow:(int)row Column:(int)col
{
  NSString* s = [self stringValFromRow:row Column:col];
  return s.doubleValue;
}
@end

Использование вышеприведенного кода:

#import "mbMysqlDB.h"
#import "mbMysqlQuery.h"
//......

mbMysqlDB* db = [[mbMysqlDB alloc] init];
db.socket = @"/Applications/MAMP/tmp/mysql/mysql.sock";
db.serverName = @"localhost";
db.dbName = @"sampledb";
db.userName = @"root";
db.password = @"12345";
db.port = 8889;
@try{
	[db connect];
  mbMysqlQuery* q = [[mbMysqlQuery alloc]initWithDatabase:db];
  q.sql = @"select * from table1 order by id";
  [q execQuery];
  NSInteger len = q.recordCount;
  for(NSInteger i=0;i<len;i++){
    NSInteger id1 = [q integerValFromRow:i Column:0];
    NSString *stringV1 = [q stringValFromRow:i Column:1];
    //... 
  }
}
@catch (NSException *exception) {
  // ...
  [db errorMessage];
}

Так-же к реализации класса mbMysqlQuery можно добавить реализацию методов возврата множества других типов данных, включая дату, время, BLOB данные.

См. также:

Работа с PostgreSQL
 
 
homeЗаметили ошибкукарта сайта  EN
   Made on a Mac