Archivio

Archivio per la categoria ‘database’

Il motore sul banco: Android Sqlite database

android e sqlite3

Uno dei metodi messi a disposizione da Android per salvare in modo permanente i dati di un’applicazione è usando il database SQLite. Ogni applicazione può avere il suo database privato: il database non sarà accessibile all’esterno dell’applicazione. SQLite più che un database vero e proprio è definita come una libreria che implementa “a self-contained, serverless, zero-configuration, transactional SQL database engine”.

L’effetto pratico è quello di poter disporre di database embedded. Tipicamente abbiamo a che fare con dei database server (mysql, oracle, sqlserver…), dove un client si collega al server su cui gira database. I database embedded sono qualcosa di molto più semplice: semplificando all’estremo sono un file binario a cui si accede con un apposito client o una libreria. Il client è necessario per effettuare sviluppi e debug. Mentre un database server è pensato per avere più accessi simultanei, su un db embedded accede un solo processo [mi si perdoni la semplificazione estrema della faccenda].

Android permette di creare ed utilizzare un database embedded integrato nel sistema operativo. L’SDK mette anche a disposizione un tool (sqlite3) per accere al database anche da remoto.
Negli esempi che ho trovato on-line, si lavora un po’ alla cieca. Mi piacerebbe poter fare tutte le prove e verifiche che desidero sul database prima di affidare ai miei sorgenti gli script. La cosa è possibile.

Come creare un database locale e svincolato da Android

Prima di tutto si installi sqlite3. Io utilizzo Ubuntu e trovo sqlite3 nel repository dei packages: ancora più facile.

Installato il client sqlite3, si crei una cartella e la si raggiunga con una shell.

cd ~/Desktop
mkdir sqlitetest
cd sqlitetest

Si invochi il client, digitando (sempre dalla stessa shell):

sqlite3 test.db

Questo comando aprirà il client di sqlite e creerà un file di database nella posizione corrente. A dire il vero se uscissi, non troverei ancora nulla perchè il db è vuoto!

Per uscire dal client: .quit

Creiamo una tabella:

 CREATE TABLE coffee(cid INTEGER PRIMARY KEY AUTOINCREMENT, name varchar(20));

vediamo se la tabella esiste:

.tables

una insert:

insert into coffee (name) values ('java');

una select:

select * from coffee;

Di seguito un screenshot delle operazioni descritte.

Abbastanza scomodo! Siamo abituati ad usare tools più user friendly, vero? Possiamo farlo anche con SQLite.
Si può accedere a SQLite con un driver JDBC e quindi con un programma tipo DBVisualizer o SqlWorkbench/J

Vediamo come fare con SQL Workbench/J.

Per accedere da jdbc servono 4 cose: driver, url di connessione, utente, password.
driver:
url: jdbc:xxx:[path al file db] esempio: ~/Desktop/sqlitetest/test.db
utente e password si lascino vuoti.

definizione della connessione

La struttura del database

una select sulla tabella coffee

In questo modo si possono creare tabelle e verificare che tutto funzioni, per poi riportare gli script nella nostra applicazione su Android.

La stessa cosa funziona anche da Java, nel caso si voglia usare sqlite anche per applicazioni non Android (es. Swing). In tale caso si trovano anche alternative; tempo fa utilizzai con soddisfazione HsqlDb (ora HyperSQL), che tra l’altro può funzionare anche in modalità ‘server’.

Categories: android, database Etichette: , ,

D.I.Y.: Android Database Synchronization

