Here is the DataSource for MySQL:
dataSource {
dbCreate = "create-drop"
url = "jdbc:mysql://localhost:3306/sevendatabases"
driverClassName = "com.mysql.jdbc.Driver"
dialect = org.hibernate.dialect.MySQL5InnoDBDialect
username = "grailsdbuser"
password = "grailsdbuser"
}
And this is it for Oracle:
dataSource {
dbcreate = "create-drop"
url = "jdbc:oracle:thin:@127.0.0.1:1521:XE"
driverClassName = "oracle.jdbc.driver.OracleDriver"
dialect = 'org.hibernate.dialect.OracleDialect'
username = "grailsdbuser"
password = "grailsdbuser"
}
In addition to the Book and Author domains, I create another DataTypes test-domain through which I try to persist some more properties of different types:
grails create-domain-class DataTypes grails create-scaffold-controller sevendatabases.DataTypes
I edit the DataTypes.groovy domain class to look like this:
package sevendatabases
class DataTypes {
String _string
String _string80
String _bigString
String _bigString2
String _inList
Integer _integer
Double _double
Float _float
BigDecimal _bigdecimal
byte[] _binaryDate
Boolean _bolean
Date _date
static constraints = {
_string80(maxSize:80)
_bigString(maxSize:8000)
_bigString2(maxSize:8000)
_inList(inList:['one','two','three'])
}
}
I've used only common data types which just came to my mind. Float and Double might look a bit outdated... byte[] is often used for file uploads. _inList checks if any 'in list' contraint will be created in the database or if this is just a gails thing. _string will check the default size for a String and should never be used in a real app!*. _bigString will check what happens to long text fields (like comments). _bigString2 will check for a strange behaviour I've already encountered with Oracle.
Problems
- I started out prefixing the property names with an underscore '_'. This seems to work fine for PostgreSQL and MySQL, but Oracle's conventions don not allow this.
- the byte[] is not automatically mapped to a blob or something equal. So if you forget to specify a maxSize, you will get strange exceptions from your database layer (see Stack Overflow).
- Hibernate maps a long String for Oracle to the datatype 'Long'. If you have two long Strings in one domain, you will get the following error message:
ORA-01754: a table may contain only one column of type LONG
Even with this workaround from Stack Overflow (Using Oracle clob with Grails), I can't make it work. The only solution I see is to use only one big String porperty in a domain or to restrict it to a sie which can be mapped to a varchar2 (4000 bytes).
package sevendatabases
class DataTypes {
String myString
String myBigString
String myBigString2
String myInList
Integer myInteger
Double myDouble
Float myFloat
BigDecimal myBigdecimal
byte[] myBinaryData
Boolean myBoolean
Date myDate
static constraints = {
myBigString(maxSize:4000)
myBigString2(maxSize:4000)
myInList(inList:['one','two','three'])
myBinaryData(maxSize: 20 * 1024 * 1024)
}
}
Results
| Property | MySQL | PostgreSQL | Oracle EX |
|---|---|---|---|
| myBigString | varchar(4000) | character varying(4000) | VARCHAR2(4000) |
| myBigString2 | varchar(4000) | character varying(4000) | VARCHAR2(4000) |
| myBigdecimal | decimal(19,2) | numeric(19,2) | DECIMAL(19) |
| myBinaryData | tinyblob | bytea | LONGVARBINARY |
| myBoolean | bit(1) | boolean | DECIMAL(1) |
| myDate | datetime | timestamp without time zone | TIMESTAMP(7) |
| myDouble | double | double precision | FLOAT(126) |
| myFloat | float | real | FLOAT(126) |
| myInList | varchar(5) | character varying(5) | VARCHAR2(5) |
| myInteger | int(11) | integer | DECIMAL(10) |
| myString | varchar(255) | character varying(255) | VARCHAR2(255) |
| myString80 | varchar(80) | character varying(80) | VARCHAR2(80) |
Lessons learnt
- it is always good practice to set a size contraint on all String or Byte[] properties. Otherwise you can get strange results.
- Grails plays nicely together with relational databases but you still habe to know about some specific behaviour if you need to create code which runs on several databases. Oracle seems to be more restrictive than MySQL or PostgreSQL
* If you define a String property without a size contraint, you might run into the following problem: Grails only checks the constraints defined in the domain class before trying to save the object. If you now try to store a String longer than 255 characters, hibernate will throw an ungly exception. http://jira.grails.org/browse/GRAILS-8770
No comments:
Post a Comment