Mostrar la Hora en un Applet Java

El siguiente programa es un ejemplo muy sencillo de un Applet Java que muestra la hora actual del sistema. Se usa la interfaz Runnable para poder preguntar cada segundo por la hora actual.

________________________________________________________
/*
 * Applet que muestra la hora en una etiqueta. 
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class AppletHour extends JApplet implements Runnable {

    private int hora, minutos, segundos;
    JLabel label;
    Calendar calendario;
    Thread h1;

    public void init() {
            getContentPane().setLayout(new BorderLayout());
            Container c = getContentPane();
            label = new JLabel(" ");
            label.setFont(new Font( "Helvetica", Font.BOLD, 50 ));
            c.add(label, BorderLayout.CENTER);
            h1 = new Thread(this);
            h1.start();
   }

    public void calcula () {

        Calendar calendario = new GregorianCalendar();
        hora = calendario.get(Calendar.HOUR_OF_DAY);
        minutos = calendario.get(Calendar.MINUTE);
        segundos = calendario.get(Calendar.SECOND); 
    }

    public void run() {
        Thread ct = Thread.currentThread();
        while(ct == h1) {   
            calcula();
            label.setText(hora + ":" + minutos + ":" + segundos);
            try {
           //System.out.println(hora + ":" + minutos + ":" + segundos);
                Thread.sleep(1000);
            }
            catch(InterruptedException e) {}
        }
    }

    public void stop() {
        h1 = null;
    }
}
________________________________________________________


Thread en Java

Los Thread (hilos) en Java,  se les suele llamar también procesos ligeros (lightweight processes). Éstos consumen menos recursos que la creación y ejecución de un proceso normal. La creación de un proceso duplica exactamente los mismos recursos que el proceso padre (el que le creó), esto implica el estado del proceso, el contador de programa, información de planificación, etc. Cuando se crea un thread en Java, lo único que necesita es el contador de programa la pila de ejecución, puesto que los demás recursos los comparte con el padre.

Creación de Thread en Java

Hay dos formas de crear los Thread.
  1. Heredando (extends) de la clase Thread. Esta clase se encuentra en el paquete java.lang. Este paquete se importa por defecto en todo programa Java.
  2. Implementando la interfaz Runnable. Esta interfaz se encuentra en el paquete java.lang.

Heredando de Thread

Es muy sencillo. Se hereda y se implementa el método run(). Cuando queramos poner en marcha el thread, se invoca al método start, no al run. El método start es que el planifica y asigna recursos al thread. Un ejemplo: en el método run, se hace un bucle grande e imprime cada 500 Iteraciones y el thread que lo está ejecutando. Variando esta cantidad, se ve como se alternan los thread.

________________________________________________________
/* 
 *  Método 1: Heredando de la clase Thread
 *  La clase Thread pertenece al paquete  
 *  java.lang que se importa por defecto.
 */

public class TestThread extends Thread {

    public static void main (String []args) {
    
        TestThread h1 = new TestThread();
        TestThread h2 = new TestThread();
        //Creamos 2 thread
        h1.start();
        h2.start();
    }

    //Si se hereda de la clase Thread, se debe 
    //implementar el método run()
    public void run() {
        for (int i = 0; i < 500000; i++)
            if ((i % 500) == 0)
                System.out.println(getName()+ " : " + i);
    }
}
________________________________________________________


Implementando la interfaz Runnable

Java no permite herencia múltiple. Por eso disponemos de la interfaz Runnable y así "permitir" herencia múltiple. Lo que tenemos que hacer es implementar, al igual que antes, el método run(). Además, para crear el Thread, ahora tenemos que crearnos un dato nuevo de tipo Thread y pasarle como argumento (en el contructor) el tipo implementado con la interfaz Runnable. Se ve mejor con un ejemplo.
________________________________________________________
 
public class TestRunnable implements Runnable {

    //Dato
    int hilo;
    public TestRunnable(int hilo) {
        this.hilo = hilo;
    }

    public static void main (String []args) {
        (new Thread(new TestRunnable(0))).start();
        (new Thread(new TestRunnable(1))).start();
    }

    public void run () {
        for (int i = 0; i < 500000; i++) {
            if ((i % 500) == 0)
                System.out.println(hilo + " : " + i);
        }
    }
}  

