BlackBerry Java SDK. Data Storage Versione: 7.0. Guida allo sviluppo



Documenti analoghi
Edizione 1 IT. Nokia e Nokia Connecting People sono marchi registrati di Nokia Corporation

Istruzioni di installazione di IBM SPSS Modeler Text Analytics (licenza per sito)

Manuale d'uso del Connection Manager

Al giorno d oggi, i sistemi per la gestione di database

IBM SPSS Statistics per Linux - Istruzioni di installazione (Licenza per sito)

Sistemi Operativi. Interfaccia del File System FILE SYSTEM : INTERFACCIA. Concetto di File. Metodi di Accesso. Struttura delle Directory

Programma applicativo di protezione LOCK Manuale per l utente V2.22-T05

I cookie sono classificati in base alla durata e al sito che li ha impostati.

5.3 TABELLE RECORD Inserire, eliminare record in una tabella Aggiungere record Eliminare record

Domande frequenti su Phoenix FailSafe

Sage Start Archivio file Guida. Dalla versione

Le variabili di Visual Basic consentono di memorizzare temporaneamente valori durante

Istruzioni di installazione di IBM SPSS Modeler Text Analytics (utente singolo)

T E O R I A D I P R O G E T T A Z I O N E D E L S O F T W A R E

Istruzioni per l uso della Guida. Icone utilizzate in questa Guida. Istruzioni per l uso della Guida. Software di backup LaCie Guida per l utente

Acronis License Server. Manuale utente

Domande frequenti su Samsung Drive Manager

IBM SPSS Statistics per Mac OS - Istruzioni di installazione (Licenza per sito)

Esercitazione 4 JDBC

Introduzione JDBC interfaccia java.sql driver caricare i driver

Volumi di riferimento

Gestione delle informazioni necessarie all attività di validazione degli studi di settore. Trasmissione degli esempi da valutare.

Database Manager Guida utente DMAN-IT-01/09/10

Internet Explorer 7. Gestione cookie

Per ulteriori informazioni, vedere l'articolo Nozioni fondamentali della progettazione di database.

Video Recording Manager export Wizard Version 1.0. Manuale del software

Sistemi Mobili e Wireless Android - Dati persistenti: SQLite

I MODULI Q.A.T. PANORAMICA. La soluzione modulare di gestione del Sistema Qualità Aziendale

SPSS Statistics per Windows - Istruzioni di installazione per (Licenza per utenti singoli)

Installazione e caratteristiche generali 1

Impossibile inviare o ricevere messaggi .

I database relazionali (Access)

Introduzione. Introduzione a NTI Shadow. Panoramica della schermata iniziale

LA GESTIONE DELLE VISITE CLIENTI VIA WEB

Personalizzazione del PC

CONFIGURAZIONE E GESTIONE DEI DATABASE (rev. 1.1)

LaCie Ethernet Disk mini Domande frequenti (FAQ)

Riccardo Dutto, Paolo Garza Politecnico di Torino. Riccardo Dutto, Paolo Garza Politecnico di Torino

Capitolo 4 Pianificazione e Sviluppo di Web Part

Che cos'è un modulo? pulsanti di opzione caselle di controllo caselle di riepilogo

La gestione dell input/output da tastiera La gestione dell input/output da file La gestione delle eccezioni

Le query. Lezione 6 a cura di Maria Novella Mosciatti

MANUALE UTENTE Fiscali Free

11/02/2015 MANUALE DI INSTALLAZIONE DELL APPLICAZIONE DESKTOP TELEMATICO VERSIONE 1.0

Basi di dati. Il Linguaggio SQL. K. Donno - Il Linguaggio SQL

BlackBerry Bridge. Versione: 3.0. Manuale dell'utente

BlackBerry Internet Service Uso dell'applicazione di configurazione della posta elettronica dello smartphone BlackBerry Versione: 2.

Internet Explorer 6. Gestione cookie

Siti web centrati sui dati Architettura MVC-2: i JavaBeans

Inserimento dei dati

Guida in linea di Symantec pcanywhere Web Remote

Capitolo 13. Interrogare una base di dati

Content Manager 2 Manuale utente

Backup e ripristino Guida per l'utente

Backup e ripristino Guida per l'utente

Access. P a r t e p r i m a

Indicatore archiviazione

2104 volume III Programmazione

Manuale dell'utente di Crystal Reports. Installazione di Crystal Reports XI

DESKTOP Internal Drive. Guida all installazione

MDAC. Attualmente la versione disponibile di MDAC è la 2.8 ma faremo riferimento alla 2.6. ADO Active Data Objects ADO OLE DB ODBC

Istruzioni per l installazione del software per gli esami ICoNExam (Aggiornate al 15/01/2014)

Condividi in linea 2.0

Solid Edge 2D Drafting Domande frequenti (FAQ)

Riepilogo delle modifiche di PA-DSS dalla versione 2.0 alla 3.0

7.4 Estrazione di materiale dal web

Riferimento rapido per l'installazione SUSE Linux Enterprise Server 11

. A primi passi con microsoft a.ccepss SommarIo: i S 1. aprire e chiudere microsoft access Start (o avvio) l i b tutti i pro- grammi

1. Le macro in Access 2000/2003

Acronis Universal Restore

BlackBerry Internet Service Uso del browser dello smartphone BlackBerry Versione: 2.6. Manuale dell'utente

Guida all'amministrazione. BlackBerry Professional Software per Microsoft Exchange. Versione: 4.1 Service Pack: 4

METODI per effettuare previsioni con analisi di tipo WHAT-IF

Informatica Generale Andrea Corradini Sistemi di Gestione delle Basi di Dati

I file di dati. Unità didattica D1 1

Iniziativa Comunitaria Equal II Fase IT G2 CAM Futuro Remoto. Approfondimento SOFTWARE PER L ARCHIVIAZIONE

Backup e ripristino Guida per l'utente

Online Help StruxureWare Data Center Expert

PULSANTI E PAGINE Sommario PULSANTI E PAGINE...1

DESCRIZIONE: Microsoft Office 2002 XP Corso Completo (Patente 60 giorni)

Cookie Policy per

IBM SPSS Statistics per Windows - Istruzioni di installazione (Licenza per utenti singoli)

Dispensa di database Access

Utilizzo dei Cookie Cosa sono i cookie? A cosa servono i cookie? cookie tecnici cookie, detti analitici cookie di profilazione

Motorola Phone Tools. Guida rapida

IL SISTEMA OPERATIVO

IBM SPSS Statistics per Windows - Istruzioni di installazione (Licenza per sito)

corso di Access MICROSOFT ACCESS Docente: Andrea Mereu Università degli studi di Cagliari 16 aprile 9 maggio 2012

Manuale LiveBox APPLICAZIONE WINDOWS PHONE V (465)

Obiettivi del corso. Creare, modificare e formattare un semplice database costituito da tabelle, query, maschere e report utilizzando Access 2000.

STRUMENTI PER L ACCESSIBILITÀ DEL COMPUTER.

Architettura MVC-2: i JavaBeans

Guida utente di Mobile Device Manager

