🎯 empfohlene Sammlungen
Balanced sample collections from various categories for you to explore
macOS Objective-C Datenbank - Beispiele
macOS Objective-C Datenbank-Beispiele einschließlich SQLite-CRD-Operationen, Abfragen, Transaktionen und Verbindungsverwaltung
💻 SQLite-CRD-Operationen objectivec
🟡 intermediate
⭐⭐⭐
Erstellen-, Lesen-, Aktualisieren- und Löschoperationen mit SQLite-Datenbank
⏱️ 30 min
🏷️ objectivec, macos, database, sqlite
Prerequisites:
Objective-C basics, SQLite3 framework
// macOS Objective-C SQLite CRUD Examples
// Using SQLite3 framework
#import <Foundation/Foundation.h>
#import <sqlite3.h>
// MARK: - 1. Database Connection
@interface SQLiteManager : NSObject
@property (nonatomic, assign) sqlite3 *database;
@property (nonatomic, strong) NSString *databasePath;
- (BOOL)openDatabase:(NSString *)path;
- (void)closeDatabase;
@end
@implementation SQLiteManager
- (BOOL)openDatabase:(NSString *)path {
self.databasePath = path;
int result = sqlite3_open([path UTF8String], &_database);
if (result != SQLITE_OK) {
NSLog(@"Failed to open database: %s", sqlite3_errmsg(_database));
return NO;
}
NSLog(@"Database opened: %@", path);
return YES;
}
- (void)closeDatabase {
if (_database) {
sqlite3_close(_database);
_database = NULL;
NSLog(@"Database closed");
}
}
- (void)dealloc {
[self closeDatabase];
}
@end
// MARK: - 2. Create Table
@interface TableCreator : SQLiteManager
- (BOOL)createUsersTable;
- (BOOL)createProductsTable;
@end
@implementation TableCreator
- (BOOL)createUsersTable {
NSString *sql = @`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
age INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`;
char *error = NULL;
int result = sqlite3_exec(_database, [sql UTF8String], NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to create users table: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Users table created successfully");
return YES;
}
- (BOOL)createProductsTable {
NSString *sql = @`
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL,
quantity INTEGER DEFAULT 0,
category TEXT
);
`;
char *error = NULL;
int result = sqlite3_exec(_database, [sql UTF8String], NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to create products table: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Products table created successfully");
return YES;
}
@end
// MARK: - 3. Insert Operations
@interface DataInserter : SQLiteManager
- (BOOL)insertUser:(NSString *)name
email:(NSString *)email
age:(NSInteger)age;
- (NSInteger)insertProduct:(NSString *)name
price:(double)price
quantity:(NSInteger)quantity
category:(NSString *)category;
@end
@implementation DataInserter
- (BOOL)insertUser:(NSString *)name
email:(NSString *)email
age:(NSInteger)age {
NSString *sql = @"INSERT INTO users (name, email, age) VALUES (?, ?, ?);";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare insert statement: %s", sqlite3_errmsg(_database));
return NO;
}
// Bind parameters
sqlite3_bind_text(statement, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 3, (int)age);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to insert user: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return NO;
}
NSInteger userId = (NSInteger)sqlite3_last_insert_rowid(_database);
NSLog(@"User inserted with ID: %ld", (long)userId);
sqlite3_finalize(statement);
return YES;
}
- (NSInteger)insertProduct:(NSString *)name
price:(double)price
quantity:(NSInteger)quantity
category:(NSString *)category {
NSString *sql = @"INSERT INTO products (name, price, quantity, category) VALUES (?, ?, ?, ?);";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare statement: %s", sqlite3_errmsg(_database));
return -1;
}
sqlite3_bind_text(statement, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_double(statement, 2, price);
sqlite3_bind_int(statement, 3, (int)quantity);
sqlite3_bind_text(statement, 4, [category UTF8String], -1, SQLITE_TRANSIENT);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to insert product: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return -1;
}
NSInteger productId = (NSInteger)sqlite3_last_insert_rowid(_database);
NSLog(@"Product inserted with ID: %ld", (long)productId);
sqlite3_finalize(statement);
return productId;
}
@end
// MARK: - 4. Select Operations
@interface DataSelector : SQLiteManager
- (NSArray *)getAllUsers;
- (NSDictionary *)getUserById:(NSInteger)userId;
- (NSArray *)getUsersByAge:(NSInteger)minAge;
- (NSArray *)getProductsByCategory:(NSString *)category;
@end
@implementation DataSelector
- (NSArray *)getAllUsers {
NSString *sql = @"SELECT id, name, email, age, created_at FROM users;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare select: %s", sqlite3_errmsg(_database));
return @[];
}
NSMutableArray *users = [NSMutableArray array];
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *user = [NSMutableDictionary dictionary];
[user setObject:@(sqlite3_column_int(statement, 0)) forKey:@"id"];
const char *name = (const char *)sqlite3_column_text(statement, 1);
if (name) [user setObject:[NSString stringWithUTF8String:name] forKey:@"name"];
const char *email = (const char *)sqlite3_column_text(statement, 2);
if (email) [user setObject:[NSString stringWithUTF8String:email] forKey:@"email"];
[user setObject:@(sqlite3_column_int(statement, 3)) forKey:@"age"];
[users addObject:[user copy]];
}
sqlite3_finalize(statement);
NSLog(@"Retrieved %lu users", (unsigned long)users.count);
return [users copy];
}
- (NSDictionary *)getUserById:(NSInteger)userId {
NSString *sql = @"SELECT id, name, email, age, created_at FROM users WHERE id = ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare statement: %s", sqlite3_errmsg(_database));
return nil;
}
sqlite3_bind_int(statement, 1, (int)userId);
if (sqlite3_step(statement) != SQLITE_ROW) {
NSLog(@"User not found");
sqlite3_finalize(statement);
return nil;
}
NSMutableDictionary *user = [NSMutableDictionary dictionary];
[user setObject:@(sqlite3_column_int(statement, 0)) forKey:@"id"];
const char *name = (const char *)sqlite3_column_text(statement, 1);
if (name) [user setObject:[NSString stringWithUTF8String:name] forKey:@"name"];
const char *email = (const char *)sqlite3_column_text(statement, 2);
if (email) [user setObject:[NSString stringWithUTF8String:email] forKey:@"email"];
[user setObject:@(sqlite3_column_int(statement, 3)) forKey:@"age"];
sqlite3_finalize(statement);
NSLog(@"Retrieved user: %@", user);
return [user copy];
}
- (NSArray *)getUsersByAge:(NSInteger)minAge {
NSString *sql = @"SELECT id, name, email, age FROM users WHERE age >= ? ORDER BY age ASC;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare statement: %s", sqlite3_errmsg(_database));
return @[];
}
sqlite3_bind_int(statement, 1, (int)minAge);
NSMutableArray *users = [NSMutableArray array];
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *user = [NSMutableDictionary dictionary];
[user setObject:@(sqlite3_column_int(statement, 0)) forKey:@"id"];
const char *name = (const char *)sqlite3_column_text(statement, 1);
if (name) [user setObject:[NSString stringWithUTF8String:name] forKey:@"name"];
const char *email = (const char *)sqlite3_column_text(statement, 2);
if (email) [user setObject:[NSString stringWithUTF8String:email] forKey:@"email"];
[user setObject:@(sqlite3_column_int(statement, 3)) forKey:@"age"];
[users addObject:[user copy]];
}
sqlite3_finalize(statement);
NSLog(@"Retrieved %lu users with age >= %ld", (unsigned long)users.count, (long)minAge);
return [users copy];
}
- (NSArray *)getProductsByCategory:(NSString *)category {
NSString *sql = @"SELECT id, name, price, quantity, category FROM products WHERE category = ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare statement: %s", sqlite3_errmsg(_database));
return @[];
}
sqlite3_bind_text(statement, 1, [category UTF8String], -1, SQLITE_TRANSIENT);
NSMutableArray *products = [NSMutableArray array];
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *product = [NSMutableDictionary dictionary];
[product setObject:@(sqlite3_column_int(statement, 0)) forKey:@"id"];
const char *name = (const char *)sqlite3_column_text(statement, 1);
if (name) [product setObject:[NSString stringWithUTF8String:name] forKey:@"name"];
[product setObject:@(sqlite3_column_double(statement, 2)) forKey:@"price"];
[product setObject:@(sqlite3_column_int(statement, 3)) forKey:@"quantity"];
const char *cat = (const char *)sqlite3_column_text(statement, 4);
if (cat) [product setObject:[NSString stringWithUTF8String:cat] forKey:@"category"];
[products addObject:[product copy]];
}
sqlite3_finalize(statement);
NSLog(@"Retrieved %lu products in category %@", (unsigned long)products.count, category);
return [products copy];
}
@end
// MARK: - 5. Update Operations
@interface DataUpdater : SQLiteManager
- (BOOL)updateUser:(NSInteger)userId
setName:(NSString *)name;
- (BOOL)updateUserAge:(NSInteger)userId age:(NSInteger)age;
- (BOOL)updateProductQuantity:(NSInteger)productId quantity:(NSInteger)quantity;
@end
@implementation DataUpdater
- (BOOL)updateUser:(NSInteger)userId
setName:(NSString *)name {
NSString *sql = @"UPDATE users SET name = ? WHERE id = ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare update: %s", sqlite3_errmsg(_database));
return NO;
}
sqlite3_bind_text(statement, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 2, (int)userId);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to update user: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return NO;
}
NSLog(@"Updated user %ld name to %@", (long)userId, name);
sqlite3_finalize(statement);
return YES;
}
- (BOOL)updateUserAge:(NSInteger)userId age:(NSInteger)age {
NSString *sql = @"UPDATE users SET age = ? WHERE id = ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare update: %s", sqlite3_errmsg(_database));
return NO;
}
sqlite3_bind_int(statement, 1, (int)age);
sqlite3_bind_int(statement, 2, (int)userId);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to update age: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return NO;
}
NSLog(@"Updated user %ld age to %ld", (long)userId, (long)age);
sqlite3_finalize(statement);
return YES;
}
- (BOOL)updateProductQuantity:(NSInteger)productId quantity:(NSInteger)quantity {
NSString *sql = @"UPDATE products SET quantity = ? WHERE id = ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare update: %s", sqlite3_errmsg(_database));
return NO;
}
sqlite3_bind_int(statement, 1, (int)quantity);
sqlite3_bind_int(statement, 2, (int)productId);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to update quantity: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return NO;
}
NSLog(@"Updated product %ld quantity to %ld", (long)productId, (long)quantity);
sqlite3_finalize(statement);
return YES;
}
@end
// MARK: - 6. Delete Operations
@interface DataDeleter : SQLiteManager
- (BOOL)deleteUser:(NSInteger)userId;
- (BOOL)deleteProduct:(NSInteger)productId;
- (NSInteger)deleteUsersByAge:(NSInteger)maxAge;
@end
@implementation DataDeleter
- (BOOL)deleteUser:(NSInteger)userId {
NSString *sql = @"DELETE FROM users WHERE id = ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare delete: %s", sqlite3_errmsg(_database));
return NO;
}
sqlite3_bind_int(statement, 1, (int)userId);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to delete user: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return NO;
}
NSLog(@"Deleted user %ld", (long)userId);
sqlite3_finalize(statement);
return YES;
}
- (BOOL)deleteProduct:(NSInteger)productId {
NSString *sql = @"DELETE FROM products WHERE id = ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare delete: %s", sqlite3_errmsg(_database));
return NO;
}
sqlite3_bind_int(statement, 1, (int)productId);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to delete product: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return NO;
}
NSLog(@"Deleted product %ld", (long)productId);
sqlite3_finalize(statement);
return YES;
}
- (NSInteger)deleteUsersByAge:(NSInteger)maxAge {
NSString *sql = @"DELETE FROM users WHERE age > ?;";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare delete: %s", sqlite3_errmsg(_database));
return 0;
}
sqlite3_bind_int(statement, 1, (int)maxAge);
result = sqlite3_step(statement);
if (result != SQLITE_DONE) {
NSLog(@"Failed to delete users: %s", sqlite3_errmsg(_database));
sqlite3_finalize(statement);
return 0;
}
NSInteger deletedCount = sqlite3_changes(_database);
NSLog(@"Deleted %ld users with age > %ld", (long)deletedCount, (long)maxAge);
sqlite3_finalize(statement);
return deletedCount;
}
@end
// MARK: - Main Demonstration
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"=== macOS Objective-C SQLite CRUD Examples ===\n");
SQLiteManager *manager = [[SQLiteManager alloc] init];
NSString *dbPath = @"/tmp/test_database.sqlite";
// Create and open database
if (![manager openDatabase:dbPath]) {
NSLog(@"Failed to open database");
return 1;
}
// Create tables
TableCreator *creator = (TableCreator *)manager;
[creator createUsersTable];
[creator createProductsTable];
// Insert data
DataInserter *inserter = (DataInserter *)manager;
[inserter insertUser:@"Alice"
email:@"[email protected]"
age:30];
[inserter insertUser:@"Bob"
email:@"[email protected]"
age:25];
[inserter insertUser:@"Charlie"
email:@"[email protected]"
age:35];
NSInteger productId = [inserter insertProduct:@"Laptop"
price:999.99
quantity:10
category:@"Electronics"];
[inserter insertProduct:@"Mouse"
price:25.50
quantity:50
category:@"Electronics"];
[inserter insertProduct:@"Desk"
price:450.00
quantity:5
category:@"Furniture"];
// Select data
DataSelector *selector = (DataSelector *)manager;
NSLog(@"\n--- All Users ---");
NSArray *users = [selector getAllUsers];
for (NSDictionary *user in users) {
NSLog(@" User: %@ - %@", user[@"name"], user[@"email"]);
}
NSLog(@"\n--- User by ID ---");
NSDictionary *user = [selector getUserById:1];
NSLog(@"User: %@", user);
NSLog(@"\n--- Users Age >= 30 ---");
NSArray *olderUsers = [selector getUsersByAge:30];
for (NSDictionary *u in olderUsers) {
NSLog(@" %@ (%ld years old)", u[@"name"], (long)[u[@"age"] integerValue]);
}
NSLog(@"\n--- Products in Electronics ---");
NSArray *products = [selector getProductsByCategory:@"Electronics"];
for (NSDictionary *p in products) {
NSLog(@" %@ - $%.2f (x%ld)", p[@"name"], [p[@"price"] doubleValue], (long)[p[@"quantity"] integerValue]);
}
// Update data
DataUpdater *updater = (DataUpdater *)manager;
[updater updateUserAge:1 age:31];
[updater updateProductQuantity:productId quantity:8];
// Delete data
DataDeleter *deleter = (DataDeleter *)manager;
[deleter deleteUser:2];
[deleter deleteProduct:productId];
NSInteger deleted = [deleter deleteUsersByAge:100];
NSLog(@"\nDeleted %ld users older than 100", (long)deleted);
// Close database
[manager closeDatabase];
NSLog(@"\n=== SQLite CRUD Examples Completed ===");
}
return 0;
}
💻 Transaktionen und Batch-Operationen objectivec
🔴 complex
⭐⭐⭐⭐
Datenbanktransaktionen, Batch-Einfügungen und Fehler-Rollback implementieren
⏱️ 35 min
🏷️ objectivec, macos, database, sqlite, transactions
Prerequisites:
Advanced Objective-C, SQLite3 framework
// macOS Objective-C SQLite Transactions Examples
// Using SQLite3 framework
#import <Foundation/Foundation.h>
#import <sqlite3.h>
// MARK: - 1. Transaction Manager
@interface TransactionManager : NSObject
@property (nonatomic, assign) sqlite3 *database;
- (instancetype)initWithDatabase:(sqlite3 *)database;
- (BOOL)beginTransaction;
- (BOOL)commitTransaction;
- (BOOL)rollbackTransaction;
- (BOOL)performTransaction:(BOOL (^)(void))block;
@end
@implementation TransactionManager
- (instancetype)initWithDatabase:(sqlite3 *)database {
self = [super init];
if (self) {
_database = database;
}
return self;
}
- (BOOL)beginTransaction {
char *error = NULL;
int result = sqlite3_exec(_database, "BEGIN TRANSACTION;", NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to begin transaction: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Transaction started");
return YES;
}
- (BOOL)commitTransaction {
char *error = NULL;
int result = sqlite3_exec(_database, "COMMIT;", NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to commit: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Transaction committed");
return YES;
}
- (BOOL)rollbackTransaction {
char *error = NULL;
int result = sqlite3_exec(_database, "ROLLBACK;", NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to rollback: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Transaction rolled back");
return YES;
}
- (BOOL)performTransaction:(BOOL (^)(void))block {
if (![self beginTransaction]) {
return NO;
}
BOOL success = block();
if (success) {
return [self commitTransaction];
} else {
return [self rollbackTransaction];
}
}
@end
// MARK: - 2. Batch Insert
@interface BatchInserter : NSObject
@property (nonatomic, assign) sqlite3 *database;
- (instancetype)initWithDatabase:(sqlite3 *)database;
- (BOOL)batchInsertUsers:(NSArray *)users;
- (BOOL)batchInsertProducts:(NSArray *)products;
@end
@implementation BatchInserter
- (instancetype)initWithDatabase:(sqlite3 *)database {
self = [super init];
if (self) {
_database = database;
}
return self;
}
- (BOOL)batchInsertUsers:(NSArray *)users {
TransactionManager *manager = [[TransactionManager alloc] initWithDatabase:_database];
return [manager performTransaction:^{
NSString *sql = @"INSERT INTO users (name, email, age) VALUES (?, ?, ?);";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare statement: %s", sqlite3_errmsg(_database));
return NO;
}
NSInteger successCount = 0;
for (NSDictionary *user in users) {
sqlite3_bind_text(statement, 1, [user[@"name"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [user[@"email"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 3, [user[@"age"] intValue]);
result = sqlite3_step(statement);
if (result == SQLITE_DONE) {
successCount++;
} else {
NSLog(@"Failed to insert user: %s", sqlite3_errmsg(_database));
}
sqlite3_reset(statement);
}
sqlite3_finalize(statement);
NSLog(@"Batch insert completed: %ld/%lu users inserted", (long)successCount, (unsigned long)users.count);
return successCount == users.count;
}];
}
- (BOOL)batchInsertProducts:(NSArray *)products {
TransactionManager *manager = [[TransactionManager alloc] initWithDatabase:_database];
return [manager performTransaction:^{
NSString *sql = @"INSERT INTO products (name, price, quantity, category) VALUES (?, ?, ?, ?);";
sqlite3_stmt *statement;
int result = sqlite3_prepare_v2(_database, [sql UTF8String], -1, &statement, NULL);
if (result != SQLITE_OK) {
NSLog(@"Failed to prepare statement: %s", sqlite3_errmsg(_database));
return NO;
}
NSInteger successCount = 0;
for (NSDictionary *product in products) {
sqlite3_bind_text(statement, 1, [product[@"name"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_double(statement, 2, [product[@"price"] doubleValue]);
sqlite3_bind_int(statement, 3, [product[@"quantity"] intValue]);
sqlite3_bind_text(statement, 4, [product[@"category"] UTF8String], -1, SQLITE_TRANSIENT);
result = sqlite3_step(statement);
if (result == SQLITE_DONE) {
successCount++;
} else {
NSLog(@"Failed to insert product: %s", sqlite3_errmsg(_database));
}
sqlite3_reset(statement);
}
sqlite3_finalize(statement);
NSLog(@"Batch insert completed: %ld/%lu products inserted", (long)successCount, (unsigned long)products.count);
return successCount == products.count;
}];
}
@end
// MARK: - 3. Savepoint
@interface SavepointManager : NSObject
@property (nonatomic, assign) sqlite3 *database;
- (instancetype)initWithDatabase:(sqlite3 *)database;
- (BOOL)createSavepoint:(NSString *)name;
- (BOOL)releaseSavepoint:(NSString *)name;
- (BOOL)rollbackToSavepoint:(NSString *)name;
@end
@implementation SavepointManager
- (instancetype)initWithDatabase:(sqlite3 *)database {
self = [super init];
if (self) {
_database = database;
}
return self;
}
- (BOOL)createSavepoint:(NSString *)name {
NSString *sql = [NSString stringWithFormat:@"SAVEPOINT %@;", name];
char *error = NULL;
int result = sqlite3_exec(_database, [sql UTF8String], NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to create savepoint: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Savepoint '%@' created", name);
return YES;
}
- (BOOL)releaseSavepoint:(NSString *)name {
NSString *sql = [NSString stringWithFormat:@"RELEASE SAVEPOINT %@;", name];
char *error = NULL;
int result = sqlite3_exec(_database, [sql UTF8String], NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to release savepoint: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Savepoint '%@' released", name);
return YES;
}
- (BOOL)rollbackToSavepoint:(NSString *)name {
NSString *sql = [NSString stringWithFormat:@"ROLLBACK TO SAVEPOINT %@;", name];
char *error = NULL;
int result = sqlite3_exec(_database, [sql UTF8String], NULL, NULL, &error);
if (result != SQLITE_OK) {
NSLog(@"Failed to rollback to savepoint: %s", error);
sqlite3_free(error);
return NO;
}
NSLog(@"Rolled back to savepoint '%@'", name);
return YES;
}
@end
// MARK: - 4. Atomic Updates
@interface AtomicUpdater : NSObject
@property (nonatomic, assign) sqlite3 *database;
- (instancetype)initWithDatabase:(sqlite3 *)database;
- (BOOL)transferAmount:(double)amount
fromAccount:(NSInteger)fromId
toAccount:(NSInteger)toId;
@end
@implementation AtomicUpdater
- (instancetype)initWithDatabase:(sqlite3 *)database {
self = [super init];
if (self) {
_database = database;
}
return self;
}
- (BOOL)transferAmount:(double)amount
fromAccount:(NSInteger)fromId
toAccount:(NSInteger)toId {
TransactionManager *manager = [[TransactionManager alloc] initWithDatabase:_database];
return [manager performTransaction:^{
// Check balance
NSString *checkSql = @"SELECT balance FROM accounts WHERE id = ?;";
sqlite3_stmt *checkStatement;
double balance = 0;
if (sqlite3_prepare_v2(_database, [checkSql UTF8String], -1, &checkStatement, NULL) == SQLITE_OK) {
sqlite3_bind_int(checkStatement, 1, (int)fromId);
if (sqlite3_step(checkStatement) == SQLITE_ROW) {
balance = sqlite3_column_double(checkStatement, 0);
}
sqlite3_finalize(checkStatement);
}
if (balance < amount) {
NSLog(@"Insufficient funds in account %ld", (long)fromId);
return NO;
}
// Deduct from sender
NSString *deductSql = @"UPDATE accounts SET balance = balance - ? WHERE id = ?;";
sqlite3_stmt *deductStatement;
if (sqlite3_prepare_v2(_database, [deductSql UTF8String], -1, &deductStatement, NULL) != SQLITE_OK) {
NSLog(@"Failed to prepare deduct statement");
return NO;
}
sqlite3_bind_double(deductStatement, 1, amount);
sqlite3_bind_int(deductStatement, 2, (int)fromId);
if (sqlite3_step(deductStatement) != SQLITE_DONE) {
NSLog(@"Failed to deduct from account %ld", (long)fromId);
sqlite3_finalize(deductStatement);
return NO;
}
sqlite3_finalize(deductStatement);
// Add to receiver
NSString *addSql = @"UPDATE accounts SET balance = balance + ? WHERE id = ?;";
sqlite3_stmt *addStatement;
if (sqlite3_prepare_v2(_database, [addSql UTF8String], -1, &addStatement, NULL) != SQLITE_OK) {
NSLog(@"Failed to prepare add statement");
return NO;
}
sqlite3_bind_double(addStatement, 1, amount);
sqlite3_bind_int(addStatement, 2, (int)toId);
if (sqlite3_step(addStatement) != SQLITE_DONE) {
NSLog(@"Failed to add to account %ld", (long)toId);
sqlite3_finalize(addStatement);
return NO;
}
sqlite3_finalize(addStatement);
NSLog(@"Transferred %.2f from account %ld to %ld", amount, (long)fromId, (long)toId);
return YES;
}];
}
@end
// MARK: - Main Demonstration
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"=== macOS Objective-C SQLite Transactions Examples ===\n");
sqlite3 *database;
NSString *dbPath = @"/tmp/test_trans.sqlite";
if (sqlite3_open([dbPath UTF8String], &database) != SQLITE_OK) {
NSLog(@"Failed to open database");
return 1;
}
// Create tables
char *error = NULL;
const char *createUsersSQL = "CREATE TABLE IF NOT EXISTS users ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT NOT NULL,"
"email TEXT UNIQUE NOT NULL,"
"age INTEGER"
");";
const char *createAccountsSQL = "CREATE TABLE IF NOT EXISTS accounts ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"balance REAL NOT NULL DEFAULT 0"
");";
sqlite3_exec(database, createUsersSQL, NULL, NULL, &error);
sqlite3_exec(database, createAccountsSQL, NULL, NULL, &error);
// Initialize accounts
sqlite3_exec(database, "INSERT INTO accounts (balance) VALUES (1000.00);", NULL, NULL, NULL);
sqlite3_exec(database, "INSERT INTO accounts (balance) VALUES (500.00);", NULL, NULL, NULL);
NSLog(@"Database initialized");
// 1. Transaction manager
NSLog(@"\n--- Transaction Manager ---");
TransactionManager *txManager = [[TransactionManager alloc] initWithDatabase:database];
[txManager performTransaction:^{
sqlite3_exec(database, "INSERT INTO users (name, email, age) VALUES ('Alice', '[email protected]', 30);", NULL, NULL, NULL);
sqlite3_exec(database, "INSERT INTO users (name, email, age) VALUES ('Bob', '[email protected]', 25);", NULL, NULL, NULL);
NSLog(@"Inserted users in transaction");
return YES;
}];
// 2. Batch insert
NSLog(@"\n--- Batch Insert ---");
BatchInserter *batchInserter = [[BatchInserter alloc] initWithDatabase:database];
NSArray *newUsers = @[
@{@"name": @"Charlie", @"email": @"[email protected]", @"age": @(35)},
@{@"name": @"Diana", @"email": @"[email protected]", @"age": @(28)},
@{@"name": @"Eve", @"email": @"[email protected]", @"age": @(22)}
];
[batchInserter batchInsertUsers:newUsers];
NSArray *newProducts = @[
@{@"name": @"Laptop", @"price": @(999.99), @"quantity": @(10), @"category": @"Electronics"},
@{@"name": @"Mouse", @"price": @(25.50), @"quantity": @(50), @"category": @"Electronics"}
];
[batchInserter batchInsertProducts:newProducts];
// 3. Savepoints
NSLog(@"\n--- Savepoints ---");
SavepointManager *spManager = [[SavepointManager alloc] initWithDatabase:database];
[spManager createSavepoint:@"before_changes"];
sqlite3_exec(database, "INSERT INTO users (name, email, age) VALUES ('Frank', '[email protected]', 40);", NULL, NULL, NULL);
sqlite3_exec(database, "INSERT INTO users (name, email, age) VALUES ('Grace', '[email protected]', 32);", NULL, NULL, NULL);
NSLog(@"Inserted users");
[spManager rollbackToSavepoint:@"before_changes"];
NSLog(@"Rolled back to before_changes");
[spManager releaseSavepoint:@"before_changes"];
// 4. Atomic updates
NSLog(@"\n--- Atomic Updates ---");
AtomicUpdater *updater = [[AtomicUpdater alloc] initWithDatabase:database];
[updater transferAmount:200.00
fromAccount:1
toAccount:2];
NSLog(@"Transferred amount");
// Check balances
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, "SELECT id, balance FROM accounts;", -1, &statement, NULL) == SQLITE_OK) {
NSLog(@"Account balances:");
while (sqlite3_step(statement) == SQLITE_ROW) {
NSInteger accountId = sqlite3_column_int(statement, 0);
double balance = sqlite3_column_double(statement, 1);
NSLog(@" Account %ld: $%.2f", (long)accountId, balance);
}
sqlite3_finalize(statement);
}
// Cleanup
sqlite3_close(database);
NSLog(@"\n=== SQLite Transactions Examples Completed ===");
}
return 0;
}