__________________________________________


Referencias:

Generando un makefile con fpcmake

Con FreePascal, existe una herramienta llamada fpcmake que genera un makefile a partir de un fichero de configuración, y así poder usar el make de GNU.

Instalación

En Ubuntu, esta herramienta está incluida en el paquete fp-utils (Un único paquete de 3730kB). Para instalarla hacemos:

$ sudo apt-get install fp-utils



Fichero de configuración

El fichero de configuración tiene que llamarse makefile.fpc . En él, escribimos los nombres de los fuentes (units, ficheros principales y ejemplos), versión del compilador a usar, nombre de paquete, versión, etc. No son obligatorias todas las etiquetas, lo que, si no se definen, no estarás dichas disponibles las opciones en el makefile.

Algunas de las secciones son las siguientes:
 
[target]
Esta sección es la más importante del fichero makefile.fpc. Es donde están especificadas las reglas para compilar todo (make all) y de donde se coge el make default. Algunas de las opciones son:
  • programs: lista de programas separadas por espacio sin la extensión .pas. El fpcmake los pone automáticamente.
  • units : lista de unidades separadas por espacios sin la extensión. El fpcmake los pone automáticamente.
  • examples: lista de programas de ejemplo. Al igual que los dos anteriores, separados por espacio y sin extensión. 


[compiler]
En esta sección se puede especificar:
  • version: en esta sección se puede especificar la versión del compiladors
  • options: las opciones para compilar. Por ejemplo, le podemos pasar -g para depurar.
  • unitdir: lista de directorios separados por dos puntos de las units incluidas (si están en otro directorio). Hay que pasarle al compulador la opción -Fu.

[package]
Un paquete es un conjuto de units. En esta sección se pueden especificar:
  • name: nombre del paquete.
  • version: versión del paquete
  • main: para indicar el paquete forma parte de otro paquete.
 Existen más secciones como install (donde se especifican los directorios donde se colocarán los programas y datos), dist, para crear una distribución de los programas etc.
Para más detalle, se puede consultar el manual en consola:

$ man 5 fpcmake



Otra fuente es el apéndice E de la guía de programadores de freepascal. link. Aquí está todo bien detallado.

Un ejemplo sencillo es el siguiente:

$ cat -n makefile.fpc
     1    [target]
     2    programs=main             #Programa principal
     3    units=unit1 unit2          #Todas las units
     4    examples=test1 test2   #Programas ejemplo
     5   
     6   
     7    [compiler]
     8    version=2.2.2-8
     9    options=-g   #opciones del compilador
    10   






Generar el Makefile

Una vez hecho el archivo de configuración hacemos:

$ fpcmake
Processing makefile.fpc
 i386-linux requires: rtl
 Writing Makefile





Usando make

Con el makefile generado, tenemos múltiples opciones. Algunas de ellas son:
  • make                 : compila los princiales más las units especificadas.
  • make examples: compila los programas ejemplos.
  • make clean       : borra todos los .o y .ppu 
  • make install     : instala los programas más las units.
  • make info           : devuelve información acerca del programa, directorios de trabajo, versión, librerías, etc.

Nota: cuando hacemos el make, se nos crea una carpeta units/ donde se van a colocar todos los .o y .ppu. Al hacer make clean, se borrarán de este directorio.

#bug en versiones debian

Hay un bug en versiones del compilador 2.2.0 para sistemas de 64 bits:


$ fpcmake -v 
FPCMake Version 2.0.0 [2009/01/08]
Processing makefile.fpc
 Targets: "x86_64-linux"
 Globals:
    FPCDIR = ""
    PACKAGESDIR = "$(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra $(FPCDIR)/packages"
    UNITSDIR = "$(FPCDIR)/units/$(FULLTARGET)"
    BASEDIR = "/home/juanjo/Desktop/Clases0910/FreePascal/listas"
 Required packages for linux-x86_64: rtl
 Package "rtl": Looking for Makefile.fpc: " /packages/rtl/Makefile.fpc /packages/base/rtl/Makefile.fpc /packages/extra/rtl/Makefile.fpc /packages/rtl/Makefile.fpc "
 Package "rtl": Looking for Package.fpc: " /units/x86_64-linux/rtl/Package.fpc "