Automatizzare i compiti ripetitivi. I file batch. File batch (1) File batch (2) Visualizzazione (2) Visualizzazione

Samsung Auto Backup FAQ

Modulo 6 Strumenti di presentazione

Si applica a: Windows Server 2008

Fiery Driver Configurator

Titolare del trattamento dei dati innanzi descritto è tsnpalombara.it

Riferimento rapido per l'installazione SUSE Linux Enterprise Server 11 SP1

Transcript:

BlackBerry Java SDK Data Storage Versione: 7.0 Guida allo sviluppo

SWD-1604146-1213120933-004

Indice 1 Panoramica della memorizzazione dei dati... 4 Confronto tra gli approcci di memorizzazione dei dati... 4 Considerazioni per la scelta dell'approccio di memorizzazione dei dati... 5 Posizioni di memorizzazione... 5 2 Memorizzazione di dati nei database SQLite... 7 Visualizzazione dei database SQLite... 7 Simulazione di una scheda di memoria... 7 Protezione dei database SQLite... 8 Esempio di codice: creazione di un database SQLite crittografato... 9 Prestazioni del database SQLite... 10 Descrizione di SQLite come servizio... 11 Procedura consigliata: ottimizzazione delle prestazioni di un database SQLite... 12 Utilizzo dei database SQLite... 14 Uso dei parametri SQL... 15 Uso dei pragma... 19 Utilizzo dei BLOB... 21 Recupero dei dati della tabella... 22 Uso delle transazioni... 23 Creazione ed eliminazione di database SQLite... 25 File del database SQLite... 25 Informazioni sulle chiavi primarie... 25 Imposizione di vincoli di chiave esterna... 26 Codifica caratteri... 26 Uso dei confronti tra lingue... 26 Creazione di un database SQLite... 27 Creazione ed eliminazione di tabelle... 30 Copia di un database in una posizione crittografata... 36 Apertura e chiusura dei database... 37 Aggiunta o rimozione dei database... 37 Applicazione di esempio SQLite... 38 Panoramica... 38 File nell'applicazione di esempio... 38 Interfacce disponibili... 39 Classi disponibili... 40 Installazione dell'applicazione di esempio... 40 Esecuzione dell'applicazione di esempio... 40

3 Memorizzazione dei file nel file system... 42 Esempio di codice: creazione di una cartella... 42 Esempio di codice: creazione di un file... 43 Esempio di codice: scrittura di testo in un file... 44 Esempio di codice: lettura delle sezioni di un file binario... 44 Esempio di codice: visualizzazione del percorso della cartella video utilizzando System.getProperty()... 46 Esempio di codice: recupero di un elenco di origini inserite... 46 4 Memorizzazione di oggetti in maniera permanente... 48 Protezione di oggetti permanenti... 48 Limitazione dell'accesso agli oggetti permanenti... 49 Prestazioni della memoria permanente... 52 Procedura consigliata: selezione di una struttura dati efficiente... 52 Procedura consigliata: conservazione degli handle di oggetti... 52 Pulizia di oggetti permanenti... 53 Creazione di una memoria permanente... 53 Creazione di un archivio dati permanente... 53 Archiviazione dei dati permanenti... 54 Memorizzazione di un oggetto in una transazione batch... 55 Utilizzo della memoria permanente... 55 Recupero dei dati permanenti... 55 Recupero di una raccolta dalla memoria permanente... 55 5 Memorizzazione di oggetti in modo non permanente... 57 Utilizzi comuni dell'archivio di runtime... 57 Protezione dell'archivio di runtime... 57 Restrizione dell'accesso ai dati dell'archivio di runtime tramite le chiavi di firma codice... 58 Aggiunta di un oggetto all'archivio di runtime... 58 Sostituzione di un oggetto nell'archivio di runtime... 58 Recupero dell'archivio di runtime... 59 Recupero di un oggetto runtime registrato... 59 Recupero di un oggetto runtime non registrato... 59 Esempio di codice: memorizzazione di una stringa nell'archivio di runtime... 60 Esempio di codice: recupero di una stringa memorizzata dall'archivio di runtime... 60 Esempio di codice: creazione di un singleton utilizzando l'api RuntimeStore... 61 6 Memorizzazione di dati nell'archivio di record... 62 Creazione di un archivio di record... 62 Aggiunta di un record a un archivio di record... 62

Esempio di codice: aggiunta di un record all'archivio di record... 63 Recupero di un record da un archivio di record... 63 Recupero di tutti i record da un archivio di record... 63 Esempio di codice: memorizzazione e recupero dei dati tramite l'archivio di record... 64 7 Gestione dei dati... 69 Procedura consigliata: riduzione della memoria utilizzata... 69 Rimozione di dati sensibili... 69 Utilizzo di Garbage Collector... 70 Garbage collection completa su un dispositivo BlackBerry... 70 Gestione della memoria in esaurimento... 71 Individuazione della condizione di memoria in esaurimento... 71 Esecuzione del backup dei dati... 71 8 Ulteriori informazioni... 73 9 Commenti e suggerimenti... 74 10 Glossario... 75 11 Cronologia delle revisioni del documento... 77 12 Note legali... 78

Panoramica della memorizzazione dei dati Panoramica della memorizzazione dei dati 1 Sono disponibili diversi metodi per memorizzare, condividere e gestire i dati delle applicazioni. Questa guida contiene un capitolo per ciascuno degli approcci seguenti: Approccio di archiviazione dei dati Database SQLite File system Memoria permanente Archivio di runtime Archivio di record Descrizione e API Consente di memorizzare i dati in database relazionali tramite l'api Database. Consente di memorizzare i dati in file e cartelle tramite l'api FileConnection. Consente di salvare gli oggetti tra un riavvio dello smartphone e l'altro tramite l'api PersistentStore. Consente di salvare gli oggetti in modo non permanente, procedura utile per la condivisione dei dati tra le applicazioni e per la creazione di singleton della stessa grandezza del sistema, tramite l'api RuntimeStore. Consente di memorizzare i dati nel sistema di gestione dei record MIDP tramite l'api RMS. Confronto tra gli approcci di memorizzazione dei dati Nella tabella seguente, vengono messe a confronto le varie modalità di memorizzazione dei dati, relative all'applicazione in uso. Funzioni Data format Storage locations Maximum storage limit Database SQLite File del database relazionale Scheda di memoria esterna, memoria contenuto multimedial e integrata Dimensione delle partizioni File system Memoria permanente Archivio di runtime Archivio di record Tutto Oggetto Java Oggetto Java Serializzato Memoria applicazioni, scheda di memoria esterna, memoria contenuto multimediale integrata Dimensione delle partizioni alle quali ha accesso l'utente Memoria applicazioni Memoria applicazioni disponibile Memoria applicazioni Memoria applicazioni disponibile Memoria applicazioni Diverso in base alla versione di BlackBerry Device Software 4