In una recente migrazione dal mondo Microsoft ad Android, ho dovuto affrontare il tema della sincronizzazione dei database.
Intendo dire tabelle e record presenti sui database delle applicazioni client, con un database centrale.
Con Microsoft e SqlServer è abbastanza semplice: il database di Redmond mette a disposizione un framework di sincronizzazione trasparente agli utilizzatori, per cui è possibile sincronizzare i database.
I client sono smartphone con Windows Mobile (6.x) su cui è installata un App .Net (C#) con db SqlServer Compact.

Passando ad Android, si incontra qualche difficoltà. Molti parlano di sincronizzazione dati, ma intedono file o interi database. Qui si intende un’operazione più chirurgica. Anni fa, prima di adottare la soluzione Microsoft, mi capitò di dover sviluppare un tale framework in casa (al progetto ha contribuito molto Domenico Federico, emerito collega che si è occupato di affinare gli sviluppi in java su client e server). Nel nostro caso utilizzavamo il database PostgreSQL sia lato server che sui client. I client erano dei laptop dati indotazione ai macchinisti della società LeNord (gruppo FNM). Il sistema è tuttora in uso, ma utilizza la piattaforma MS (sigh! :-( )

La soluzione torna in auge con Android. E’ comunque qualcosa di ‘casalingo‘ e lo prenderei solo come un’esercizio. Il database utilizzato è SqlLite, lo stesso che troviamo su Android.

Il server

Sul server è necessario avere un database e poter installare dei WebService (del tipo che preferite: SOAP, Hessian, Rest…).
Servono le seguenti tabelle:

  1. SYNC_TABLES – registro delle tabelle che desidero sincronizzare,
  2. SYNC_MASTER – tabella di log per registrare le modifiche avvenute sulle tabelle sincronizzate,
  3. COFFEE – la tabella che voglio sincronizzare.

La SYNC_TABLES – ha un campo numerico (chiave, autoincrementante) e un campo testo con il nome della tabella che desidero sincronizzare:

  • id – integer not null autoincrement primary key – serve da id univoco per la tabella (per non trascinarmi dietro il nome)
  • tname – varchar – vero nome della tabella

Le tabelle per la sincronizzazione

La SYNC_MASTER – registra ogni operazione effettuata sulle tabelle ‘sotto sync’.

  • id – integer not null autoincrement primary key – chiave univoca dell’operazione
  • ts – timestamp – quando ho inserito (‘i’), modificato (‘u’) o cancellato (‘d’) una riga?
  • action – che operazione ho effettuato sulla riga? ‘i’,'u’ o ‘d’
  • tblid – su che tabella è avvenuta l’operazione? qui trovo l’id della tabella, come definiti in SYNC_TABLES.
  • rwid – su che riga della tabella è avvenuta la modifica? qui ho l’id univoco della riga della tabella; per questo ogni tabella deve avere un id univoco che sia chiave primaria e che questi id siano dello stesso tipo per tutte le tabelle sincronizzate!

La COFFEE – è la tabella che voglio sincronizzare. Ha solo 2 campi, un id (int, autoincrement not null…) e un campo name varchar(20) dove metto il nome dei caffè. Tutte le tabelle che voglio sincronizzare devono avere una chiave dello stesso tipo – per esempio int autoincrementante, questo perché le registrerò sempre nella tabella master.

Le DDL delle tabelle da creare sul server (sqllite):

CREATE TABLE coffee (
  cid INTEGER PRIMARY KEY AUTOINCREMENT,
  name varchar(20));

CREATE TABLE master_tables (
  tblid INTEGER PRIMARY KEY AUTOINCREMENT,
  tbname varchar(50));
INSERT INTO master_tables (tbname) values ('coffee');

CREATE TABLE master_sync(
  uid INTEGER PRIMARY KEY AUTOINCREMENT,
  tblid integer,
  act char(1),
  rwid integer,
  ts DateTime);

I TRIGGERS

Mi dispiace tanto, ma questa soluzione si basa sui triggers! Ogni tabella che desideriamo sincronizzare ne deve avere almeno 3:
uno sulle insert, uno sulle delete ed uno sulle update. Ogni volta che una riga della tabella viene modificata, il trigger scrive un riferimento nella tabella Master.

Ecco una possibile definizione dei trigger, nell’ipotesi che sia sul client che sul server stia utilizzando sqllite:

CREATE TRIGGER tt_i_coffee after INSERT ON coffee
  BEGIN
    INSERT INTO MASTER_SYNC
      (tblid,act,rwid,ts)
    values
      (1,'i', new.cid, CURRENT_TIMESTAMP );
  END;

CREATE TRIGGER tt_u_coffee after UPDATE ON coffee
  BEGIN
    INSERT INTO MASTER_SYNC
      (tblid,act,rwid,ts)
    values
      (1,'u', old.cid, CURRENT_TIMESTAMP );
  END;

CREATE TRIGGER tt_d_coffee after DELETE ON coffee
  BEGIN
    INSERT INTO MASTER_SYNC
      (tblid,act,rwid,ts)
    values
      (1,'d', old.cid, CURRENT_TIMESTAMP );
  END;

Cosa accade se inserisco un record su coffee, lo modifico e lo cancello?
Inserisco un caffe di nome ‘java’; l’autoincrement assegna id pari ad 8. Poi decido di modificare il nome del caffè in ‘arabica’. Dopo qualche minuto lo cancello del tutto.
Cosa avro’ nella master? Il log delle operazioni svolte.

Logging delle operazioni sulla tabella Master

Attenzione: le operazioni è bene che avvengano sempre in una ‘direzione’: sebbene sia possibile creare una sincronizzazione nei due sensi, la cosa è abbastanza sconsigliabile e complessa. Significa che mi troverò a conciliare modifiche avvenute sul server e sul client, magari conflittuali. Se possibile si segua questo approccio:
Il client è ‘slave’: non scrive direttamente nelle tabelle sincronizzate, ma esegue delle chiamate a webservices sul server per chiedere le modifiche, dopodichè scarica i dati con una sincronizzazione. Cosa fare se non ho connessione? salvo i dati (se sono così importanti) in una tabella temporanea o anche solo in memoria e provo la riscrittura fino a che non riottengo una connessione.

il flusso dei dati è unidirezionale

Il client

Sul client avro un database Sqllite (Android). Devo creare le tabelle che voglio sincronizzare, nel nostro caso la coffee. E’ necessario tenere traccia dell’ultima sincronizzazione andata a buon fine. L’informazione si può tenere anche su un file, ma magari è più pratico avere tutto nello stesso db, quindi creaiamo anche una tabella LAST_UPDATE con un solo campo: un timestamp con la data di aggiornamento.

La DDL delle tabelle da creare sul server (sqllite):

CREATE TABLE coffee (
  cid INTEGER PRIMARY KEY AUTOINCREMENT,
  name varchar(20));

CREATE TABLE last_update (
  last_update DateTime);

La tabella LAST_UPDATE

Quando il client avvia una sincronizzazione, recupera il timestamp dell’ultima sincro ed esegue una chiamata al server passando tale valore (es. tralasciando la data ed usando solo l’ora: 8:00:00). Il server mette da parte il timestamp in cui riceve la chiamata (le 9:30:01) e quindi esegue una select sulla tabella master:

  select
    *
  from sync_master
  where ts > '8:00:00'
  order by ts

Questa deve produrre una lista di operazioni da effettuare sul database del client. Le operazioni devono essere ordinate per timestamp e sono generate, prima esaminado la master e poi recuperando i dati dalle tabelle necessarie (nel nostro esempio abbiamo una sola tabella!).  Supponiamo siano in formato xml:

<sync last_update='9:30:01'>
 <insert table='1' ts='8:51:10'>
   <row>
     <col name='id'>1</col>
     <col name='name'>java</col>
   </row>
 </insert>

<update table='1' ts='8:52:57'>
  <row>
    <col name='id'>1</col>
    <col name='name'>arabica</col>
  </row>
</update>

<delete table='1' ts='9:01:02'>
  <row>
    <col name='id'>1</col>
  </row>
</delete>

</sync>

Il client riceve tale lista e la passa ad un DAO che implementa le operazioni di INSERT, UPDATE o DELETE. Sono possibili delle ottimizzazioni, ovviamente, omesse per semplicità. Tutte le operazioni si fanno all’interno di una transazione: l’ultima operazione è l’aggiornamneto della LAST_UPDATE, che viene imposta a ’9:30:01′.

Flussi tra client e server

Primary key auto incrementante su tabella postgresql

il database postgresCome aggiungere una colonna che sia anche chiave primaria ad una tabella dove tale colonna non sia stata prevista? Il database il oggetto è un postgresql 8.3; la tabella non ha una chiave primaria ed è già riempita con dei dati. Il campo che si aggiungerà sarà anche autoincrementante.

CREATE SEQUENCE rtest_seq;
ALTER TABLE registrazioni ADD rid INT UNIQUE ;
ALTER TABLE registrazioni ALTER COLUMN rid SET DEFAULT NEXTVAL(‘rtest_seq’);
UPDATE registrazioni SET rid = NEXTVAL(‘rtest_seq’);
ALTER TABLE registrazioni ADD PRIMARY KEY (rid);

 

Listare le tabelle di uno schema in SQLServer

09.04.2010 1 commento

Mi dimentico sempre come listare le tabelle di uno schema in SQLServer:

select table_name from INFORMATION_SCHEMA.TABLES 
where table_schema = 'dbo' and TABLES.TABLE_CATALOG = 'nome_del_database' 
and table_name like '%'
Categories: database Etichette:

Ripulire uno schema Oracle

Per eliminare tutte le tabelle e le viste in uno schema:

select ‘drop table ‘ || table_name || ‘ cascade constraints;’ from user_tables;

select ‘drop view ‘ || view_name || ‘;’ from user_views;

questi generano una serie di drop da salvare (SPOOL) su file di testo. Il file di testo si puo’ lanciare come script e lo schema risulta pulito.

Categories: database Etichette:

ORACLE – dump/restore di uno schema

Dumpare uno schema:

Collegarsi al server oracle. Da terminale digitare:

exp nomeutente/passwordutente@schema file=E:\nomedump.dmp log=E:\dump.log owner=nomeproprietarioschema consistent=Y statistics=ESTIMATE buffer=10000000

Restore di uno schema:

imp nomeutente/passwordutente@schema file=E:\dumpdaimportare.dmp log=E:\logimportazione.log fromuser=utenteorigine touser=utentedestinatario buffer=10000000 IGNORE=Y

nota: IGNORE forza l’import e non si ferma in caso di errori.

Categories: database
Iscriviti

Get every new post delivered to your Inbox.