Error: Target "linux", package "rtl" not found



Enlace del bug: http://bugs.freepascal.org/view.php?id=10775

Manual básico de gdb

El depurador gdb (GNU Debugger) es el depurador estándar de Linux. Fue creado por Richard Stallman en el año 1988. Después de esta introducción de wikipedia, pasamos a ver como se usa.

Con gdb podemos depurar código C/C++, Pascal, y Ada. Es un depurador de línea de comandos, aunque existe una parte gráfica llamada DDD. A mí personalmente, el DDD me dio muchos problemas. Me fío más de la línea de comandos.

Para usarlo, es necesario compilar el fuente con la opción de depuración, para C, C++ y Pascal, dicha opción es -g.


Programa de ejemplo pascal para probar con gdb.
______________________________________________________
program ejemplo;

procedure proc ();
var
  i : integer;
begin
  for i := 1 to 10 do
    writeln('In for: ', i);
end;
  
begin
  writeln('This is the first line');
  proc();
end.
______________________________________________________

Compilamos con la opción -g

$ fpc -g ejemplo.pas



Cargando el depurador

$ gdb ./ejemplo
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
(gdb)




Listar el código

Para listar el código usamos el comando list o l simplemente. El patrón es el siguiente:
list | l lineInit, lineEnd

Ejemplo:

(gdb) list 1, 5
1    program ejemplo;
2  
3    procedure proc ();
4    var
5      i : integer;
(gdb)



Nota: Si le damos a ENTER sin ninguna opción, se vuelve a repetir el último comando.

(gdb)
6    begin
7      for i := 1 to 10 do
8        writeln('In for: ', i);
9    end;
10     
11   
12    begin
13      writeln('This is the first line');
14      proc();
15    end.(gdb)




 Colocar breakpoints

Para colocar breakpoints usamos el comando break  line, o b line, donde line es el número de línea que queremos el breakpoint. Suponer que la queremos colocar el la línea 13.

(gdb) b 13
Breakpoint 1 at 0x400229: file ejemplo.pas, line 13.




Comenzar la ejecución

Una vez tengamos hayamos puesto puntos de ruptura (también se podría poner wachpoint y catchpoint) pasamos a ejecutar el programa. Para ello usamos la instrucción run.

(gdb) run
Starting program: /home/user/Desktop/ejemplo

Breakpoint 1, main () at ejemplo.pas:13
13      writeln('This is the first line');
(gdb)




Traza

Ahora tenemos varias posibilidades:
  1. Ir paso a paso pasando por cada función: usamos step
  2. Ejecutar la instrucción actual: usamos stepi
  3. Ir paso a paso sin pasar por cada función: cont.
Por ejemplo:

(gdb) step
This is the first line
14      proc();
(gdb)
PROC () at ejemplo.pas:7
7      for i := 1 to 10 do
(gdb)
8        writeln('In for: ', i);
(gdb)
In for: 1
7      for i := 1 to 10 do
(gdb)
8        writeln('In for: ', i);

(gdb) cont
Continuing.
In for: 2
In for: 3
In for: 4
In for: 5
In for: 6
In for: 7
In for: 8
In for: 9
In for: 10

Program exited normally.




Imprimir el valor de una variable

Para mostrar por pantalla el valor de una variable usamos la instrucción print nombre_variable.


(gdb) step
8        writeln('In for: ', i);
(gdb) print i
$3 = 1




Limpiar la lista de breakpoints

Para quitar un breakpoint, usamos clear num_Line. Donde num_Line es el número de línea donde teníamos un breakpoint. Si no nos acordamos la línea en la que lo hemos puesto, usamos el comando info breakpoints.

Para eliminar todos los breakpoints usamos delete breakpoints.

Ejemplo:

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x0000000000400229 in main at ejemplo.pas:13
4       breakpoint     keep y   0x00000000004001ac in PROC at ejemplo.pas:7

(gdb) delete breakpoints
Delete all breakpoints? (y or n) y
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb)


Uso básico de subversion

Subversion es un sistema de control de versiones bajo Licencia Apache. Creado para sustituir a CVS.

Instalando subversion 