Considerazioni per la scelta dell'approccio di memorizzazione dei dati Funzioni BlackBerry Device Software support Persists across device restarts Applications can share data Database SQLite alle quali ha accesso l'utente 5.0 o versione successiva File system 4.2. o versione successiva Memoria permanente Tutto Archivio di runtime 3.6 o versione successiva Sì Sì Sì No Sì Sì Sì Sì Sì Sì Archivio di record Tutto Considerazioni per la scelta dell'approccio di memorizzazione dei dati Il file system è in genere la posizione di memorizzazione più efficiente per file di grandi dimensioni e di sola lettura come i video oppure file grafici di grandi dimensioni. Per memorizzare dati diversi da file di grandi dimensioni e di sola lettura, i database SQLite rappresentano un'opzione scalabile per la memorizzazione dei dati. La memoria dei dispositivi wireless può essere molto limitata, pertanto si consiglia di non memorizzare tutti i dati sul dispositivo. I dispositivi BlackBerry sono connessi frequentemente, pertanto l'applicazione può accedere ai dati quando necessario. In molti casi, il migliore approccio è quello di memorizzare i dati durante i riavvii del dispositivo solo nel caso di dati ai quali si accede frequentemente. Quando si deve decidere dove memorizzare i dati importanti, tenere in mente che le schede microsd possono essere rimosse. La latenza è maggiore nel caso di scrittura sulla memoria applicazioni che non nel caso di lettura da essa. Ad esempio, la lettura dalla memoria permanente è relativamente veloce mentre i commit sono relativamente lenti. Il file system e l'archivio di record rappresentano approcci basati su standard, mentre la memoria permanente e l'archivio di runtime sono specifici dei dispositivi BlackBerry. Se si desidera eseguire l'applicazione su altri dispositivi compatibili con Java ME, è opportuno prendere in considerazione un approccio basato su standard. Posizioni di memorizzazione Smartphone BlackBerry diversi supportano posizioni diverse per la memorizzazione dei dati. Sono disponibili le seguenti posizioni di memorizzazione, in base al modello di smartphone: 5

Posizioni di memorizzazione Memoria applicazioni Archiviazione su una scheda di memoria esterna Memoria contenuto multimediale integrata Questa posizione di memorizzazione è interna allo smartphone. Contiene il sistema operativo, BlackBerry Java Virtual Machine e un file system interno. La memoria applicazione viene definita anche memoria flash e memoria su scheda. La memoria applicazioni è l'unica posizione su uno smartphone BlackBerry da cui è possibile eseguire le applicazioni. Tutti gli smartphone BlackBerry dispongono di una memoria applicazioni. Questa posizione di memorizzazione è rappresentata da una scheda microsd che gli utenti BlackBerry possono inserire per aumentare la quantità di memoria dei propri smartphone. È opzionale e rimovibile. Sulla scheda di memoria è montato un file system FAT. Le schede microsd sono supportate su tutti gli smartphone in cui è in esecuzione BlackBerry Device Software 4.2 o versioni successive, ad eccezione di BlackBerry 8700 Series. Questa posizione di memorizzazione è una scheda multimediale incorporata, denominata emmc. Non è rimovibile. Sulla scheda di memoria integrata è montato un file system FAT. La memoria contenuto multimediale integrata è denominata anche memoria multimediale interna e memoria su scheda del dispositivo. La memoria contenuto multimediale integrata è inclusa in alcuni modelli di smartphone BlackBerry. 6

Memorizzazione di dati nei database SQLite Memorizzazione di dati nei database SQLite 2 SQLite è un sistema per la gestione di database relazionali. Con un footprint del codice di circa 300 KB, SQLite si adatta perfettamente a dispositivi di piccole dimensioni, come gli smartphone. Inoltre, SQLite consente un utilizzo efficiente della memoria, dello spazio su disco e della larghezza di banda su disco; inoltre, i database SQLite non richiedono alcuna manutenzione da parte di un amministratore del database. Per creare e utilizzare i database SQLite nell'applicazione Java, è necessario utilizzare l'api Database, che corrisponde al pacchetto net.rim.device.api.database. L'API Database implementa i database SQLite in un modo che potrebbe risultare leggermente diverso da quello a cui è abituato l'utente. Per migliorare l'efficienza, SQLite viene eseguito come servizio sullo smartphone BlackBerry. Le operazioni di database utilizzano un collegamento runtime per il trasferimento dei dati tra Java e il codice nativo. Per ulteriori informazioni, vedere Descrizione di SQLite come servizio. BlackBerry Device Software 7 utilizza SQLite 3.7.2. Per ulteriori informazioni su SQLite, visitare il sito www.sqlite.org. Visualizzazione dei database SQLite I visualizzatori di database SQLite sono disponibili presso fornitori di terzi. I visualizzatori possono essere di aiuto durante il processo di sviluppo del database. I visualizzatori di database sono utili soprattutto per la visualizzazione delle modifiche apportate a un database. Quando si esegue un'istruzione SQL, è possibile visualizzare immediatamente il risultato nel visualizzatore di database. Il visualizzatore di database SQLite viene eseguito sul computer, non sullo smartphone. Per utilizzare il visualizzatore, configurare BlackBerry Smartphone Simulator per emulare una scheda microsd. Quando viene eseguita l'applicazione, il visualizzatore di database legge il database da una cartella sul computer. Nota: I visualizzatori di database SQLite non funzionano con i database crittografati. È possibile crittografare il database dopo aver completato l'applicazione SQLite. Simulazione di una scheda di memoria Per visualizzare i database SQLite in un visualizzatore di database, potrebbe essere necessario configurare BlackBerry Smartphone Simulator per emulare una scheda di memoria. I file di database vengono archiviati in una scheda di memoria per impostazione predefinita. 1. Creare una cartella sul computer in uso per archiviare i file di emulazione della scheda di memoria. 2. In BlackBerry Smartphone Simulator, nel menu Simulate, fare clic su Change SD Card. 3. Fare clic su Add Directory. 4. Accedere alla cartella che è stata creata e fare clic su di essa. 5. Fare clic su OK. 6. Fare clic su Close. 7

Protezione dei database SQLite Protezione dei database SQLite Il database SQLite può disporre di uno dei seguenti livelli di protezione: Nessuna crittografia: un file di testo normale, accessibile da qualsiasi applicazione sullo smartphone. Crittografia: un file crittografato, accessibile da qualsiasi applicazione sullo smartphone. Crittografia e protezione: un file crittografato, accessibile solo dalle applicazioni sullo smartphone firmate con la stessa chiave di firma codice. Protezione del contenuto oltre a crittografia e protezione: un file crittografato e protetto, che utilizza la protezione del contenuto per crittografare la chiave master SQLite e offre protezione aggiuntiva quando lo smartphone è bloccato. Le applicazioni contenenti informazioni sensibili devono utilizzare database crittografati e protetti, per impedire ad altre applicazioni di utilizzare il metodo attach per accedere a tali informazioni. Non è possibile limitare l'accesso a un database di testo normale perché è possibile leggerlo tramite le operazioni di I/O del file. Le sezioni seguenti descrivono ciascuno dei livelli di protezione. Crittografia La crittografia impedisce la copia dei file da uno smartphone e la relativa lettura da parte di altri utenti. L'algoritmo utilizzato per implementare la crittografia SQLite è AES 256. Per trasferire un database crittografato su un altro smartphone, è necessario prima decrittografarlo. Un'applicazione può aprire o creare un database crittografato solo quando lo smartphone è sbloccato. Se un database viene aperto con lo smartphone bloccato, il database continua a essere leggibile e scrivibile. La crittografia non impedisce ad altre applicazioni dello smartphone di accedere al database dell'utente. Per limitare l'accesso, è necessario proteggere il database firmandolo con una chiave di firma codice. Nell'esempio di codice seguente, viene creato un database crittografato ma non firmato. Viene creato un oggetto DatabaseSecurityOptions denominato dbso, che passa true come singolo valore di parametro. try URI myuri = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyEncryptedDatabase.db"); DatabaseSecurityOptions dbso = new DatabaseSecurityOptions(true); d = DatabaseFactory.create(myURI,dbso); d.close(); catch ( Exception e ) System.out.println( e.getmessage() ); e.printstacktrace(); Crittografia e protezione 8

