Grails z MySQL
Z Jacek Laskowski - Wiki Projektanta Java EE
Spis treści |
Wprowadzenie
Domyślna konfiguracja Grails obejmuje uruchomienie aplikacji z wbudowaną bazą danych HSQL. Takie podejście pozwala na natychmiastowe budowanie aplikacji webowych bez konieczności zestawiania środowiska uruchomieniowego z bazą danych. Po prostu ją mamy. W tym artykule przedstawię, co jest potrzebne do uruchomienia aplikacji grailsowej z MySQL.
Instalacja i zarządzanie serwerem MySQL
Rozpoczynamy od pobrania MySQL z jego strony domowej mysql.org wraz ze sterownikiem JDBC - Connector/J. Instalacja sprowadza się do wykonania serii kroków z pomocą asystenta instalacji (baza danych) bądź rozpakowania do wybranego katalogu (baza danych i sterownik JDBC).
Instalacja na Linux/MacOS X/Unix
Po rozpakowaniu paczki instalacyjnej, np. mysql-5.5.16-osx10.6-x86_64.tar.gz, wykoujemy serię poleceń, które tworzą przykładową bazę i zakładają użytkownika administracyjnego root.
$ ./bin/mysqladmin version ./bin/mysqladmin Ver 8.42 Distrib 5.5.16, for osx10.6 on i386 Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Server version 5.5.16 Protocol version 10 Connection Localhost via UNIX socket UNIX socket /tmp/mysql.sock Uptime: 5 min 9 sec Threads: 1 Questions: 5 Slow queries: 0 Opens: 33 Flush tables: 1 Open tables: 26 Queries per second avg: 0.016 jacek:~/apps/mysql $ scripts/mysql_install_db --user=jacek Installing MySQL system tables... OK Filling help tables... OK To start mysqld at boot time you have to copy support-files/mysql.server to the right place for your system PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER ! To do so, start the server, then issue the following commands: ./bin/mysqladmin -u root password 'new-password' ./bin/mysqladmin -u root -h devmac.local password 'new-password' Alternatively you can run: ./bin/mysql_secure_installation which will also give you the option of removing the test databases and anonymous user created by default. This is strongly recommended for production servers. See the manual for more instructions. You can start the MySQL daemon with: cd . ; ./bin/mysqld_safe & You can test the MySQL daemon with mysql-test-run.pl cd ./mysql-test ; perl mysql-test-run.pl Please report any problems with the ./bin/mysqlbug script! $ ./bin/mysqld_safe & 111014 20:53:02 mysqld_safe Logging to '/Users/jacek/apps/mysql/data/devmac.local.err'. 111014 20:53:02 mysqld_safe Starting mysqld daemon with databases from /Users/jacek/apps/mysql/data jacek:~/apps/mysql $ ./bin/mysqladmin -u root password 'passw0rd' $ ./bin/mysql -u root -p Enter password: passw0rd
Uruchomienie
Na systemach uniksowych, np. MacOS X czy Linux, polecenie uruchomienia i zatrzymania serwera bazodanowego MySQL sprowadza się do następujących poleceń:
$ ./bin/mysqld_safe 110622 08:35:52 mysqld_safe Logging to '/Users/jacek/apps/mysql/data/devmac.local.err'. 110622 08:35:52 mysqld_safe Starting mysqld daemon with databases from /Users/jacek/apps/mysql/data
Poprawne uruchomienie powoduje pojawienie się następujących wpisów w dzienniku data/devmac.local.err.
$ tail -f /Users/jacek/apps/mysql/data/devmac.local.err InnoDB: Doublewrite buffer not found: creating new InnoDB: Doublewrite buffer created InnoDB: 127 rollback segment(s) active. InnoDB: Creating foreign key constraint system tables InnoDB: Foreign key constraint system tables created 110622 8:35:52 InnoDB: Waiting for the background threads to start 110622 8:35:53 InnoDB: 1.1.7 started; log sequence number 0 110622 8:35:53 [Note] Event Scheduler: Loaded 0 events 110622 8:35:53 [Note] /Users/jacek/apps/mysql/bin/mysqld: ready for connections. Version: '5.5.13' socket: '/tmp/mysql.sock' port: 3306 MySQL Community Server (GPL)
Zatrzymanie sprowadza się do wciśnięcia Ctrl-C w terminalu, w którym uruchomiono MySQL lub (preferowany sposób) wydaniu polecenia mysqladmin shutdown podając użytkownika z prawami SHUTDOWN (więcej w dokumencie 5.1.10. The Shutdown Process).
$ ./bin/mysqladmin -u root -p shutdown Enter password: passw0rd
W dzienniku pojawi się wiadomość o zamknięciu serwera MySQL.
$ tail -f /Users/jacek/apps/mysql/data/devmac.local.err 110622 8:41:26 [Note] /Users/jacek/apps/mysql/bin/mysqld: Normal shutdown 110622 8:41:26 [Note] Event Scheduler: Purging the queue. 0 events 110622 8:41:26 InnoDB: Starting shutdown... 110622 8:41:27 InnoDB: Shutdown completed; log sequence number 1595675 110622 8:41:27 [Note] /Users/jacek/apps/mysql/bin/mysqld: Shutdown complete
Aplikacja grailsowa - grailsmysql
Stwórzmy przykładową aplikację, która początkowo korzysta z HSQL, a w kolejnym kroku zdefiniujemy konfigurację uruchomieniową z MySQL.
Utworzenie aplikacji - grails create-app
Zaczynamy od stworzenia struktury katalogowej projektu poleceniem grails create-app grailsmysql.
$ grails create-app grailsmysql
Welcome to Grails 1.4.0.M1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/jacek/apps/grails
Base Directory: /Users/jacek/sandbox
Running script CreateApp_.groovy
Environment set to development
[mkdir] Created dir: /Users/jacek/sandbox/grailsmysql/src
...
Created Eclipse project files.
Created Grails Application at /Users/jacek/sandbox/grailsmysql
Uruchomienie grails create-app jest stworzeniem zrębu aplikacji i już w tym momencie możliwe jest jej uruchomienie (poleceniem grails run-app). Nie łudźmy się jednak odnośnie jej funkcjonalności - owa aplikacja sprowadzi się do pojedynczej strony powitalnej, która wyświetla listę dostępnych kontrolerów, a skoro nie mamy jeszcze żadnego (za moment go stworzymy), pojawi się jedynie statyczny tekst.
Przechodzimy do katalogu projektu grailsmysql.
$ cd grailsmysql/
Utworzenie klasy dziedzinowej - grails create-domain-class
Kolejnym krokiem jest utworzenie klasy dziedzinowej pl.jaceklaskowski.grails.Ksiazka poleceniem grails create-domain-class pl.jaceklaskowski.grails.Ksiazka.
$ grails create-domain-class pl.jaceklaskowski.grails.Ksiazka
Welcome to Grails 1.4.0.M1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/jacek/apps/grails
Base Directory: /Users/jacek/sandbox/grailsmysql
Running script CreateDomainClass.groovy
Environment set to development
[mkdir] Created dir: /Users/jacek/sandbox/grailsmysql/grails-app/domain/pl/jaceklaskowski/grails
Created /Users/jacek/sandbox/grailsmysql/grails-app/domain/pl/jaceklaskowski/grails/Ksiazka.groovy for Ksiazka
[mkdir] Created dir: /Users/jacek/sandbox/grailsmysql/test/unit/pl/jaceklaskowski/grails
Created /Users/jacek/sandbox/grailsmysql/test/unit/pl/jaceklaskowski/grails/KsiazkaTests.groovy for Ksiazka
Zmieniamy treść klasy dziedzinowej Ksiazka (plik grails-app/domain/pl/jaceklaskowski/grails/Ksiazka.groovy) na następującą:
package pl.jaceklaskowski.grails
class Ksiazka {
String tytul
String autor
static constraints = {
tytul(blank: false)
autor(blank: false)
}
}
Utworzenie kontrolera - grails create-controller
Dla stworzonej klasy dziedzinowej Ksiazka tworzymy odpowiedni kontroler poleceniem grails create-controller pl.jaceklaskowski.grails.Ksiazka.
$ grails create-controller pl.jaceklaskowski.grails.Ksiazka
Welcome to Grails 1.4.0.M1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/jacek/apps/grails
Base Directory: /Users/jacek/sandbox/grailsmysql
Running script CreateController.groovy
Environment set to development
[mkdir] Created dir: /Users/jacek/sandbox/grailsmysql/grails-app/controllers/pl/jaceklaskowski/grails
Created /Users/jacek/sandbox/grailsmysql/grails-app/controllers/pl/jaceklaskowski/grails/KsiazkaController.groovy for Ksiazka
[mkdir] Created dir: /Users/jacek/sandbox/grailsmysql/grails-app/views/ksiazka
Created /Users/jacek/sandbox/grailsmysql/test/unit/pl/jaceklaskowski/grails/KsiazkaControllerTests.groovy for Ksiazka
Modyfikujemy klasę kontrolera KsiazkaController (plik grails-app/controllers/pl/jaceklaskowski/grails/KsiazkaController.groovy) tak, aby zawierała poniższą treść:
package pl.jaceklaskowski.grails
class KsiazkaController {
def scaffold = Ksiazka
}
Istotnym elementem kontrolera jest wykorzystanie dynamicznego rusztowania (ang. dynamic scaffolding), gdzie widoki odpowiadające akcjom CRUD (ang. Create-Read-Update-Delete) są tworzone w pamięci, dynamicznie. Wystarczy zdefiniować statyczną zmienną scaffold z wartością, która wskazuje na obsługiwaną klasę dziedzinową (wartość to nazwa klasy, jednakże w Groovy Ksiazka == Ksiazka.class i dodawanie .class nie jest konieczne).
Uruchomienie aplikacji - grails run-app
W tym momencie możemy już uruchomić aplikację poleceniem grails run-app.
$ grails run-app Welcome to Grails 1.4.0.M1 - http://grails.org/ Licensed under Apache Standard License 2.0 Grails home is set to: /Users/jacek/apps/grails Base Directory: /Users/jacek/sandbox/grailsmysql Running script RunApp.groovy Environment set to development ... Running Grails application.. Server running. Browse to http://localhost:8080/grailsmysql
Po jej uruchomieniu, wystarczy skierować przeglądarkę na adres http://localhost:8080/grailsmysql i cieszyć się "pięknem" naszej aplikacji grailsowej.
Wykonanie kilku czynności w aplikacji powinno upewnić nas, że domyślna konfiguracja bazodanowa z H2 działa poprawnie. Czas na włączenie konfiguracji MySQL.
Konfiguracja połączenia z MySQL
Zmiana konfiguracji aplikacji - grails-app/conf/DataSource.groovy
Jak mogliśmy zauważyć podczas uruchamiania poleceń grails, jednym z komunikatów była informacja z jakiego środowiska uruchomieniowego korzystamy, np.:
Environment set to development
W tym przykładzie, konfiguracja środowiska to środowisko rozwojowe development. W Grails istnieją 3 predefiniowane konfiguracje środowiska - development, test oraz production. Wskazanie, które powinno być bieżące to uruchomienie polecenia grails z parametrem JVM grails.env lub po prostu z podaniem nazwy skróconej konfiguracji jako drugi parametr grails, np.
$ grails test run-app ... Environment set to test
Wykorzystajmy tę wiedzę do zdefiniowania własnej konfiguracji mysql z bazą MySQL w pliku grails-app/conf/DataSource.groovy. Plik DataSource.groovy jest skryptem Groovy, który odpowiada za konfigurację bazodanową i tam właśnie znajdziemy konfigurację domyślną z H2.
Plik grails-app/conf/DataSource.groovy powinien zawierać następującą treść:
dataSource {
pooled = true
driverClassName = "org.h2.Driver"
username = "sa"
password = ""
}
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = true
cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
url = "jdbc:h2:mem:devDb"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:h2:mem:testDb"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:h2:prodDb"
}
}
mysql {
dataSource {
dbCreate = "create-drop"
url = "jdbc:mysql://localhost/grailsmysqldb"
driverClassName = "com.mysql.jdbc.Driver"
dialect ="org.hibernate.dialect.MySQLDialect"
username = "root"
password = "passw0rd"
}
}
}
Zwróćmy uwagę na ostatnią "sekcję" mysql, w której definiujemy źródło danych wskazujące na MySQL (w zasadzie to mysql oraz dataSource to wywołania metod akceptujących pojedynczy parametr, który jest de facto domknięciem).
Dostęp do bazy danych w Javie wymaga właściwego sterownika JDBC. W przypadku MySQL będzie to Connector/J jako plik mysql-connector-java-5.1.15-bin.jar, który umieszczamy w katalogu lib projektu. Konieczne jest ponowne uruchomienie aplikacji.
Utworzenie bazy danych
Ostatnim krokiem jest stworzenie bazy danych w MySQL. W naszej konfiguracji mysql w DataSource.groovy założyliśmy nazwę bazy grailsmysqldb. Stworzenie bazy to wykonanie polecenia create database grailsmysqldb (przez użytkownika z odpowiednimi uprawnieniami).
$ ./bin/mysql -u root -p Enter password: passw0rd Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 13 Server version: 5.5.16 MySQL Community Server (GPL) Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database grailsmysqldb; Query OK, 1 row affected (0.01 sec)
Uruchomienie aplikacji - grails -Dgrails.env=mysql run-app
Po tych zmianach uruchamiamy aplikację ponownie poleceniem grails -Dgrails.env=mysql run-app.
$ grails -Dgrails.env=mysql run-app Welcome to Grails 1.4.0.M1 - http://grails.org/ ... Environment set to mysql ... Server running. Browse to http://localhost:8080/grailsmysql
Uruchomienie aplikacji http://localhost:8080/grailsmysql i stworzenie książki...
...to gwarancja, że aplikacja korzysta poprawnie z bazy MySQL.
Na zakończenie sprawdźmy struktury bazodanowe w MySQL.
$ ./bin/mysql -u root -p Enter password: passw0rd Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 13 Server version: 5.5.16 MySQL Community Server (GPL) Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use grailsmysqldb; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +-------------------------+ | Tables_in_grailsmysqldb | +-------------------------+ | ksiazka | +-------------------------+ 1 row in set (0.00 sec) mysql> describe ksiazka; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | autor | varchar(255) | NO | | NULL | | | tytul | varchar(255) | NO | | NULL | | +---------+--------------+------+-----+---------+----------------+ 4 rows in set (0.04 sec) mysql> select * from ksiazka; +----+---------+-----------------+----------------+ | id | version | autor | tytul | +----+---------+-----------------+----------------+ | 1 | 0 | Jacek Laskowski | Grails z MySQL | +----+---------+-----------------+----------------+ 1 row in set (0.00 sec) mysql> quit Bye
Działa jak należy. Gratulacje!