Lo podemos descargar desde la página principal de subversion. Si estamos un ubuntu podemos hacer:

$ sudo apt-get install subversion

Existen también interfaces gráficas para subversion como son KdeSVN y Tortoise.

Sistema de Control de Versiones  
   
Un sistema de control de versiones (por dar una definición distinta a los miles de páginas que hablan de esto) es un programa que permite la copia nuestros documentos sin tener que recurrir a copiarlos con distinto nombre, o en directorios distintos mientras lo estamos desarrollando.
Por ejemplo. suponer que estamos desarrollando un programa en C. Podríamos tener una primer programa que funcione, pero que para nada está completada. Pues una primera versión podría ser esta. Al segundo día de desarrollo, mejoramos la interactividad con el usuario y tocamos muchas cosas del código. Si no nos funciona pueden pasar dos cosas: 
a) Que tengamos una copia de seguridad por cualquier otro lado y recuperarla.
b) Que no la tengamos y si no nos funciona, nos la tenemos que ingeniar para arreglarlo.

Al usar subversion, guardaríamos los cambios en un repositorio, tantas veces como queramos. Si luego, nos hiciera falta volver a una versión anterior, o queremos saber lo que hicimos el 2 de diciembre del 2005 (siempre y cuando esté en el repositorio), podríamos recuperarlo con un simple comando. Esa es la idea, facilitar al desarrollador la creación de programas.  Es más, si hay varios desarrolladores trabajando, cada uno se baja del repositorio los últimos cambios, y al finalizar los expone para que sus compañeros sigan trabajando sin necesidad de tener cientos de carpetas.


Subversion está pensado principalmente para trabajar con ficheros de texto, como es el código fuente de programas. Esto no quiere decir que en nuestro repositorio podamos subir imágenes, ficheros word, etc, pero hay que tener cuidado, porque subversion almacena las diferencias de un fichero a otro. Si es un fichero de texto, las diferencias son las líneas de texto (o trozos de texto, si se quiere ver así) en las que cambia. Mientras que si subimos un fichero binario, al hacer el mínimo cambio, su representación binario es diferente, con lo cuál, el fichero binario será completamente distinto al del repositorio. Esto implica que el repositorio aumentará de tamaño dependiendo del binario y del número de veces que lo versionemos. Por eso, en este aspecto hay que tener cuidado. 

Lo que se suele hacer es versionar los fuentes (ficheros de texto), que es con lo que se trabaja día a día. Si acaso alguna imagen (iconos) que son imágenes que no suelen cambiar.


Creando un repositorio

La forma de crear un repositorio es con el comando svnadmin. Se entenderá mejor con un ejemplo.

$ svnadmin create MiRepositorio

Esto crea una jerarquí de directorios como la siguiente:

$ tree MiRepositorio/
MiRepositorio/
|-- README.txt
|-- conf
|   |-- authz
|   |-- passwd
|   `-- svnserve.conf
|-- db
|   |-- current
|   |-- format
|   |-- fs-type
|   |-- revprops
|   |   `-- 0
|   |       `-- 0
|   |-- revs
|   |   `-- 0
|   |       `-- 0
|   |-- transactions
|   |-- txn-current
|   |-- txn-current-lock
|   |-- txn-protorevs
|   |-- uuid
|   `-- write-lock
|-- format
|-- hooks
|   |-- post-commit.tmpl
|   |-- post-lock.tmpl
|   |-- post-revprop-change.tmpl
|   |-- post-unlock.tmpl
|   |-- pre-commit.tmpl
|   |-- pre-lock.tmpl
|   |-- pre-revprop-change.tmpl
|   |-- pre-unlock.tmpl
|   `-- start-commit.tmpl
`-- locks
    |-- db-logs.lock
    `-- db.lock

10 directories, 25 files


No os preocupéis, en principio no hay que tocar nada de aquí, afortunadamente.


Importar un proyecto

Una vez creado el repositorio, lo que tenemos que hacer es importar nuestros ficheros y directorios donde estábamos haciendo el desarrollo. Suponer la siguiente jerarquía de proyecto:

$ tree Proyecto/
Proyecto/
|-- Dos
`-- Uno
    `-- file.txt

2 directories, 1 file

Dos carpetas y un fichero. Ahora queremos subir esto al repositorio. A este paso se le llama importar el proyecto.


$ svn import /tmp/MiProyecto/ file:///tmp/MiRepositorio/ -m "Creación del proyecto"
Añadiendo      /tmp/Proyecto/Uno
Añadiendo      /tmp/Proyecto/Uno/file.txt
Añadiendo      /tmp/Proyecto/Dos

Commit de la revisión 1.

Donde los argumentos son:
  1. La ruta donde está el proyecto a importar.
  2. La ruta del repositorio.
  3. Comentario acerca de la versión

Ya podemos borrar la jerarquía de proyecto. Ahora solo nos hace falta el repositorio.


Espacio de trabajo

Una vez importado, creamos el espacio de trabajo, que podría ser el el home mismo. Para bajarnos la última versión del programa usamos el argumento checkout de subversion.

$ svn checkout file:///tmp/MiRepositorio/

El segundo argumento es la ruta completa donde está el repositorio. Se nos crea, en el directorio donde lo hayamos hecho, la jerarquía que teníamos del proyecto, con la peculiaridad de que ahora tenemos unos archivos .svn donde estará la información necesaria para comunicarse con el repositorio.

Comandos de trabajo

Los comandos más comunes para el trabajo diario son:

svn update  :  actualiza el repositorio.

$ svn update 
En la revisión 1.


svn add file :  añade un fichero o un conjunto de ficheros al repositorio.

$ svn add file2.txt


svn commit :  guarda los cambios y crea una nueva versión.

$ svn commit -m "Comentario de la version"
Añadiendo      Uno/file2.txt
Transmitiendo contenido de archivos .
Commit de la revisión 2.


Si queremos volver a una versión anterior, una de las formas es asociarla por el comentario que se hizo cuando se produjo el commit.


$ svn log
------------------------------------------------------------------------
r2 | user | 2009-09-17 20:14:37 +0100 (jue 17 de sep de 2009) | 1 line

Comentario de la version
------------------------------------------------------------------------
r1 | user | 2009-09-17 19:52:08 +0100 (jue 17 de sep de 2009) | 1 line

Creación del proyecto
------------------------------------------------------------------------



Por tanto, si ahora queremos recuperar la primera hacemos un checkout de la primera.

$ svn checkout -r 1 file:///tmp/MiRepositorio/ Rev2

Le pasamos -r y luego el número de la versión. La última cadena "Rev2" es simplemente para colocarlo en un directorio llamado Rev2. Lo crea dinámicamente.
Para ver las diferencias usamos la opción diff. Por ejemplo, para ver la diferencia entre la versión 1 y la 2 hacemos:

$ svn diff -r 1:2 file:///tmp/MiRepositorio/
Index: Uno/file2.txt
============================================



Manuales 

No es muy complicado de usar, al menos lo básico y una vez que se acostumbre es muy útil. Esto no es más que un pequeño comienzo. Para ver manuales y tutoriales están las siguiente urls.
  1. http://chernando.eu/doc/svn/
  2. http://svnbook.red-bean.com/

Copias de seguridad en MySQL

Hay dos métodos para hacer copias de seguridad. Yo explicaré los dos, aunque el recomendable es el segundo, que hace uso del comando mysqldump.


Método 1: Copiar archivos de la base de datos

Este método es a pelo, es decir, coger directamente los archivos dentro de la jerarquía de directorios de mysql donde están definidas las bases de datos. Este método no se recomienda porque pueden haber diferencias de formatos entre distintas versiones de MySQL, si lo que pretendemos es traspasar la base de datos de una máquina a otra. En Windows, la ruta donde se guardan las bases de datos es parecida a la siguiente: 
C:\Archivos de programa\MySQL\MySQL Server5.X\data[nombreBaseDeDatos]

Donde X completa la versión que tengamos de MySQL. En sistemas Linux y Mac OS x se encuentra en /var/lib/mysql/


Método 2: Uso del comando mysqldump

El segundo método, y el recomendado es hacer uso de comando mysqldump. Este comando tiene múltiples opciones. Veremos aquí sólo algunas de ellas. Lo necesario para sobrevivir. Por supuesto, siempre queda la documentación.

$ man mysqldump

La ventaja de usar este comando, es que no depende de la versión y funciona igual en cualquier máquina. La sintaxis típica para este comando es:

$ mysqldump -u usuario -p objeto_a_respaldar

El objeto a respaldar puede ser toda la base de datos, una base de datos en concreta, una tabla o un conjunto de tablas. Para verlo mejor, hacemos una ejemplos. Suponer que tenemos una base de datos test y una tabla dentro de esa base de datos que se llama cliente.

Respaldo de base de datos: Vamos a copiar la base de datos test:

$ mysqldump -u root -p test > test.bk.sql


Respaldo de una tabla: Vamos a respaldar la tabla cliente.

$mysqldump -u root -p test cliente > cliente.bk.sql


Respaldo de toda la base de datos:

$ mysqldump -u root -p --all-databases > database.bk.sql



Restaurar la base de datos

Si queremos recuperar los datos, es  muy sencillo. Si hemos usado el método de coger directamente el archivo, es llevarlo nuevamente a su sitio correspondiente. Si hemos usado el comando mysqldump queda como sigue.

Si hemos hecho copia de toda la base de datos (--all-databases) la recuperación queda:


$ mysql -u root -p < databases.bk.sql

Si hemos hecho una copia selectiva de alguna base de datos, hay que añadirle la opción -D.

$ mysql -u root -p -D test < test.bk.sql

Creación de tablas en MySQL

En este post, me centraré en cómo crear tablas, inserción de datos y hacer consultas sencillas usando MySQL. Todo esto lo haré desde la línea de comandos.

Creación de tablas

La sintaxis es la siguiente, de forma muy reducida.

mysql> CREATE TABLE nombre_tabla (
nombre_columna1 tipo_dato opciones, 
nombre_columna2 tipo_dato opciones ...);

nombre_tabla y nombre_columna son los nombres que les queramos dar. Los tipo de datos más comunes son:

1. Numéricos
  • int (tamaño): entero de 4 bytes.
  • bigint(tamaño): entero largo de 8 bytes.
  • float (precisión): flotante de 24 dígitos.
  • double(precisión): real de 53 dígitos.

2. Cadenas
  • char(tamaño): cadenas de longitud fija.
  • varchar(tamaño): cadenas de longitud variable.

3. Fechas
  • date : almacena una fecha en formato 'AAAA-MM-DD'
  • datetime: almacena una fecha y una hora: 'AAAA-MM-DD HH:MM:SS'
  • time: almacena la hora. 'HH:MM:SS'

Las opciones más comunes son las siguientes:
  • not null: no permitimos que la columna tenga valores nulos.
  • primary key: establecemos la clave primaria de la tabla.
  • foreign key: establecemos la clave ajena de la tabla. 
 ________________________________________________________

Ejemplo: Se desea crear una tabla Cliente que tenga como atributos el DNI, el nombre y la edad. Cada cliente se identifica por su DNI, por lo que ésta será su clave primaria.

create table cliente (
dni VARCHAR(9) NOT NULL,
nombre VARCHAR(50),
edad INT(3),
PRIMARY KEY (dni));  


Insertar filas en las tablas

Ahora vamos a insertar filas. Es muy sencillo. La sintaxis es la siguiente:

mysql>INSERT INTO nombre_tabla VALUES (
valor1, valor2, ... , valorn)

donde n es igual al número de columnas de la tabla.

Por ejemplo: si queremos insertar un cliente en la tabla creada anteriormente sería:

INSERT INTO cliente VALUES (
"12345678A", "peter", 22
);


Selección de filas

Si queremos ver las filas insertadas la forma es mediante la instrucción SELECT.

mysql> SELECT nombre_Col1, nombre_Col2, 
FROM nombre_tabla
WHERE (condición);

Esta es la forma general. Por ejemplo, si quisiéramos ver todas las filas y las columnas haríamos:

SELECT * FROM cliente;

El siguiente ejemplo muestra sólo los dni de los clientes que sean menores de 30 años. Esta restricción se la especificamos en la cláusula WHERE.

SELECT dni
FROM cliente
WHERE (edad < 30);

Todo esto no es más que una pequeñísima instrucción a MySQL. Para ampliar no hay nada mejor que los manuales de referencia de mysql.