Protezione dei database SQLite Se si desidera limitare l'accesso a un database in modo che possa essere utilizzato solo dall'applicazione di cui fa parte, è necessario firmare il database con una chiave di firma codice. Per limitare l'accesso a un'applicazione, è necessario utilizzare una chiave univoca, generata tramite BlackBerry Signing Authority Tool. Questa firma è diversa dalla firma codice creata per le API controllate. È possibile anche utilizzare la chiave di firma codice per condividere l'accesso al database con altre applicazioni specifiche. Se più applicazioni vengono firmate con la stessa chiave, tali applicazioni hanno tutte accesso al database. Nell'esempio di codice seguente, viene crittografato e protetto un database esistente. Inizialmente, l'esempio di codice recupera la chiave di firma codice da un file chiamato XYZ. Successivamente, crittografa e firma il database. Se il database è già crittografato, il metodo encrypt viene chiuso correttamente. CodeSigningKey codesigningkey = CodeSigningKey.get(CodeModuleManager.getModuleHandle( "SQLiteDemo" ), "XYZ"); try DatabaseFactory.encrypt(uri, new DatabaseSecurityOptions(codeSigningKey)); catch(databaseexception dbe) errordialog("encryption failed - " + dbe.tostring()); Protezione del contenuto oltre a crittografia e protezione La protezione del contenuto crittografa le chiavi di crittografia in modo che risultino inaccessibili quando lo smartphone è bloccato. Anche quando un file del database è crittografato, il massimo livello di protezione viene raggiunto quando è attivata la protezione del contenuto. Con la protezione del contenuto, un'applicazione può aprire o può creare un database crittografato solo quando lo smartphone è sbloccato. È necessario chiudere un database crittografato il prima possibile. Una connessione al database aperta potrebbe essere suscettibile agli attacchi al momento dell'avvio a freddo. Per ulteriori informazioni sulla protezione del contenuto, consultare Guida a BlackBerry Java SDK - Protezione, disponibile all'indirizzo www.blackberry.com/go/devguides. Esempio di codice: creazione di un database SQLite crittografato I file di database vengono archiviati in una scheda di memoria per impostazione predefinita. Se si utilizza BlackBerry Smartphone Simulator, potrebbe essere necessario simulare una scheda di memoria. import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.container.*; import net.rim.device.api.database.*; import net.rim.device.api.io.*; public class CreateEncryptedDatabase extends UiApplication 9

Prestazioni del database SQLite public static void main(string[] args) CreateEncryptedDatabase theapp = new CreateEncryptedDatabase(); theapp.entereventdispatcher(); public CreateEncryptedDatabase() pushscreen(new CreateEncryptedDatabaseScreen()); class CreateEncryptedDatabaseScreen extends MainScreen Database d; public CreateEncryptedDatabaseScreen() LabelField title = new LabelField("SQLite Create Encrypted Database Sample", LabelField.ELLIPSIS LabelField.USE_ALL_WIDTH); settitle(title); add(new RichTextField("Creating an encrypted database called " + "MyEncryptedDatabase.db on the microsd card.")); try URI myuri = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyEncryptedDatabase.db"); DatabaseSecurityOptions dbso = new DatabaseSecurityOptions(true); d = DatabaseFactory.create(myURI,dbso); d.close(); catch ( Exception e ) System.out.println( e.getmessage() ); e.printstacktrace(); Prestazioni del database SQLite Rispetto ai computer, i dispositivi mobili offrono un ambiente molti limitato per i database SQLite. Per ottenere prestazioni ottimali su uno smartphone BlackBerry, tenere in considerazione i seguenti vincoli: Il limite di memoria dinamico è pari a 16 MB. Questo limite fa riferimento alla quantità di RAM disponibile per la memorizzazione, da parte di un database SQLite, delle strutture di dati interne per gli schemi e le transazioni. Lo schema dell'intero database viene caricato nella memoria quando viene aperto un database SQLite e rimane nella memoria fin quando il database non viene chiuso. La lunghezza massima della query SQL è di 1 MB. Il numero massimo di database che è possibile aprire contemporaneamente è di circa 50. L'API Database utilizza una modalità cache condivisa, per consentire un utilizzo efficiente di memoria per le connessioni multiple allo stesso database. 10

Prestazioni del database SQLite È possibile eseguire una sola connessione in lettura/scrittura alla volta al database SQLite. Le altre connessioni database sono di sola lettura. Quando si utilizzano i metodi Database.createBlobOutputStream e Database.createBlobInputStream per la lettura e scrittura dei BLOB, la memoria disponibile per SQLite non limita le dimensioni del BLOB che è possibile utilizzare: l'insieme di risultati non è limitato a 1 MB. È possibile tenere traccia dell'utilizzo della memoria per ciascuna connessione al database tramite i seguenti metodi: Database.getCacheUsed, Database.getSchemaUsed e Database.getStatementUsed. Descrizione di SQLite come servizio Su uno smartphone BlackBerry, SQLite viene eseguito come servizio. Le operazioni di database utilizzano un collegamento runtime per il trasferimento dei dati tra Java e il codice nativo. Esiste un 1 limite di MB sulla quantità di dati che è possibile trasferire tramite il collegamento runtime. Il collegamento runtime può offrire prestazioni eccellenti riguardo alle operazioni di database, ma può ridurre le prestazioni se non viene utilizzato in modo appropriato. Quando si crea un'istruzione preparata per l'inserimento o l'aggiornamento dei dati, è necessario utilizzare i metodi Statement.executeInsert o Statement.executeUpdate per ridurre il numero di chiamate tramite il collegamento runtime. Questi metodi consentono di eseguire le seguenti operazioni nel codice nativo: Associare i parametri SQL Eseguire l'istruzione Reimpostare l'istruzione Deselezionare le associazioni Restituire l'ultimo ID della riga inserito ( solo executeinsert) Quando si esegue una query che non restituisce un insieme di risultati e non vengono associati parametri, è necessario utilizzare il metodo Database.executeStatement, che riduce il numero di chiamate tramite il collegamento runtime, eseguendo le seguenti operazioni nel codice nativo: Preparare l'istruzione Eseguire l'istruzione Finalizzare l'istruzione Quando si esegue una query che restituisce insiemi di risultati tramite il metodo Statement.getCursor, è possibile recuperare preventivamente un determinato numero di righe, tramite il metodo Statement.setCursorBufferSize. Questo approccio consente di ridurre l'utilizzo del collegamento runtime. Quando il cursore si sposta oltre l'insieme di dati nel buffer, viene automaticamente recuperato un nuovo batch di righe. È possibile recuperare il numero di righe che un cursore memorizzerà nel buffer tramite il metodo Statement.getCursorBufferSize. Quando si recuperano valori interi da utilizzare come chiavi in un'altra query, è possibile utilizzare i metodi Statement.getIntegers e Statement.getLongs. Questi metodi consentono di semplificare e ottimizzare il recupero delle colonne degli interi. 11

