Java
  Home arrow Java arrow Page 4 - Introduction to Mapping Redux
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
JAVA

Introduction to Mapping Redux
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 5 stars5 stars5 stars5 stars5 stars / 1
    2007-05-03

    Table of Contents:
  • Introduction to Mapping Redux
  • Writing a Mapping Document
  • Generating Some Class
  • Cooking up a Schema
  • Connecting Hibernate to MySQL

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    Introduction to Mapping Redux - Cooking up a Schema


    (Page 4 of 5 )

     

    That was pretty easy, wasn’t it? You’ll be happy to learn that creating database tables is a very similar process. As with code generation, you’ve already done most of the work in coming up with the mapping document. All that’s left is to set up and run the schema generation tool.

    How do I do that?

    The first step is something we alluded to in Chapter 1. We need to tell Hibernate the database we’re going to be using, so it knows the specific “dialect” of SQL to use. SQL is a standard, yes, but every database goes beyond it in certain directions and has a specific set of features and limitations that affect real-life applications. To cope with this reality, Hibernate provides a set of classes that encapsulate the unique features of common database environments, in the packagenet.sf.hibernate.dialect. You just need to tell it which one you want to use. (And if you want to work with a database that isn’t yet supported “out of the box,” you can implement your own dialect.)

    In our case, we’re working with HSQLDB, so we want to use HSQLDialect. The easiest way to configure Hibernate is to create a properties file namedhibernate.propertiesand put it at the root level somewhere in the class path. Create this file at the top level of yoursrcdirectory, and put the lines shown in Example 2-4 into it.

     

    Example 2-4. Setting up hibernate.properties

    You can use an XML format for the configuration
    information as well, but for the simple needs we
    have here, it doesn’t buy you anything.

       
      hibernate.dialect=net.sf.hibernate. dialect.HSQLDialect
      hibernate.connection.driver_class=org. hsqldb.jdbcDriver
      hibernate.connection.url=jdbc:hsqldb: data/music
      hibernate.connection.username=sa
      hibernate.connection.password=

    In addition to establishing the SQL dialect we are using, this tells Hibernate how to establish a connection to the database using the JDBC driver
    that ships as part of the HSQLDB database JAR archive, and that the data should live in the data directory we’ve created—in the database named music. The username and empty password (indeed, all these values) should be familiar from the experiment we ran at the end of Chapter 1.

    TIP

    Notice that we’re using a relative path to specify the database filename. This works fine in our examples—we’re using ant to control the working directory. If you copy this for use in a web application or other environment, though, you’ll likely need to be more explicit about the location of the file.

    You can put the properties file in other places, and give it other names, or use entirely different ways of getting the properties into Hibernate, but this is the default place it will look, so it’s the path of least resistance (or, I guess, least runtime configuration).

    We also need to add some new pieces to our build file, shown in Example 2-5. This is a somewhat substantial addition, because we need to compile our Java source in order to use the schema generation tool, which relies on reflection to get its details right. Add these targets right before the closing </project> tag at the end of build.xml.

    Example 2-5.  Ant build file additions for compilation and schema generation

     1   <!-- Create our runtime subdirectories and copy resources into them -->
     2   <target name="prepare" description="Sets up build structures">
     3     <mkdir dir="${class.root}"/>
     4
     5     <!-- Copy our property files and O/R mappings for use at runtime -->
     6     <copy todir="${class.root}" >
     7       <fileset dir="${source.root}" >
     8         <include name="**/*.properties"/>
     9         <include name="**/*.hbm.xml"/>
    10       </fileset>
    11     </copy>
    12   </target>
    13
    14   <!-- Compile the java source of the project -->
    15   <target name="compile" depends="prepare"
    16           description="Compiles all Java classes">
    17     <javac srcdir="${source.root}"
    18           destdir="${class.root}"
    19           debug="on"
    20           optimize="off"
    21           deprecation="on">
    22      <classpath refid="project.class.path"/>
    23    </javac>
    24  </target>
    25
    26  <!-- Generate the schemas for all mapping files in our class tree -->
    27  <target name="schema" depends="compile"
    28          description="Generate DB schema from the O/R mapping files">
    29
    30    <!-- Teach Ant how to use Hibernate's schema generation tool -->
    31    <taskdef name="schemaexport"
    32             classname="net.sf.hibernate. tool.hbm2ddl.SchemaExportTask"
    33             classpathref="project. class.path"/>
    34
    35    <schemaexport properties="${class.root}/hibernate.properties"
    36                  quiet="no" text="no" drop="no" delimiter=";">
    37     <fileset dir="${class.root}">
    38       <include name="**/*.hbm.xml"/>
    39     </fileset>
    40   </schemaexport>
    41 </target>

    First we add a prepare target that is intended to be used by other targets more than from the command line. Its purpose is to create, if necessary, the classes directory into which we’re going to compile, and then copy any properties and mapping files found in the src directory hierarchy to corresponding directories in the classes hierarchy. This hierarchical copy operation (using the special “**/*” pattern) is a nice feature of Ant, enabling us to define and edit resources alongside to the source files that use them, while making those resources available at runtime via the class loader.

    The aptly named compile target at line 14 uses the built-in java task to compile all the Java source files found in the src tree to the classes tree. Happily, this task also supports the project class path we’ve set up, so the compiler can find all the libraries we’re using. The depends="prepare" attribute in the target definition tells Ant that before running the compile target, prepare must be run. Ant manages dependencies so that when you’re building multiple targets with related dependencies, they are executed in the right order, and each dependency gets executed only once, even if it is mentioned by multiple targets.

    If you’re accustomed to using shell scripts to compile a lot of Java source, you’ll be surprised by how quickly the compilation happens. Ant invokes the Java compiler within the same virtual machine that it is using, so
    there is no process startup delay for each compilation.

    Finally, after all this groundwork, we can write the target we really wanted to! The schema target (line 26) depends on compile, so all our Java classes will be compiled and available for inspection when the schema generator runs. It uses taskdef internally at line 31 to define the schemaexport task that runs the Hibernate schema export tool, in the same way we provided access to the code generation tool at the top of the file. It then invokes this tool and tells it to generate the database schema associated with any mapping documents found in the classes tree.

    There are a number of parameters you can give the schema export tool to configure the way it works. In this example (at line 35) we’re telling it to display the SQL it runs so we can watch what it’s doing (quiet="no"), to actually interact with the database and create the schema rather than simply writing out a DDL file we could import later or simply deleting the schema (text="no", drop="no"). For more details about these and other configuration options, consult the Hibernate reference manual.


    T I P

    You may be wondering why the taskdef for the schema update tool is inside our schema target, rather than at the top of the build file, next to the one for hbm2java. Well, I wanted it up there too, but I ran into a snag that’s worth explaining. I got strange error messages the first time I tried to build the schema target, complaining there was no hibernate.properties on the class path and our compiled Track class couldn’t be found. When I ran it again, it worked. Some detective work using ant -verbose revealed that if the classes directory didn’t exist when the taskdef was encountered, Ant helpfully removed it from the class path. Since a taskdef can’t have its own dependencies, the solution is to move it into the schema target, giving it the benefit of that target’s dependencies, ensuring the classes directory exists by the time the taskdef is processed.

    With these additions, we’re ready to generate the schema for our TRACK table.

    WARNING

    You might think the drop="no" setting in our schema task means you can use it to update the schema—it won’t drop the tables, right? Alas, this is a misleading parameter name: it means it won’t just drop the tables, rather it will go ahead and generate the schema after dropping them. Much as you want to avoid the codegen task after making any changes to the generated Java source, you mustn’t export the schema if you’ve put any data into the database. Luckily, there is another tool you can use for incremental schema updates that works much the same way, as long as your JDBC driver is powerful enough. This SchemaUpdate tool can be used with an Ant taskdef too.

     

    Because we’ve asked the schema export task not to be “quiet,” we want it to generate some log entries for us. In order for that to work, we need to configure log4j, the logging environment used by Hibernate. The easiest way to do this is to make a log4j.properties file available at the root of the class path. We can take advantage of our existing prepare target to copy this from the src to the classes directory at the same time it copies Hibernate’s properties. Create a file named log4j.properties in the src directory with the content shown in Example 2-6. An easy way to do this is to copy the file out of the src directory in the Hibernate distribution you downloaded, since it’s provided for use by their own examples. If you’re typing it in yourself, you can skip the blocks that are commented out; they are provided to suggest useful logging alternatives.


    Example 2-6. The logging configuration file, log4j.properties

    ### direct log messages to stdout ###
    log4j.appender.stdout=org.apache.log4j. ConsoleAppender
    log4j.appender.stdout.Target=System.out
    log4j.appender.stdout.layout=org.apache. log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

    ### direct messages to file hibernate.log ###
    #log4j.appender.file=org.apache.log4j. FileAppender
    #log4j.appender.file.File=hibernate.log
    #log4j.appender.file.layout=org.apache. log4j.PatternLayout
    #log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

    ### set log levels - for more verbose logging change 'info' to 'debug' ###

    log4j.rootLogger=warn, stdout

    log4j.logger.net.sf.hibernate=info

    ### log just the SQL
    #log4j.logger.net.sf.hibernate.SQL=debug

    ### log JDBC bind parameters ###
    log4j.logger.net.sf.hibernate.type=info

    ### log schema export/update ###
    log4j.logger.net.sf.hibernate.tool.hbm2ddl=debug

    ### log cache activity ###
    #log4j.logger.net.sf.hibernate.cache=debug

    ### enable the following line if you want to track down connection ###
    ### leakages when using DriverManagerConnectionProvider ###
    #log4j.logger.net.sf.hibernate.connection.
    DriverManagerConnectionProvider=trace

    TIP

    With the log configuration in place, you might want to edit the codegen target in build.xml so that it, too, depends on our new prepare target. This will ensure logging is configured whenever we use it, preventing the warnings we saw when first running it. As noted in the tip about class paths and task definitions in the previous section, though, to make it work the very first time you’ll have to move the taskdef for hbm2java inside the codegen target, in the same way we put schemaexport inside the schema target.

    Time to make a schema! From the project directory, execute the command ant schema. You’ll see output similar to Example 2-7 as the classes directory is created and populated with resources, the Java source is compiled,* and the schema generator is run.

    Example 2-7. Output from building the schema using HSQLDB’s embedded database server

    % ant schema
    Buildfile: build.xml

    prepare:
        [mkdir] Created dir:  /Users/jim/Documents/Work/OReilly/Hibernate/ Examples/
    ch02/classes

        [copy] Copying 3 files to /Users/jim/Documents/Work/OReilly/Hibernate/
    Examples/ch02/classes

    compile:
        [javac] Compiling 1 source file to /Users/jim/Documents/Work/OReilly/
    Hibernate/Examples/ch02/classes

    schema:
    [schemaexport] 23:50:36,165 INFO Environment:432 - Hibernate 2.1.1
    [schemaexport] 23:50:36,202 INFO Environment:466 - loaded properties from
    resource hibernate.properties: {hibernate.connection.username=sa, hibernate.
    connection.password=, hibernate.cglib.use_reflection_optimizer=true, hibernate.
    dialect=net.sf.hibernate.dialect.HSQLDialect, hibernate.connection.url=jdbc:
    hsqldb:data/music, hibernate.connection.driver_class=org.hsqldb. jdbcDriver}
    [schemaexport] 23:50:36,310 INFO Environment:481 - using CGLIB reflection
    optimizer
    [schemaexport] 23:50:36,384 INFO Configuration:166 - Mapping file: /Users/jim/
    Documents/Work/OReilly/Hibernate/Examples/ ch02/classes/com/oreilly/hh/Track.hbm.
    xml
    [schemaexport] 23:50:37,409 INFO Binder:225 - Mapping class: com.oreilly.hh.
    Track -> TRACK
    [schemaexport] 23:50:37,928 INFO Dialect:82 - Using dialect: net.sf.hibernate.
    dialect.HSQLDialect
    [schemaexport] 23:50:37,942 INFO Configuration:584 - processing one-to-many
    association mappings
    [schemaexport] 23:50:37,947 INFO Configuration:593 - processing one-to-one
    association property references
    [schemaexport] 23:50:37,956 INFO Configuration:618 - processing foreign key
    constraints
    [schemaexport] 23:50:38,113 INFO Configuration:584 - processing one-to-many
    association mappings
    [schemaexport] 23:50:38,124 INFO Configuration:593 - processing one-to-one
    association property references
    [schemaexport] 23:50:38,132 INFO Configuration:618 - processing foreign key
    constraints
    [schemaexport] 23:50:38,149 INFO SchemaExport:98 - Running hbm2ddl schema export
    [schemaexport] 23:50:38,154 INFO SchemaExport:117 - exporting generated schema
    to database
    [schemaexport] 23:50:38,232 INFO DriverManagerConnectionProvider:41 - Using
    Hibernate built-in connection pool (not for production use!)
    [schemaexport] 23:50:38,238 INFO DriverManagerConnectionProvider:42 - Hibernate
    connection pool size: 20
    [schemaexport] 23:50:38,278 INFO DriverManagerConnectionProvider:71 - using
    driver: org.hsqldb.jdbcDriver at URL: jdbc:hsqldb:data/music
    [schemaexport] 23:50:38,283 INFO DriverManagerConnectionProvider:72 -connection
    properties: {user=sa, password=}
    [schemaexport] drop table TRACK if exists
    [schemaexport] 23:50:39,083 DEBUG SchemaExport:132 - drop table TRACK if exists
    [schemaexport] create table TRACK (
    [schemaexport]    TRACK_ID INTEGER NOT NULL IDENTITY,
    [schemaexport]    title VARCHAR(255) not null,
    [schemaexport]    filePath VARCHAR(255) not null,
    [schemaexport]    playTime TIME,
    [schemaexport]    added DATE,
    [schemaexport]    volume SMALLINT
    [schemaexport] )
    [schemaexport] 23:50:39,113 DEBUG SchemaExport:149 - create table TRACK (
    [schemaexport]    TRACK_ID INTEGER NOT NULL IDENTITY,
    [schemaexport]    title VARCHAR(255) not null,
    [schemaexport]    filePath VARCHAR(255) not null,
    [schemaexport]    playTime TIME,
    [schemaexport]    added DATE,
    [schemaexport]    volume SMALLINT
    [schemaexport] )
    [schemaexport] 23:50:39,142 INFO SchemaExport:160 - schema export complete
    [schemaexport] 23:50:39,178 INFO DriverManagerConnectionProvider:137 - cleaning
    up connection pool: jdbc:hsqldb:data/music

    BUILD SUCCESSFUL
    Total time: 10 seconds

    Toward the end of the schemaexport section you can see the actual SQL used by Hibernate to create the TRACK table. If you look at the start of the music.script file in the data directory, you’ll see it’s been incorporated into the database. For a slightly more friendly (and perhaps convincing) way to see it, execute ant db to fire up the HSQLDB graphical interface, as shown in Figure 2-1.


    Figure 2-1. The database interface with our new TRACK table expanded, and a query

    What just happened?

    We were able to use Hibernate to create a data table in which we can persist instances of the Java class it created for us. We didn’t have to type a single line of SQL or Java! Of course, our table is still empty at this point. Let’s change that! The next chapter will look at the stuff you probably most want to see: using Hibernate from within a Java program to turn objects into database entries and vice versa.

    It’s about time? Yeah, I suppose. But at least you didn’t have to figure out all these steps from scratch!

    Before diving into that cool task, it’s worth taking a moment to reflect on how much we’ve been able to accomplish with a couple of XML and properties files. Hopefully you’re starting to see the power and convenience that make Hibernate so exciting.

    What about...

    ...Other approaches to ID generation? Keys that are globally unique across a database or the world? Hibernate can support a variety of methods for picking the keys for objects it stores in the database. This is controlled using the generator tag, line 15 in Example 2-1. In this example we told Hibernate to use the most natural kind of keys for the type of database that it happens to be using. Other alternatives include the popular “hi/lo” algorithm, global UUIDs, leaving it entirely up to your Java code, and more. See the “generator” section in the Basic O/R Mapping chapter of the Hibernate reference documentation for details. And, as usual, if none of the built-in choices are perfect for your needs, you can supply your own class to do it exactly how you’d like, implementing the interface net.sf.hibernate.id.IdentifierGenerator and supplying your class name in the generator tag.

    More Java Articles
    More By O'Reilly Media


       · This article is an excerpt from the book "Hibernate: A Developer's Notebook,"...
     

    Buy this book now. This article is excerpted from chapter two of Hibernate: A Developer's Notebook, written by James Elliott (O'Reilly; ISBN: 0596006969). Check it out today at your favorite bookstore. Buy this book now.

    JAVA ARTICLES

    - Deploying Multiple Java Applets as One
    - Deploying Java Applets
    - Understanding Deployment Frameworks
    - Database Programming in Java Using JDBC
    - Extension Interfaces and SAX
    - Entities, Handlers and SAX
    - Advanced SAX
    - Conversions and Java Print Streams
    - Formatters and Java Print Streams
    - Java Print Streams
    - Wildcards, Arrays, and Generics in Java
    - Wildcards and Generic Methods in Java
    - Finishing the Project: Java Web Development ...
    - Generics and Limitations in Java
    - Getting Started with Java Web Development in...







    © 2003-2009 by Developer Shed. All rights reserved. DS Cluster 1 Hosted by Hostway
    For more Enterprise Application Development news, visit eWeek