When you think of all developing tools, you will definitely take a new tool. In this article, the fixed contributor Rick Hightower of DeveloperWorks introduces you to the two most exciting business new technologies with an example of a real world. Hibernate is an object relationship mapping tool, while Spring is an AOP framework and an IOC container. Rick introduces how to combine both, build a transaction persistence for enterprise applications.
If you care about the latest hotspots of developers, you may have heard of IOC (Control Invert, Inversion of Control) container and AOP (aspect-oriented). However, like many developers, you may not know how to use these technologies in your own development work. In this article, you will recognize these technologies by using Hibernate and Spring to build a transaction persistence layer in an enterprise application using Hibernate and Spring.
Hibernate is a popular, easy-to-use Open Source Object Relationship (OR) mapping framework on the Java platform. Spring is an AOP framework and IOC container. These two technologies provide the basis for the development work described in this article. Hibernate will be mapped to a relational database using Hibernate, making Hibernate more easily and provides declarative transaction support with Spring. Since DBUNIT is used when writing test code for the sample class, I also introduced a little TDD (test-driven development).
Note that this article assumes that the reader is familiar with the business development on the Java platform, including JDBC, OR mapping content, J2EE design patterns such as DAO, and declarative transaction support, such as Enterprise JavaBean (EJB) technology. It is understood that the discussion here does not need to be experts in these technologies, nor does it need to be familiar with AOP, IOC or TDD because of these three in this article.
I will first introduce two development techniques, then analyze examples.
Introduction to Hibernate
Hibernate is a full-featured, open source OR mapping framework on the Java platform. Hibernate is similar to that of EJB CMP CMR (Persistent / container management of container) and JAVA Data Objects. Unlike JDO, Hibernate is fully eye-catching with OR mapping of relational databases, including more features than most commercial products. Most EJB CMP CMR solutions use code generation to implement persistent code, while JDO uses bytecode modifications. In contrast, Hibernate is generated using reflection and runtime, making it almost transparent to end users (for previous Hibernate implementation only reflecting, which helps debug, the current version retains this option).
Transplantation-based application
If the application must run on multiple RDBMS systems, Hibernate-based applications can be ported without porting to IBM DB2, MySQL, PostgreSQL, Sybase, Oracle, HypersonicsQL, and many other databases. I recently even ported from MySQL to Hibernate without a good support, and this transplant is easy. Hibernate can simulate inheritance (there are several ways), associated (one-to-one or one-to-one, containment and aggation) and composition. I will discuss several examples of each relationship type in this article.
Hibernate provides a query language called Hibernate Query Language (HQL), which is similar to JDO's JDOQL and EJB EJB QL, although it is closer to the former. But Hibernate does not stop this: it can also perform direct SQL queries and / or easy to make query conditions when using Object Criteria. In the example of this article, I will only use HQL. Unlike EJB CMP CMR, Hibernate can work inside or outside the J2EE container like JDO, which allows those who perform TDD and agile development benefits.
Introduction to Spring
AOP expert Nicholas lesiecki first explained AOP, he said that I said that I didn't understand, I think it is like the first time I consider the possibility of using IOC containers. The concept of each technique is well digested, and the various abbreviations used by each technology make things worse - especially many of these terms are different from us.
Like many technologies, understanding the actual use of these two technologies is easier than learning theory. After your own analysis of AOP and IOC containers (ie Xwork, PicoContainer and Spring), I found that these technologies can help me get functions without adding code-based dependencies in the multi-frame. They will become part of my development project.
Simply put, AOP allows developers to create non-behavioral focus, called cross-cutting points and insert them into the application code. After using AOP, public services (such as logs, persistence, transaction, etc.) can be decomposed into aspects and apply to domain objects, and do not increase the complexity of object models of domain objects.
IOC allows you to create an application environment that can construct an object and then communicate them to these objects. As the word inversion is indicated, IOC is like the reverse JNDI. No use of a bunch of abstract factories, service locator, single elements (Singleton) and STRIGHT Construction, each object is constructed with its collaborative object. It is therefore a collaborator that is managed by the container management.
Spring is both an AOP framework and an IOC container. I remember that Grady Booch said, the best place to replace them, and Spring is the best place to help you replace them. With Spring, just join the dependency (collaboration object) with JavaBeaN property and configuration file. You can then easily replace a collaborative object with similar interfaces during need.
Spring provides a good entry for IOC containers and AOP. Therefore, it is possible to understand the examples in this article without familiarizing AOP. What you need to know is to add transaction support to the sample application to declare the sample application, which is basically the same as using EJB technology.
Specific to business
In the rest of this article, all discussions will be based on an actual example. The starting point is an enterprise application to implement a transaction persistence layer for it. The persistence layer is an object relational database that includes familiar abstraction like User, User Group, Roles, and ContactInfo.
In depth to the factor of the database - query and transaction management - before, it is necessary to establish its foundation: Object Relationship Mapping. I will set it with hibernate and only use a little Spring.
Perform OR mapping with Hibernate
Hibernate uses the XML (* .hbm.xml) file to map the Java class to the table and map the javabean property to the database table. Fortunately, there is a set of XDoclet tags to support Hibernate development, which makes it easier to create the * .hbm.xml file you need. The code in Listing 1 maps a Java class to the database table. Listing 1. Mapping the Java class to DB table [user.java]
/ ** * @ hibernate.class table = "tbl_user" * .. * .. * ... * / public class user {private long id = new long (-1); private string email; private string password ;. . / *** * @Return * @ hibernate.id column = "pk_user_id" * unsaved-value = "- 1" * generator-class = "native" * / public long getId () {return ID;} ... / ** * @ hibernate.property column = "vc_email" * type = "string" * update = "false" * INSERT = "true" * unique = "true" * not-null = "true" * length = "82" * @Return * / public string geteMail () {return email;} / ** * @ hibernate.property column = "vc_password" * type = "string" * update = "false" * insert = "* unique =" True "* not-null =" true "* length =" 20 "* @return * / public string getPassword () {return password;} ... ...}
It can be seen that the @ hibernate.class table = "tbl_user" tab maps the user to the TBL_USER table. @ hibernate.property column = "vc_password" maps the JavaBean property Password to the VC_Password column. @ hibernate.id column = "pk_user_id" tag declaration ID attribute is the primary key, which will use this machine (Generator-class = "native") database mechanism generate key (for example, Oracle Sequences, and SQL Server Identity keys). Hibernate can specify generator-class = "native", others can imagine the primary key to get the strategy, but I am more willing to use Native. The TYPE and LENGTH properties are used to generate a table from the Hibernate * .hbm.xml OR mapping file. These factory properties are optional because it may not be a Green-Field database that may be used. In this example, there is already a database, so you don't need additional properties. (Green-Field Application is a new application, Green-Field data is a new database of new applications. It will not often develop a new application, but occasionally one or two are also good). I have seen how the table is mapped to classes and how to map to the JavabeaN property, which uses Hibernate to set some relationships in the OR database.
Set the object relationship
In this section, I will only touch a small part of the options for the setup objects provided by Hibernate. First set the relationship between these classes such as USER, User Group, Roles, and ContactInfo. Some of these relationships are shown in Figure 1, which is a database verification object model.
Figure 1. Illustration of the relationship
As you can see, there are a variety of relationships in the above abstraction. User is a one-on-one relationship with ContactInfo. ContactInfo's lifecycle is the same as USER (with the terminology of the database, the constitutive AKA cascade). If you delete the user, the corresponding ContactInfo will also be deleted. There is a multi-parallel relationship between Users and Roles (ie, associated with the independent lifecycle). There is a pair of relationships between Groups and Users because there are many users. The user can exist outside the group, ie the aggregation rather than Composition (with the database, there is no cascading between Groups and Users). In addition, User and Employee have sub-relations, that is, the type of Employee is User. Table 1 shows how to create some different types of object relationships with the XDoclet tab.
Table 1. Create an object relationship with XDoclet
Relationship Java / XDocletsql DDL (MySQL generated by Hibernate Schema Export) group contains a one-to-many AGGREGATION bidirection (Group.java] / *** * @ return * @ hibernate.bag name = "users" * cascade = "save-update" * lazy = "true" * inverse = "true" * * @ hibernate.collection-key * column = "fk_group_id" * @ hibernate.collection-one-to-many * Class = "net.sf.hibernateexamples.user" * / public list getusers () {return users;} [user.java] / *** @ hibernate.many-to-one * column = "fk_group_id" * class = " net.sf.hibernateExamples.Group "* / public Group getGroup () {return group;} create table tBL_USER (PK_USER_ID BIGINT NOT nULL AUTO_INCREMENT, USER_TYPE VARCHAR (255) not null, FK_GROUP_ID BIGINT, VC_EMAIL VARCHAR (82) not null unique, primary key (PK_USER_ID)) create table TBL_GROUP (PK_GROUP_ID BIGINT NOT NULL AUTO_INCREMENT, VC_DESCRIPTION VARCHAR (255), vC_NAME VARCHAR (40) unique, primary key (PK_GROUP_ID)) alter table tBL_USER add index (FK_GROUP_ID), add constraint FK_111 foreign key ( FK_GROUP_ID) References TBL_GROUP (PK_GROUP_ID) User has contact information One-to-one Composition One-way (Uses R -> ContactInfo) [User.java] / *** @ Return * * @ hibernate.one-to-one cascade = "all" * * / public contactinfo getContactinfo () {return contactinfo;} [contactinfo.java] (Nothing to see here. Unidirectional!) create table tBL_USER (PK_USER_ID BIGINT NOT nULL AUTO_INCREMENT, USER_TYPE VARCHAR (255) not null, FK_GROUP_ID BIGINT, VC_EMAIL VARCHAR (82) not null unique, primary key (PK_USER_ID)) create table TBL_CONTACT_INFO (PK_CONTACT_INFO_ID Bigint Not Null, ......... primary key (pk_contact_info_id)) User and Role Association Multi-Association One-way (Users -> Roles) [user.java] / *** @ return * @Hibernate .bag * Table = "
TBL_JOIN_USER_ROLE "* cascade =" all "* inverse =" true "* * @ hibernate.collection-key * column =" FK_USER_ID "* * @ hibernate.collection-many-to-many * class =" net.sf.hibernateExamples. Role "* column =" FK_ROLE_ID "* * / public List getRoles () {return roles;}.! [Role.java] Nothing to see here Unidirectional create table TBL_ROLE (PK_ROLE_ID BIGINT NOT NULL AUTO_INCREMENT, VC_DESCRIPTION VARCHAR (200), vC_NAME VARCHAR (20), primary key (PK_ROLE_ID)) create table tBL_USER (PK_USER_ID BIGINT NOT nULL AUTO_INCREMENT, USER_TYPE VARCHAR (255) not null, FK_GROUP_ID BIGINT, VC_EMAIL VARCHAR (82) not null unique, primary key (PK_USER_ID)) create table TBL_JOIN_USER_ROLE (FK_USER_ID BIGINT not null, FK_ROLE_ID BIGINT not null) Inheritance user employee is employee user [User.java] / *** @ hibernate.class table = "tBL_USER" * discriminator-value = "2" * @ hibernate.discriminator column = "User_type" * ......... * / public class user {[Employee.java] / *** @ hibernate.subclass discriminator-value = "1" * / public class Employee Extends user {create Table TBL_USER (PK_USE R_ID Bigint Not Null Auto_Int, User_Type Varchar (255) Not Null, FK_GROUP_ID BIGINT, VC_EMAIL VARCHAR (82) Not Null Unique, Primary Key (PK_USER_ID)) Query in Hibernate
Hibernate has three types of queries:
☆ criteria, Object composition ☆ SQL ☆ HQL
The HQL will be used in the example below. This section also uses Spring, with its AOP-Driven HibernateTemplate to simplify the processing of the Hibernate session. A DAO (Data Access Object) will be developed in this section. To learn more about DAO, see Resources.
Listing 2 shows two ways: a group query using HQL queries, the other is a group query that follows an operation. Note how Spring HibernateTemplate simplifies session management in the second method.
Listing 2. Using query
import net.sf.hibernate.HibernateException; import net.sf.hibernate.Session; import net.sf.hibernate.Query; import org.springframework.orm.hibernate.HibernateCallback; import org.springframework.orm.hibernate.support.HibernateDaoSupport / ** * @Author richard hightower * ArcMind Inc. http://www.arc-mind.com * / public class userdao extends Hibernatedaosupport {...... / ** * Demonstrates Looking Up a group with a hql query * @ Param email * @return * / public group findgroupbyName (string name) {return (group) gethateTemplate (). Find ("from group g where g.name =?", name) .get (0);} / ** * Demonstrates looking up a group and forcing it to populate users (relationship was lazy) * @param email * @return * / public Group findPopulatedGroupByName (final String name) {HibernateCallback callback = new HibernateCallback () {public Object doInHibernate (Session session) throws HibernateException, SQLException {group group group = null; string query = "from group g where g.name =?"; Query Q UeryObject = gethiberNateTemplate (). CreateQuery (session, query); QueryObject.SetParameter (0, name); group = (group) queryObject.list (). Get (0); group.getusers (). size (); // Force load return group;}}; getHibernateTemplate (). EXECUTE (Callback);} You may notice that the second method is much more complicated than the first method, because it is forced to load the User set . Because the relationship between group-> users is set to Lazy Initialize (ie, lazy = "true" in Table 2), the group object requires an active session to query the user. Set this property when defining the relationship between Group and Users, does not require a second method. In this case, the group details may be listed in the first method (FINDPOPOPULATEDGROUPBYNAME).
Spring IoC and Hibernate
When using Spring, it is easy to work outside the J2EE container. For example, in the nearest project, I use the HSQL and the local database in Eclipse to perform persistence unit testing using the HiBernate Transaction Manager's HyperSonic SQL database. Then, when deploying to the J2EE server, the persistence layer converts the persistence layer to use the J2EE data source (through JNDI), JTA transaction, and using Firebird (an open source version of InterBase). This is done using Spring as the IOC container. As can be seen from Listing 3, Spring allows to add dependencies. Note how the application context file in the list is configured for DataSource. DataSource is passed to the sessionFactory, and sessionFactory is passed to userdao.
Listing 3. Spring IoC and Hibernate
/ PrOPS> Property> bean>
Listing 4. Predefined query [user.java]
/ ** * @Author richard hightower * arcmind Inc. http://www.arc-mind.com * @ hibernate.class table = "TBL_USER" discriminator-value = "2" * @ hibernate.discriminator column = "user_type" * * @ hibernate.query name = "AllUsers" query = "from User user order by user.email asc" * * @ hibernate.query name = "OverheadStaff" * query = "from Employee employee join employee.group g where g. Name Not in ('Engineering', 'IT') "* * @ hibernate.query name =" criticalstaff "* query =" from Employee Employee Join Employee.group g where g.name in ('Engineering', 'IT') "* * @ hibernate.query name =" GetUsersInAGroup "* query =" select user from Group g join g.users user "* * @ hibernate.query name =" GetUsersNotInAGroup "* query =" select user from User user where user. group is null "* * @ hibernate.query name =" UsersBySalaryGreaterThan "* query =" from User user inner join user.contactInfo info where info.salary>? 1 "* * @ hibernate.query name =" UsersBySalaryBetween "* query = "from user user join user.contactinfo info where info. salary between? 1 AND? 2 "* * @ hibernate.query name =" UsersByLastNameLike "* query =" from User user join user.contactInfo info where info.lastName like? 1 "* * @ hibernate.query name =" GetEmailsOfUsers " * query = "SELECT USER.EMAIL from group g join g.users as user where g.name =? 1" * * / public class user {.. The above code defines several predefined queries. The predefined query is a query stored in the * .hbm.xml file. In Listing 5, you can see how to perform a predefined query.
Listing 5. predefined query [UserDAO.java] / ** * Demonstrates a query that returns a String * / public String [] getUserEmailsInGroup (String groupName) {List emailList = getHibernateTemplate () findByNamedQuery ( "GetEmailsOfUsers").; Return (String []) Emaillist.Toarray (New String [emailist.size ()]);} / ** * DemonStrates a query That Returns a list of users * * @return a list of emails of all of the users in the Uses in the . authentication system * * / public List getUsers () {return getHibernateTemplate () findByNamedQuery ( "AllUsers");.} / ** * Demonstrates passing a single argument to a query * * @return A list of UserValue objects * *.. / public List getUsersBySalary (float salary) {return getHibernateTemplate () .findByNamedQuery ( "UsersBySalaryGreaterThan", new Float (salary));} / ** * Demonstrates passing multiple arguments to a query * * @return A list of UserValue objects *. * / Public List Getus ErsbysalaryRange (Float Start, Float Stop) {Return gethibernateTemplate () .findbynamedquery ("UsersBysalarybetWeen", new Object [] {new float (start), new float (start)};
When the query is processed, the last layer can be added in the persistence layer: using Spring's transaction management.
Spring management transaction
Spring can declare transactions. For example, the UserDao.adduser method is currently not executed in a single transaction. Therefore, each user in the group is inserted into its own transaction, as shown in Listing 6.
Listing 6. Add a group of users [userdao.java]
/ ** * @Param group * / public void addgroup (group group) {gethibernateTemplate (). Save (group);}
[Userdaotest.java]
Public void testaddgroupofusers () {group group = new group (); for (int index = 0; index <10; index ) {user user = new user (); user.seTemail ("Rick" index "@ foobar.com "); User.SetPassword (" foobar "); group.adduser (user); group.setname (" testgroup "); userDao.addgroup (group); assertNotNull (Group.getId ()); group group2 = userdao. FindPopulateDgroupbyName ("TestGroup"); Assertequals ("TestGroup", Group2.getName ()); assertequals (10, group2.getusers (). size ()); string email = () Group2.getusers (). Get ( 0))). Getemail (); assertequals ("rick0@foobar.com", email);} It is not recommended to use the above solution because each User is inserted into the database in its own transaction. If there is a problem, you can only add some users. If you want to keep the ACID attribute (ie, all or all do not occur), you can perform transaction management through the program, but it will become a mess. Instead, Spring's AOP should be used to support declarative transactions, as shown in Listing 7.
Listing 7. Declared management transaction [ApplicationContext.xml]
Conclude
In this article, how to use it
Hibernate
with
Spring
Implement a business persistence layer.
Hibernate
Advanced
Oral
Mapping tool,
Spring
Is an
AOP
Frame and
IOC
container. The integrated use of these two technologies makes developers to write code comparable to database vendors, which can be
J2EE
Operation in the container can also be run separately. used
DBUnit
(
Junit
Extension) Build and test all the code of the examples in this article, although this is not the focus of discussion.