Prestazioni del database SQLite Procedura consigliata: ottimizzazione delle prestazioni di un database SQLite Attenersi alle seguenti istruzioni: Procedura consigliata Utilizzare la modalità del diario appropriata Provare a diminuire i vincoli di sicurezza per le tabelle Prova Archiviare il minor numero possibile di dati Raggruppare le istruzioni con transazioni esplicite Creare degli indici efficienti Descrizione Per impostazione predefinita, viene utilizzato un diario di ripristino per registrare le transazioni, ma è possibile scegliere di utilizzare invece un registro write-ahead. Il registro write-ahead aumenta la simultaneità delle operazioni e risulta più veloce del diario di ripristino nella maggior parte delle situazioni, poiché la scrittura sul database non blocca la lettura. Tuttavia, il registro write-ahead utilizza più handle di file. Il registro write-ahead utilizza fino a tre handle di file che possono rimanere memorizzati per lunghi periodi, mentre il diario di ripristino ne utilizza uno, o talvolta due, durante la scrittura delle transazioni. Per modificare la modalità del diario in un registro write-ahead, eseguire l'istruzione SQL "PRAGMA journal_mode = WAL;". Quando l'integrità dei dati non rappresenta una priorità, provare ad utilizzare i comandi Pragma per evitare di specificare un diario e per disattivare la modalità sincrona. Ad esempio, PRAGMA journal_mode=off e PRAGMA synchronous=off. Se si pensa di creare un database con uno schema di grandi dimensioni o di inserire BLOB di grandi dimensioni, è necessario eseguire il test del database sugli smartphone BlackBerry di destinazione, per assicurarsi che gli smartphone dispongano di una quantità di memoria sufficiente. La maggior parte del tempo di elaborazione dei database SQLite viene impiegata per la lettura e la scrittura per l'archiviazione. Un minor numero di dati significa in genere un minor numero di letture e scritture. Il motore di database SQLite memorizza nella cache le pagine del database a cui si accede frequentemente. Archiviando un numero di dati inferiore, è possibile aumentare la probabilità che il motore di database SQLite recuperi i dati richiesti più rapidamente dalla cache anziché dalla memoria relativamente lenta. Se non si utilizzano transazioni esplicite, viene creata una transazione per ogni istruzione eseguita. Questo comportamento predefinito non è efficiente. Presuppone l'apertura, la riapertura, la scrittura e la chiusura del file journal per ogni istruzione. Con le transazioni esplicite, è possibile raggruppare le istruzioni per ottenere una maggiore efficienza. È possibile eseguire più istruzioni in una sola transazione posizionando Database.beginTransaction e Database.commitTransaction in un gruppo di istruzioni. Gli indici possono ridurre di molto il tempo richiesto per effettuare una ricerca in una tabella. Di seguito, sono riportate alcune note sulla creazione di indici efficienti: Gli indici possono migliorare le prestazioni per le query di sola lettura, come ad esempio SELECT, ma possono ridurre le prestazioni per le query che modificano le righe. Provare a indicizzare solo le tabelle che vengono aggiornate raramente. 12

Prestazioni del database SQLite Procedura consigliata Ridurre la dimensione delle righe Memorizzare appropriatamente i BLOB Prendere in considerazione l'utilizzo delle tabelle temporanee Utilizzare i parametri SQL Non utilizzare delle sottoquery Deframmentare il database Nelle istruzioni per le tabelle, prendere in considerazione l'ordine delle colonne. Utilizzare i metodi di funzionamento in blocco Descrizione L'ordine delle colonne in un indice influisce sulle prestazioni. Le colonne utilizzate in genere nelle clausole WHERE dovrebbero essere collocate per prime, seguite dalle colonne utilizzate in genere nelle clausole BY. Per le colonne contenenti dati recuperati, creare un indice di copertura. Evitare gli indici duplicati. Il motore di database SQLite crea automaticamente gli indici per le colonne che hanno i vincoli UNIQUE o PRIMARY KEY. Le colonne denominate INTEGER PRIMARY KEY producono query più veloci perché hanno accesso diretto ai dati della tabella. Se si dispone di una colonna molto ampia, prendere in considerazione la possibilità di inserirla in una tabella separata. Se i dati dell'utente includono BLOB, è necessario leggerli e scriverli tramite gli oggetti InputStream e OutputStream, utilizzando createblobinputstream e createbloboutputstream. È anche possibile provare a memorizzare ciascun BLOB in una tabella separata. Se i BLOB sono molto grandi, è possibile memorizzarli come file all'esterno del database (e memorizzare il percorso per ogni file del database), ma questa procedura implica un sovraccarico per la ricerca dei nomi dei file. Se non è necessario rendere disponibili i dati dopo il riavvio dello smartphone, utilizzare l'istruzione CREATE TEMP TABLE invece di CREATE TABLE. Per eseguire una serie di istruzioni dello stesso formato, preparare prima un'istruzione generica che utilizzi i parametri SQL. È possibile eseguire l'istruzione reiterando i valori variabili e associando i valori alle variabili denominate in ogni iterazione. In alcuni casi, il motore di database SQLite memorizza i risultati della sottoquery in un file temporaneo, che può rallentare l'elaborazione. Utilizzare il comando VACUUM di SQLite per deframmentare il database. Questo processo riduce anche la dimensione del file di database. L'ordine delle colonne in una dichiarazione di tabella influisce sulle prestazioni, soprattutto in caso di assenza di un indice, perché il motore di database SQLite effettua una ricerca nelle colonne nell'ordine definito nella dichiarazione di tabella. Le colonne che contengono un minor numero di dati, ai quali si accede con frequenza, dovrebbero essere collocate prima delle colonne contenenti un maggior numero di dati, ai quali si accede raramente. I seguenti metodi di funzionamento in blocco consentono un utilizzo efficiente del collegamento runtime: Database.executeStatement Statement.executeInsert e Statement.executeUpdate 13

