Hibernate Your Data

zhaozj2021-02-16  56

Published on Njava.com (http://www.onjava.com/)

http://www.onjava.com/pub/a/onjava/2004/01/14/Hibernate.html See this if You're Having Trouble Printing Code Examples

Hibernate Your Databy

Davor CENGIJA

01/14/2004

Object-relational mapping (O / R mapping) is a common requirement of many software development projects. The activities involved in persisting data are tedious and error-prone. If we also take into consideration the inevitable change of requirements, we're in serious Trouble: The Data Storage Structure Must Be Kept in Sync with The Source Code. Add The Portability Issue, And Things Are Becoming Very, Very Complicated.

Hibernate will help us to painlessly store the data in permanent storage without too much hassle about choosing the kind of storage, installation, or configuration Hibernate allows us to store any kind of objects;. Therefore, our application does not need to know that its data will be persisted using Hibernate Of course, everything mentioned here can be applied in the opposite direction:.. fetching already prepared objects from a storage is now nearly trivial Updating and deleting data is also available.

Before get started

Before you get started you'll need the Hibernate distribution, available on the Hibernate web site, www.hibernate.org. We'll use version 2.0.3. For a database, we'll use Hypersonic SQL version 1.7.1, available at hsqldb.sourceforge.net. Hibernate also supports many open source and commercial databases, such as MySQL, PostgreSQL, Oracle, DB2, etc. It is easy to set up this tutorial for any supported database. See the official documentation for the complete list .

Related Reading Java Data Objectsby David Jordan, Craig Russell

Table of contents

IndexSample Chapter

Read Online - Safari

Search this book on Safari:

Note: If you do not want your classes to be persisted in a database, but say, serialized, the Hibernate API provides you with the net.sf.hibernate.persister.EntityPersister class and the net.sf.hibernate.persister.ClassPersister Interface. by Subclassing Or Implementing Them, You Can Write Your OWN PERSISTER CLASSES AND SIMPLY USEM AS NEEDED.

After downloading all of the needed packages, we'll have to set up our testing environment. Basically, all we need to do is to put downloaded .jar files into our CLASSPATH. This includes hibernate2.jar from the Hibernate distribution and hsqldb.jar from Hypersonic's lib / directory. Hibernate also requires quite a few additional libraries, all of them available in the / lib directory. Not all .jars from that directory are needed, but it will not hurt if you simply use ..................

Note:... Hibernate uses commons-logging from Apache It's a smart tool and it will silently use log4j if found Log4j is an excellent logging library and we'll use it in this tutorial If you do not already have it (and you SHOULD!) Download It from the log4j homepage and add to your classpath. Use the sample log4j.properties provided by the Hibernate Team and Available in / src.

SO, you have a proBLEM?

Evely Developer Has Had to Perform Something Like The Following Task At Least Once: Create An ORDER, PUT Some Products in It THEN SEN SAVE The Order.

We'll Use these Simple SQL Commands to Set Up Our Database:

CREATE TABLE ORDERS (ID VARCHAR NOT NULL PRIMARY KEY, ORDER_DATE TIMESTAMP NOT NULL, PRICE_TOTAL DOUBLE NOT NULL) CREATE TABLE PRODUCTS (ID VARCHAR NOT NULL PRIMARY KEY, NAME VARCHAR NOT NULL, PRICE DOUBLE NOT NULL, AMOUNT INTEGER NOT NULL) CREATE TABLE ORDER_ITEMS (ID VARCHAR NOT NULL PRIMARY KEY, ORDER_ID VARCHAR NOT NULL, PRODUCT_ID VARCHAR NOT NULL, AMOUNT INTEGER NOT NULL, PRICE DOUBLE NOT NULL) This data model is rather simple. For a real, "production quality" data model we would need foreign keys , Indices, Additional Fields, Etc. for this Tutorial, The Above Data Model Will Suffice.

Note: if you decided to use hypersonicsql for this tutorial, you can use the providies.script and orders.properties files available in the source package attached to this article.

Java Code

Although these business requirements are simple and understandable, the traditional approach of writing a bunch of prepared statements will quickly become boring. Hibernate will save us from that. All we need is a set of simple mapping files. But first, we need to write our Java classes.

NOTE: We'll Put of Our To-Be-Persisted Classes in The Test.hibernate Package, And All Runner Classes in The Test Package.

PRODUCT

This simple class defines only the necessary fields:. ID, product name, price of the product, and the current amount of this item available in stock Since Hibernate works with plain, simple JavaBeans, all we need to do is to create getters and setters For Every Significant Field (All Fields Are Significant, In Our Case) and the default constructor.

package test.hibernate; public class Product {private String id; private String name; private double price; private int amount; public String getId () {return id;} public void setId (String string) {id = string;} // default constructor and other // getters / setters not shown for brevity // ...} Also, we override the toString () method This will help us to follow the application flow using simple System.out.println (obj) calls.:

Public String Tostring () {Return "[Product]" Name "(" ID ") price =" price "amount =" Amount;}

. That's it, no more, no less How Hibernate will know to persist the objects of this type, since Product does not implement any interface or extend any class The answer is simple:? Hibernate will work with any kind of Java object, as Long As it Follows JavaBeans Convention.

ORDER

The next class we need to create is Order It's even simpler than Product:. It only contains ID, creation date, total price, and the Set of OrderItems of which this Order consists Of course, create the getters and setters and default constructor..

package test.hibernate; import java.util.Date; import java.util.HashSet; import java.util.Set; public class Order {private String id; private Date date; private double priceTotal; private Set orderItems = new HashSet () ; // Automatically set the creation time of // this order public order () {this.date = new date ();} public string getId () {return id;} public void setid (string string) {ID = string; } // other getters / setters not shown for // BREVITY / / ...}

OVERRIDE TOSTRING () AS Well. Don't forget to loop through orderitems! Download the Complete Source Code To See the Example.OrDerItem

This class is a little bit more complicated, but it's still fairly straightforward. Our business demands say that we need a certain amount of Products, which we will put into an Order. Those Products will automatically become OrderItems. It's a time for custom constructor.

package test.hibernate;. public class OrderItem {/ ** * Creates valid OrderItem Automatically sets * this OrderItem's price and corrects * Product's stock availability amount * * @param order to which this OrderItem belongs * @param product from which this OrderItem is. created * @param amount * / public OrderItem (Order order, Product product, int amount) {this.order = order; this.product = product; this.amount = amount; product.setAmount (product.getAmount () - amount) ; this.price = product.getPrice () * amount;.} // we also need default constructor to keep // Hibernate happy / ** * Empty constructor to conform to JavaBeans * convention * * / public OrderItem () {// empty default constructor} // fields private String id; private Product product; private Order order; private String productId; private String orderId; private double price; private int amount; public String getId () {return id;} public String getProductId () {Return Product.getID (); public string getorderId () {return Er.Getid ();} // other getters / setters not shown // ... // Convenient Way to Display this OrderItem Public String Tostring () {return "[OrderItem] ID =" ID "AMOUNT =" amount "price =" price "(" product ")";.}} Now we have all of the classes that reflect the database structure The only thing left unexplained is how we will put Products into an Order Simply. Add The Following Method to The Order Class:

/ ** * Add a Product to this Order. Product * automatically becomes an OrderItem. * The priceTotal is automatically updated. * * @Param p Product to add to this Order * @param amount amount of products to add * / public void addProduct (Product P, Int Amount) {OrderItem OrderItem = New OrderItem (this, p, amount); this.pricetotal = this.priketotal p.GetPrice () * Amount; this.orderItems.Add (OrderItem);} ">

Starting Up Hibernate

The basic usage pattern in our imaginary application is simple: we'll create a Product and then make it persistent (or in other words, save it), we'll search for and load an already persisted Product and make sure it's usable, and We'll Update and Delete Products.

Create and Persist a Product

Now We'll Finally Use Hibernate. The Usage Scenario Is Fairly Simple:

Create a valid Product. Obtain net.sf.hibernate.SessionFactory using net.sf.hibernate.cfg.Configuration at the start of the application. Open net.sf.hibernate.Session by calling SessionFactory # openSession (). Save the Product and Close the session.

AS We can see, There's No mention of JDBC, SQL, or Anything Similar. Very Encouraging! The Following Sample Follows The Above-Mentioned Steps:

package test; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Transaction; import net.sf.hibernate.cfg.Configuration; import test.hibernate.Product; // use as // java test.InsertProduct name amount price public class InsertProduct {public static void main (String [] args) throws Exception {// 1. Build a Product Product p = new Product (); p.setName (args [0 ]); P.Setamount (Integer.Parseint (args [1])); P.SETPRICE (Double.Parsedouble); // 2. Fire Up Hibernate Configuration CFG = New Configuration () .addclass () .addclass Product.class); sessionFactory sf = cfg.buildsessionFactory (); // 3. Open session session sess = sf.opensession (); // 4. Save product and close session transaction t = sess.begintransaction (); sess.save (p); t.commit (); sess.close ();}} let's run it for the first time! Insert 100 Bottles of Milk At 1.99 Each by Issuing Java Test.IsertProduct Milk 100 1.99. We get Something Similar To this :

Nov 23, 2003 9:05:50 am net.sf.hibernate.cfg.environment info: Hibernate 2.0.3 Nov 23, 2003 9:05:50 am net.sf.hibernate.cfg.Environment Info: hibernate.properties Not Found Nov 23, 2003 9:05:50 am net.sf.hibernate.cfg.environment info: using cglib Reflection Optimizer Nov 23, 2003 9:05:50 am net.sf.hibernate .cfg.environment info: JVM Proxy Support: True Nov 23, 2003 9:05:50 am net.sf.hibernate.cfg.configuration addclass info: maping resource: test / hibernate / product.hbm.xml exception in thread "main" net.sf.hibernate.MappingException: Resource: test / hibernate / Product.hbm.xml not found at net.sf.hibernate.cfg.Configuration.addClass (Configuration.java:285) at test.FindProductByName.main (FindProductByname.java: 24 )In't Work. Two Lines Are Especially Interesting:

Info: hibernate.properties not found and

Resource: Test / Hibernate / Product.hbm.xml Not found.

The INFO line indicates that we need a hibernate.properties configuration file, of course. That's the place where we configure which database we use, the username and password, and many other options. Use this provided sample to connect to the Hypersonic database mentioned before :

hibernate.connection.username = sa hibernate.connection.password = hibernate.connection.url = jdbc: hsqldb: / home / davor / hibernate / orders hibernate.connection.driver_class = org.hsqldb.jdbcDriver hibernate.dialect = net.sf. Hibernate.Dialev.hsqldiaAlact

Modify it as appropriate (e.g., You'll Probably Need to change hibernate.connection.URL) and save in your classpath.

This was an easy one, but what is that test / hibernate / Product.hbm.xml resource? It's an XML file that defines how a Java object is persisted (mapped) to a database. In that file, we define into which database table The Data Goes, Which Field Is Mapped to Which Table Column, How Different Objects Relate To Each Other, etc. let's take a look at product.hbm.xml.

IT Is Very Simple and UndAnetable. A FEW DETAILS Are Especial INTERESTING:

says that we're mapping a class named test.hibernate.Product to the table products. The element and its child elements define the connection between our Java class and the database. elements define into which column each field goes, its type, name, etc.The element is not quite understandable at first. Knowing that it is one Of the child elements of , ITS role become a little bit obvious: Since Our Application Doesn't Know How ITS Data Will Be Persisted (WE NED A SURROGATE, WITH NO business meaning, to help Hibernate to manipulate objects. Newly created Products do not have that id, and Hibernate will create them for us. We chose to use UUID strings, but many different ID generators are provided (sequential, within some specific range, OR EVEN User Assigned, etc.) And you can always Write Your OWN ID Generator. See The Documentation for Deta ILS.

Now, create (copy and paste) the content of Product.hbm.xml and place the file into the same package as the test.hibernate.Product class (eg, in the same directory where your Product.java file is placed) and re -Run Java Test.InsertProduct Milk 100 1.99. Now We See Much More Logging Information and ... Nothing More! Is IT Working Correctly? Add System.out.Println (P) Just Before Session Sess = sf.openSession (); and After sess.close () to see what's going on with outuct. Re-run. You'll See Something Similar To this (That Funny ID Number Will Surely Be Different):

[Product] Milk (null) price = 1.99 amount = 100 [Product] Milk (40288081f907f42900f907f448460001) price = 1.99 amount = 100Hibernate created the Product's id for us! Let's see if the Product is stored in our database. Issue select * from products. The Database Returns Something Similar TO:

ID | Name | Price | Amount | 40288081F907F42900F907F448460001 | MILK | 1.99 | 100 |

The product information is successfully inserted INTO OUR DATABASE AND WE Haven't Written A Single Line of SQL!

Insert Some Other Products, Such As Bread, Coffee, Beer, etc., to have this tutorial.

Find and load products

Finding and loading already persisted objects is very simple with Hibernate. Using its query language we can easily fetch an object (or set of objects) by its ID, name, or some other property. We can fetch the complete object or just some of its Properties. Hibernate Will Take Care of the rest, and at the end...

package test; import java.util.List; import net.sf.hibernate.Hibernate; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.cfg.Configuration; import test .hibernate.Product; // use as // java test.FindProductByName name public class FindProductByName {public static void main (String [] args) throws Exception {// query to issue String query = "select product from product" "in Class test.hibernate.product " " where produuct.name =: name "; // search for what string name = args [0]; // init configuration cfg = new configuration () .addclass (product.class); SessionFactory sf = cfg.buildsessionFactory (); // Open session session sess = sf.opensession (); // search and return list list = sess.find (query, name, hibernate.string); if (list.size () == 0) {system.out.println ("No Products named" name); system.exit (0);} Product P = (product) list.get (0); sess.close (); system.out .println ("Found Product:" P);}} WE Have SEVERAL INTERESTING POINTS IN F IndproductByname:

There's a query string with a where clause. This is very similar to standard SQL. We initialize Hibernate in the same way as in our first example. This time, we have the configuration and mapping files. Sess.find () executes the query and sets the provided product name as the search argument of type Hibernate.STRING As the result, we get a java.util.List full of found Products With Product p = (Product) list.get (0);.. we fetch the found Objects in The Usual Way, with casting.

Issue Java Test.FindProductByname Milk and See What's shown in the console.

Note:. Queries are case-sensitive, so searching for lowercase milk will not return any results Use the lower () or upper () SQL functions to enable case insensitive searches In that case, we would have where lower (product.name. ) = lower (:.. name) in our query string See the documentation for details on queries Also, if you do not want all the INFO logging information displayed, tweak log4j.properties and set all log levels to warn.Update and Delete PRODUCTS

............. ..

To increase the price of all products by 10% Percent in a Single Transaction, We Write Something Like this:

Double percentage = double.parsedouble (args [0]) / 100; sess = sf.opensesis (); transaction t = sess.begintransaction (); // list contacts product itrator iter = list.iterator (); while (iter). HasNext ()) {Product P = (Product) iter.next (); p.setprice (p.GetPrice ()); sess.saveorupdate (P);} T.Commit (); sess. CLOSE ();

And Final, To Delete A Product, We Would, Of Course (Product). Don't forget to commit () The Transaction if AutoCommit () The Transaction IF AutoCommit is Turned Off for your database.

Now we have gone through all of the basic operations - create, read, update, and delete -. For a single object It does look interesting, but things are getting even better We'll now learn how to manipulate a collection of. Objects without Writing a Single Sql Statement. All of the magic will be done through the mapping files.

ORDERS, OrderItems

Manipulating objects on one-by-one basis will definitely save as some time, but what we really want are cascading loads and updates. We'll now see how to do that.We need to examine Orders and OrderItems in parallel. As mentioned before , we add a Product to an Order and it then becomes an OrderItem Order internally keeps a set of OrderItems What we want is to save Order and have Hibernate do the rest:.. save OrderItems and to update the stock availability (amount) of the Added Products. Sounds Complicated, But It Is Actually Very Simple. Hibernate Knows How To DEAL with Related Objects in One-to-One, One-To-Many, Many-to-One, And Many-to-Many Fashion. WE ' Ll Start with the mapping files.

ORDER.HBM.XML

< Column name = "ID" SQL-TYPE = "CHAR (32)" NOT-NULL = "true" />

This mapping file is quite understandable, except the last element, This represents connections between different classes; in our case, those are Order and OrderItem The attributes and child elements are quite understandable:.. A field of type Set, named orderItems (see the Order source code above), contains objects of the type test.hibernate.OrderItem, as explained by child element. Those objects are persisted in the order_items table, where the order_id column contains keys for OrderItem type of objects.The cascade = "all" attribute is a very important one. It explains how Hibernate should act while manipulating connected objects. In our specific situation, when an Order is created, we definitely want all of its OrderItems to be created as Well, And, Of Course, WHEN An ORDER IS DELETED, WEE Also Want All of Its ORDERITEMS to Be deleted. There all it More Options Cascade Attribute Can Hold, None, Save-Update, And Delete, And We'll See How To To Use them in the followi Ng example.

ORDERITEM.HBM.XML

This object is an interesting one. Its instances are created automatically within Order, and basically do not have life outside of it. However, we need them, since they represent the Products at the time Order was created. So, if a Product's price is changed, we definitely do not want all the appropriate OrderItems 'and therefore Orders' prices to be changed. But what we want is to update the stock availability of a Product whenever an OrderItem is created. and finally, when an Order is deleted , its OrderItems are deleted, as well, but we must not touch the Products! Sounds complicated, especially when all of those SQL statements need to be written. But Hibernate compresses all of them into two lines in the mapping file!

< Column name = "ID" SQL-TYPE = "CHAR (32)" NOT-NULL = "true" />

WE KNOW All About the and Elements By Now, But IS A New One. It's Fairly Simple. The First Use of the Element Indicates That OrderItem's Field named order is of type test.hibernate.Order and is referenced through the order_id column from the table order_items (see the table attribute of the element class). The second many-to-one element is similar to the first one, except that it has cascade = "save-update" attribute. It's explained before what it defines. In this case, we say that Hibernate should propagate changes on Products only when an OrderItem is saved (created) or updated (changed), and not on delete. So The Above-Mentioned Concerns About Complicated SQL Statements Are Compressed in One Single Attribute! Now Beat That! Usage Examples

Create An Order. In this Example, we create and personst an order. Run this Example More Than Once to Seeh How Products' Amounts Change After Each Success ERDER CREATION.

// ... configuration cfg = new configuration () .addclass (product.class) .addclass (Order.class); // ... Order ORDER = New Order (); Order.AddProduct (Milk, 3); Order.addProduct (Coffee, 5); // ... sess = sf.openSession (); transaction t = sess.begintransaction (); sess.save (order); t.commit (); Sess.close (); System.out.Println (Order); // ...

Find ORDERS WITHIN A Price Range. In this Example, We show how to use a query with two parameters. Hibernate Correctly Loads ORDERS WITH APPRIATE ORDERITEMS AND PRODUCTS.

// ... string query = "SELECT O from O" "in class test.hibernate.order" "Where o.pricetotal>: precating" "and o.prketotal <: precetitalupper"; // ... QUERY Q = sess.createQuery (query); Q.SetDouble, double.parsedouble (args [0])); Q.SetDouble ("prichdoudouble, double.parsedouble); List list = q.list (); // ... sess.close (); // ... delete Orders within a price range. this is an estortant example. here we can see how intelligent a Tool Hibernate is. As Mentioned ABOVE ................... ..

// ... string query = "SELECT O from O" "In Class Test.hibernate.Order" "Where o.pricetotal>: PriceTotAllower" "And O.PriceTotal <: precititalupper"; transaction tx = sess. Begintransaction (); sess.delete (query, new object [] {new double (args [1])}, new type [] {hibernate.double, hibernate.double}; TX .Commit (); sess.close ();

Conclusion

This article shows how powerful Hibernate is. You've learned how easy it is to persist any kind of Java object, to manipulate a hierarchy of objects, handle collections, and work with transactions. But the scope of Hibernate's functionality is much wider. It handles full transactions with commit and rollback, inheritance, a few types of collections, and offers very powerful object-oriented query language, HQL, which supports associations and joins, polymorphism, subqueries, etc. Your next step is to read the Hibernate Reference Documentation AND to Start Using Hibernate in Your Day-to-Day Work.Resources

Source code used in this article Hibernate home page, www.hibernate.org: Here you will find the most recent Hibernate distribution, documentation, other tutorials, etc. O / R Mapping tools comparison: visit this page if you want to compare Hibernate to x`return to onjava.com.

CopyRight? 2004 O'Reilly Media, Inc.

转载请注明原文地址:https://www.9cbs.com/read-19009.html

New Post(0)