Utilizzo dei database SQLite Procedura consigliata Descrizione Statement.getIntegers e Statement.getLongs Statement.setCursorBufferSize Per ulteriori informazioni, vedere Descrizione di SQLite come servizio. Utilizzo dei database SQLite Dopo la creazione di un database SQLite, è possibile utilizzare le istruzioni SQL per eseguire operazioni quali l'aggiunta e il recupero di dati e la modifica del database. L'elenco di istruzioni SQL supportate e la loro sintassi è disponibile sul sito www.sqlite.org. L'API Database non supporta FTS2 e RTREE. Esistono due modi per eseguire le istruzioni: creare un oggetto Statement oppure utilizzare Database.executeStatement. Esecuzione delle istruzioni con un oggetto Statement I passaggi seguenti delineano come eseguire le istruzioni con un oggetto Statement: 1. Creare un oggetto Statement tramite il metodo Database.createStatement. 2. Preparare l'esecuzione dell'istruzione richiamando il metodo Statement.Prepare. 3. Parametri di associazione nell'istruzione. Si tratta di un'opzione facoltativa, ma consente di migliorare le prestazioni quando si esegue l'istruzione più volte. 4. Eseguire l'istruzione. Se è probabile che l'istruzione restituisca risultati (ad esempio, un'istruzione SELECT), eseguirla richiamando Statement.getCursor, che restituisce un oggetto Cursor. Se l'istruzione non restituisce un insieme di risultati, eseguirla richiamando uno dei metodi seguenti: Statement.executeUpdate: utilizzare questo metodo durante l'aggiornamento dei dati (tramite un'istruzione UPDATE) e l'esecuzione dell'istruzione più volte con parametri di associazione. Statement.executeInsert: utilizzare questo metodo durante l'inserimento dei dati (tramite un'istruzione INSERT) e l'esecuzione dell'istruzione più volte con parametri di associazione. Statement.execute: utilizzare questo metodo quando si desidera utilizzare parametri di associazione. 5. Se l'istruzione restituisce un insieme di risultati, recuperare l'insieme di risultati reiterando il cursore restituito riga per riga. Eseguire questa operazione utilizzando l'interfaccia Cursor, che funziona in tutte le circostanze ma è valida solo per l'inoltro. Per il movimento bidirezionale del cursore, ma solo per insiemi di risultati di piccole dimensioni, utilizzare la classe BufferedCursor. Nota: È necessario chiudere esplicitamente le istruzioni per liberare risorse. Nell'esempio seguente, vengono aggiornate le righe: 14

Utilizzo dei database SQLite Statement st = d.createstatement("update Account set Balance =? WHERE AcctNo >?"); try st.prepare(); Object[] bindparams = new Integer (2000), new Integer (100); st.executeupdate(bindparams); finally st.close(); Esecuzione delle istruzioni senza un oggetto Statement Quando si esegue una query che non restituisce un insieme di risultati e non si utilizzano parametri di associazione, non è necessario creare un oggetto Statement. Al contrario, è possibile utilizzare Database.executeStatement, che esegue la preparazione, l'esecuzione e la chiusura di un'istruzione in una singola chiamata. Nell'esempio seguente, viene creata una tabella: Database d = null; try d = DatabaseFactory.create("hello.db"); d.executestatement( "CREATE TABLE t (a INTEGER PRIMARY KEY, b BLOB);" ); catch (Exception e) System.out.println( e.getmessage() ); finally try d.close(); catch (DatabaseException e) Uso dei parametri SQL Quando si crea un'istruzione SQL, è possibile creare parametri SQL per riutilizzare l'istruzione con valori diversi. Questa pratica può fornire dei vantaggi in termini di prestazioni. È possibile preparare istruzioni generiche per l'utilizzo di variabili denominate ed eseguire le istruzioni quando necessario, iterando i valori delle variabili e associando i valori alle variabili denominate in ogni iterazione. Quando si utilizzano i metodi executeinsert o executeupdate, l'utente associa i parametri nel metodo con il parametro bindparams. bindparams è costituito da un array di oggetti, che può corrispondere a una qualsiasi combinazione di Null, Integer, Long, Boolean, Float, Double, String o ByteBuffers. Di seguito, viene riportato un esempio: Statement st = d.createstatement("update Account set Balance =? WHERE AcctNo >?"); try st.prepare(); Object[] bindparams = new Integer (2000), new Integer (100); 15

Utilizzo dei database SQLite st.executeupdate(bindparams); finally st.close(); Quando si utilizza il metodo getcursor o execute, è possibile utilizzare il metodo Statement.bind per fornire i nomi per i parametri SQL. Il metodo bind() acquisisce il numero del parametro e il valore da assegnargli. Se si utilizza un numero esterno all'intervallo consentito, viene generata un'eccezione DatabaseException. Tutte le associazioni possono essere reimpostate tramite Statement.reset. È possibile scegliere uno dei seguenti metodi per numerare i parametri: Un punto interrogativo (?) nell'istruzione consente di numerare ogni parametro in modo sequenziale, iniziando da 1. Un punto interrogativo seguito da un numero intero (?NNN) nell'istruzione assegna a ogni parametro il numero NNN. Di seguito, viene riportato un esempio di istruzione che utilizza parametri per creare un limite superiore e un limite inferiore, da poter definire ad ogni esecuzione dell'istruzione. In questo esempio, i parametri sono numerati in modo sequenziale. Statement s = Database.createStatement("SELECT * FROM T WHERE a <? AND a >?"); s.prepare(); s.bind(1, upperbound); s.bind(2, lowerbound); Cursor c = s.getcursor(); Di seguito, viene riportata la stessa istruzione, eccetto i numeri espliciti specificati per i parametri: Statement s = Database.createStatement("SELECT * FROM T WHERE a <?5 AND a >?12"); s.prepare(); s.bind(5, upperbound); s.bind(12, lowerbound); Cursor c = s.getcursor(); Il metodo Statement.getFormalName converte un indice del parametro in un nome di parametro SQL. Se si desidera che getformalname restituisca il nome del parametro, è necessario fornire un nome nella query. Ad esempio, quando si richiama getformalname(1), l'istruzione "SELECT * FROM T WHERE a = :a" restituisce :a. Se si utilizzano i parametri, quali il punto interrogativo (?), come segnaposto, getformalname() non è in grado di restituire il nome del parametro. Ad esempio, getformalname(1) non restituirà il nome del parametro in questa istruzione: "SELECT * FROM T WHERE a =?" Esempio di codice: creazione di un aggiornamento con parametri import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.container.*; import net.rim.device.api.database.*; import net.rim.device.api.io.*; import java.util.*; 16

Utilizzo dei database SQLite public class ParameterizedUpdate extends UiApplication public static void main(string[] args) ParameterizedUpdate theapp = new ParameterizedUpdate(); theapp.entereventdispatcher(); public ParameterizedUpdate() pushscreen(new ParameterizedUpdateScreen()); class ParameterizedUpdateScreen extends MainScreen Database d; public ParameterizedUpdateScreen() LabelField title = new LabelField("SQLite Parameterized Update Sample", LabelField.ELLIPSIS LabelField.USE_ALL_WIDTH); settitle(title); add(new RichTextField("Attempting to update data in " + "MyTestDatabase.db on the SDCard.")); try URI myuri = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createstatement( "UPDATE People SET Age=? WHERE Name=?"); st.prepare(); Hashtable ht = new Hashtable(2); ht.put("sophie", new Integer(10)); ht.put("karen", new Integer(7)); Enumeration names = ht.keys(); Enumeration ages = ht.elements(); while (names.hasmoreelements()) Integer iage = (Integer)ages.nextElement(); String strname = (String)names.nextElement(); st.bind(1,iage.intvalue()); st.bind(2,strname); st.execute(); st.reset(); st.close(); d.close(); catch ( Exception e ) System.out.println( e.getmessage() ); e.printstacktrace(); 17

Utilizzo dei database SQLite Esempio di codice: creazione di un inserimento con parametri import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.container.*; import net.rim.device.api.database.*; import net.rim.device.api.io.*; import java.util.*; public class ParameterizedInsert extends UiApplication public static void main(string[] args) ParameterizedInsert theapp = new ParameterizedInsert(); theapp.entereventdispatcher(); public ParameterizedInsert() pushscreen(new ParameterizedInsertScreen()); class ParameterizedInsertScreen extends MainScreen Database d; public ParameterizedInsertScreen() LabelField title = new LabelField("SQLite Insert Data " + "Schema Sample", LabelField.ELLIPSIS LabelField.USE_ALL_WIDTH); settitle(title); add(new RichTextField("Attempting to insert data into " + "MyTestDatabase.db on the SDCard.")); try URI myuri = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createstatement("insert INTO People(Name,Age) " + "VALUES (?,?)"); st.prepare(); Hashtable ht = new Hashtable(4); ht.put("sophie", new Integer(6)); ht.put("karen", new Integer(3)); ht.put("kevin", new Integer(82)); ht.put("cindy", new Integer(12)); Enumeration names = ht.keys(); Enumeration ages = ht.elements(); while (names.hasmoreelements()) String strname = (String)names.nextElement(); Integer iage = (Integer)ages.nextElement(); st.bind(1,strname); st.bind(2,iage.intvalue()); st.execute(); st.reset(); 18

Utilizzo dei database SQLite st.close(); d.close(); catch ( Exception e ) System.out.println( e.getmessage() ); e.printstacktrace(); Uso dei pragma Il comando PRAGMA è una funzionalità di SQLite che consente di inviare una query allo schema, inviare una query e modificare i cookie dello schema e dell'utente, modificare il funzionamento della libreria SQLite ed eseguire il debug della libreria. I pragma supportati sono descritti nella classe Pragma. L'API Database supporta i seguenti comandi Pragma: Pragma collation_list compile_options database_list foreign_keys freelist_count Descrizione Consente di ottenere un elenco delle sequenze di confronto definite per la connessione al database corrente. Ad esempio, per ottenere un elenco di sequenze di confronto definite, eseguire l'istruzione SQL "PRAGMA collation_list;" e leggere le righe risultanti. Consente di ottenere i nomi delle opzioni relative all'ora di compilazione, utilizzati durante la creazione del database. Ad esempio, per ottenere le opzioni di compilazione per la libreria SQLite, eseguire l'istruzione SQL "PRAGMA compile_options;" e leggere le righe risultanti. Sarà disponibile un'opzione per riga. Consente di ottenere una riga per ciascun database allegato alla connessione al database corrente. Ad esempio, per ottenere un elenco dei database allegati per una connessione, eseguire l'istruzione SQL "PRAGMA database_list;" e leggere le righe risultanti. Sarà disponibile un nome database per riga. Consente di ottenere o impostare l'imposizione di vincoli di chiave esterna. Questa impostazione equivale all'utilizzo dell'opzione foreign_key_constraints nella classe DatabaseOptions. Ad esempio, per impostare l'imposizione di vincoli di chiave esterna, eseguire l'istruzione SQL "PRAGMA foreign_keys;" al di fuori di una transazione. Consente di ottenere il numero di pagine inutilizzate nel database, che è possibile utilizzare per determinare il momento in cui eseguire il comando VACUUM. 19

Utilizzo dei database SQLite Pragma journal_mode Descrizione Ad esempio, per ottenere il numero di pagine inutilizzate in un file del database, eseguire l'istruzione SQL "PRAGMA freelist_count;" e leggere la riga risultante. Consente di ottenere o impostare la modalità del diario della connessione al database corrente. Le impostazioni disponibili offrono prestazioni e livelli di sicurezza dei dati diversi. Tutte le opzioni, eccetto WAL e OFF, utilizzano un diario di ripristino. Le opzioni sono: DELETE: consente di eliminare il diario di ripristino al termine di una transazione (impostazione predefinita). TRUNCATE: consente di eseguire il commit delle transazioni, troncando il diario di ripristino su una lunghezza pari a zero. PERSIST: impedisce ad altre connessioni di ripristinare il diario. In questa modalità, il diario di ripristino può diventare molto grande, pertanto potrebbe essere opportuno controllarlo tramite journal_size_limit. MEMORY: consente di memorizzare il diario di ripristino nella RAM. WAL: costringe ad utilizzare un registro write-ahead invece di un diario di ripristino. OFF: consente di disattivare il diario di ripristino, disattivando di conseguenza le funzionalità di ripristino e commit atomico di SQLite. journal_size_limit page_count synchronous user_version Ad esempio, per controllare la modalità del diario, eseguire l'istruzione SQL "PRAGMA journal_mode;" e leggere la riga risultante. Per modificare la modalità del diario in un registro write-ahead, eseguire l'istruzione SQL "PRAGMA journal_mode = WAL;". Consente di ottenere o impostare il limite di dimensioni del diario, in byte. Ciò risulta utile quando journal_mode è impostato su PERSIST. Ad esempio, per controllare il limite di dimensioni del diario, eseguire l'istruzione SQL "PRAGMA journal_size_limit;" e leggere la riga risultante. Per impostare il limite di dimensioni del diario su 1000 byte, eseguire l'istruzione SQL "PRAGMA journal_size_limit = 1000;". Consente di ottenere il numero totale di pagine nel database. Consente di impostare la modalità sincrona per il database in uso. Le opzioni sono FULL (la modalità più sicura ma più lenta, nonché quella predefinita), NORMAL e OFF. Ad esempio, per controllare la modalità sincrona, eseguire l'istruzione SQL "PRAGMA synchronous;" e leggere la riga risultante. Per modificare la modalità sincrona in OFF, eseguire l'istruzione SQL "PRAGMA synchronous = 0;". Consente di ottenere o impostare una versione utente. La versione utente non è utilizzata da SQLite; è disponibile per l'utilizzo da parte dell'utente. La versione utente è un intero con firma a 32 bit. 20

Utilizzo dei database SQLite Pragma Descrizione Ad esempio, per impostare la versione utente su 123, eseguire l'istruzione SQL "PRAGMA user_version = 123;". Per controllare la versione utente, eseguire l'istruzione SQL "PRAGMA user_version;" e leggere la riga risultante. Utilizzo dei BLOB È possibile includere oggetti binari di grandi dimensioni nel database SQLite in uso. Per qualunque oggetto di dimensioni superiori a 1 MB, è necessario utilizzare gli oggetti InputStream e OutputStream per la lettura e la scrittura del BLOB. Questa tecnica evita il problema della memorizzazione dell'intero BLOB nella memoria. Se non si utilizza un flusso di flusso di input e uno di output, la quantità di memoria dinamica disponibile limita le dimensioni del BLOB che è possibile utilizzare. Per scrivere i dati in un BLOB, creare un oggetto OutputStream tramite il metodo Database.createBlobOutputStream. Per leggere i dati in un BLOB, creare un oggetto InputStream tramite il metodo Database.createBlobInputStream. È possibile riservare spazio per l'output del BLOB tramite il metodo Statement.bindZeroBlob. Questo metodo consente di associare una serie di byte nulli a un parametro in un'istruzione. È necessario chiudere sempre esplicitamente i BLOB, in modo che non esauriscano la memoria prima della chiusura del database. Nota: Tuttavia, possono verificarsi errori esterni alla memoria se si utilizzano i metodi Statement.bind che vengono utilizzati sugli array di byte o se si specifica direttamente un BLOB come parte di un'istruzione SQL. Nell'esempio di codice seguente, viene scritto un BLOB su una tabella e poi viene letto il BLOB dalla tabella. Database d = DatabaseFactory.openOrCreate("hello.db"); d.executestatement( "CREATE TABLE IF NOT EXISTS t (a INTEGER PRIMARY KEY, b BLOB);" ); d.executestatement( "INSERT INTO t(b) VALUES( ZEROBLOB( 1024 ) );" ); java.io.outputstream outputstream = d.createbloboutputstream( "t", "b", d.lastinsertedrowid( ) ); for( int i = 0; i < 1024; ++i ) outputstream.write( i % 128 ); outputstream.close( ); java.io.inputstream inputstream = d.createblobinputstream( "t", "b", d.lastinsertedrowid( ) ); for( int i = 0; i < 1024; ++i ) if( i % 128!= inputstream.read( ) ) fail( "write and read mismatch" ); inputstream.close( ); d.close(); 21

Utilizzo dei database SQLite Recupero dei dati della tabella Per eseguire una query che restituisca insiemi di risultati (come ad esempio un'istruzione SELECT), è necessario utilizzare il metodo Statement.getCursor. L'oggetto Cursor è una tabella temporanea che mantiene l'insieme di risultati. Quando l'oggetto Cursor è chiuso, la tabella temporanea viene ignorata. L'interfaccia Cursor offre un accesso di sola lettura all'oggetto Cursor. I cursori possono essere oggetto di query, proprio come avviene per le tabelle permanenti. Le colonne Cursor possono essere prese come riferimento da parte degli oggetti Column che vengono passati nelle query successive. L'implementazione predefinita dell'interfaccia Cursor non memorizza alcun dato nella cache; pertanto fornisce una navigazione unidirezionale, valida solo per l'inoltro. Un tentativo di accedere a una riga prima di quella corrente fornisce un risultato del tipo DatabaseException. La classe BufferedCursor memorizza nella cache i dati del cursore presenti in memoria e fornisce un accesso ai dati bidirezionale e casuale, ma esistono dei limiti sulla quantità di dati che è in grado di gestire. Il cursore del buffer potrebbe generare un OutOfMemoryError se viene utilizzato con insiemi di risultati di grandi dimensioni. Per impostazione predefinita, viene memorizzata nel buffer una riga alla volta. Quando il cursore si sposta oltre l'insieme di dati nel buffer, viene automaticamente recuperato un nuovo batch di righe. Per migliorare le prestazioni, potrebbe essere opportuno aumentare le dimensioni del buffer a un valore maggiore di 1. È possibile utilizzare il metodo Statement.setCursorBufferSize per specificare il numero di righe da memorizzare contemporaneamente nel buffer. In un cursore, esiste un limite di 1 MB di dati che è possibile memorizzare nel buffer. Nella maggioranza dei casi, questo limite è sufficiente. Se si prevede di superare tale limite, è possibile utilizzare più query per creare insiemi di risultati di dimensioni inferiori. È possibile, ad esempio, specificare le colonne da restituire in un'istruzione SELECT. Se si supera il limite, è necessario controllare se l'opzione setcursorbuffersize sia impostata su un valore troppo elevato. Se una riga per cui è in esecuzione una query contiene BLOB, è possibile utilizzare il metodo createblobinputstream per creare un oggetto InputStream, che non ha limiti di dimensioni. Quando si utilizza un oggetto InputStream, l'insieme di risultati non è limitato a 1 MB. Se il recupero dei dati risulta lento, provare a creare un indice di copertura. Un indice di copertura include tutte le colonne a cui si fa riferimento nella query. Esempio di codice: recupero dei dati della tabella import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.container.*; import net.rim.device.api.database.*; import net.rim.device.api.io.*; public class ReadData extends UiApplication public static void main(string[] args) ReadData theapp = new ReadData(); 22

Utilizzo dei database SQLite theapp.entereventdispatcher(); public ReadData() pushscreen(new ReadDataScreen()); class ReadDataScreen extends MainScreen Database d; public ReadDataScreen() LabelField title = new LabelField("SQLite Read Table Data Sample", LabelField.ELLIPSIS LabelField.USE_ALL_WIDTH); settitle(title); add(new RichTextField("Attempting to retrieve data from " + "MyTestDatabase.db on the SDCard.")); try URI myuri = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createstatement("select Name,Age FROM People"); st.prepare(); Cursor c = st.getcursor(); Row r; int i = 0; while(c.next()) r = c.getrow(); i++; add(new RichTextField(i + ". Name = " + r.getstring(0) + ", " + "Age = " + r.getinteger(1))); if (i==0) add(new RichTextField("No data in the People table.")); st.close(); d.close(); catch ( Exception e ) System.out.println( e.getmessage() ); e.printstacktrace(); Uso delle transazioni Le istruzioni SQLite vengono sempre eseguite nelle transazioni. Se l'istruzione viene eseguita correttamente, viene eseguito automaticamente il commit della transazione. Se l'istruzione non riesce, la transazione viene ripristinata. 23

Utilizzo dei database SQLite Per impostazione predefinita, viene creata una transazione separata per ogni istruzione SQLite. Questo approccio è meno efficiente rispetto all'esecuzione di più istruzioni in una sola transazione. In genere, è possibile migliorare le prestazioni specificando esplicitamente le transazioni per i gruppi di istruzioni. È possibile eseguire più istruzioni in una sola transazione utilizzando Database.beginTransaction() e Database.commitTransaction() in gruppi di istruzioni. Le transazioni annidate non sono supportate. Esempio di codice: utilizzo delle transazioni import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.container.*; import net.rim.device.api.database.*; import net.rim.device.api.io.*; public class UsingTransactions extends UiApplication public static void main(string[] args) UsingTransactions theapp = new UsingTransactions(); theapp.entereventdispatcher(); public UsingTransactions() class UsingTransactionsScreen extends MainScreen Database d; public UsingTransactionsScreen() LabelField title = new LabelField("SQLite Using Transactions Sample", LabelField.ELLIPSIS LabelField.USE_ALL_WIDTH); settitle(title); add(new RichTextField( "Updating data in one transaction in MyTestDatabase.db.")); try URI myuri = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); d.begintransaction(); Statement st = d.createstatement("update People SET Age=7 " + "WHERE Name='Sophie'"); st.prepare(); st.execute(); st.close(); st = d.createstatement("update People SET Age=4 " + "WHERE Name='Karen'"); st.prepare(); st.execute(); st.close(); d.committransaction(); d.close(); 24