Java-Podcast

Data Access Objects – What are they?

Data Access Objects (or DAOs for short) are used as a direct line of connection and communication with our database. DAOs are used when the actual CRUD (CRUD = Create, Read, Update, Delete) operations are needed and invoked in our Java code. These data access objects also represent the “data layer” of our application.

These objects are still just plain old Java objects that incorporate the use of some Hibernate annotations to give them the functionality we need from them. Again, that functionality being the communication with the database.

Also, believe it or not, the concept of creating a file specifically for accessing the database is a design pattern. It's called the Data Access Object Pattern and you can read more about it from this nice short Wiki article.

What Hibernate Annotations Should We Use?

Okay, so now that you're somewhat familiar with DAOs, it's time to learn how to integrate these plain old Java objects with our Hibernate framework (so they actually do the work we need them to do).

There are two main annotations that you need to be familiar with:

  • @Repository
  • @Transactional

The first of the two annotations @Repository is one from Spring and it's pretty straight-forward. It's used to mark the Java file as something Spring calls a “Component”, which enables it to be scanned and incorporated into Spring's code. You really just need to remember to put this annotation in all of your DAOs (on the class level) and you'll be good to go.

The second (and more complicated) annotation is the @Transactional annotation. This annotation is used as a means to enable transaction management within your Java DAO file.

Transaction management is a vast (and complex) topic. I'll give you a brief overview of what it is and why it's useful.

Transaction management is all about data integrity… which means it's all about keeping your data valid, non-corrupt and error free: three things that are very handy! Let's think of the opposite scenario, having our data be invalid, corrupt and full of errors… does that last sentence make you wince? Well, if it does, then transaction management is the vaccine you need.

What is a Transaction?

A transaction (as it pertains to databases) is the trick we use to be able to roll back (or revert) a database operation. Consider the following database operation:

insert into users (username, password) values ('trevor_page', 'password**!');

This database operation has to do a few things:

  1. Insert a new row of data into the users table
  2. Assign a primary key to this new row
  3. Populate the new row with the provided data

Fairly straight forward stuff, but what happens if your database server crashed after step #1? Or what happens if someone yanks the power cord out of the server by accident after step #1? What happens if the disk drive becomes full after step #2?

All of these scenarios would leave the database operation only “partly committed”. If we were to leave the data as is, in its partially committed state, then our data would be corrupt and could lead to errors in our application. NOT COOL!

Okay, so now let's consider what I've said about a database transaction. Its job is to “roll back” the database operation if it doesn't complete correctly. So let's assume that we open a transaction, start our database operation, get to step #2 and then there's a failure. The database keeps track of the “state” its in and (once restored) sees that there's a transaction that was not fully committed, so it will roll back to the previously known “stable state”… thus eliminating the partially committed (and invalid) data.

Magic!

So you see why transactions are so useful? They will save your butt when the unexpected becomes a reality… now there's a whole lot more to understand about transactions, but that's outside of the scope of this conversation, so I'll get back to the topic at hand.

Example of a Real Data Access Object in Java

Okay, so now it's time for the big reveal! Let's take a look at an example DAO class that I've created.

We've been talking about using the example of an Address Book program, so let's take a look at what the beginning of our Address Book DAO would look like:

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class AddressBookDao
{
  // empty class... for now!
}

As you can see above, we have put both of the annotations that we've just learned about at the class level for the DAO.

Pretty straight forward right?

Now let's talk about the SessionFactory

What the heck is a SessionFactory?

A SessionFactory is what we use to grab individual Sessions so that we can talk to our database. It uses the Factory design pattern, which essentially means it's sole purpose is to dish our Sessions whenever you ask for them.

So the real question here is, what the heck is a Session?!

A Session is what we use to create open our initial transaction, perform some kind of database operation, and then commit the transaction (or roll it back if there was a failure).

Let's take a look at how we get a Session in Java:

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class AddressBookDao
{
  @Autowired
  SessionFactory sessionFactory;

  /**
   * Save an AddressBook object to the database
   */
  public void save(AddressBook addressBook)
  {
  	Session currentSession = sessionFactory.getCurrentSession();
  	currentSession.saveOrUpdate(addressBook);
  }
}

Now things are starting to get a little more interesting!

You see that we used the @Autowired annotation to automatically populate the sessionFactory with an actual real instantiated instance. Spring can do this because we've already configured the SessionFactory in our PersistenceConfig class. If you don't remember what that file is, you can read about it in this post.

Once we have a real instance of the SessionFactory we can use it to grab a real Session. We do so by invoking the getCurrentSession() method and assign it to a variable.

Now that we have a Session we can invoke one of our CRUD operations. In the example above, I am invoking a saveOrUpdate(), which will either create a new row of data or update an existing row.

Hibernate's saveOrUpdate Method

This is a very important method to understand, as it incorporates one of the fundamental rules by which Hibernate operates.

You see, how the heck is Hibernate supposed to know whether or not you wish to create a new row of data with the object you've given to it, or if it should update an existing row of data?

Let's assume you've created a brand new AddressBook object and populated it with some relevant information. Now you wish to save it to the database… YOU know that it's a new piece of data, and therefore it should have a new row created in the database… but how does Hibernate know?

Hibernate looks at the @Id variable that you've defined in the AddressBook class! If there's an actual ID value assigned to your object, then that means it must already exist in the database and therefore this operation should be an UPDATE… if there's no ID valued populated in the AddressBook object (i.e. it's null), then it should be a new row and it performs an INSERT.

So let's say we have the following AddressBook scenario:

AddressBook ab = new AddressBook();
ab.setId(1L);
ab.setCity("Toronto");
ab.setCountry("Canada");
ab.setEmailAddress("trevor@javavideotutorials.net");
ab.setName("Trevor Page");
ab.setPhoneNumber("555-555-1234");
ab.setRegion("Ontario");
ab.setStreetAddress("123 Fake St");
ab.setZipCode("M1M 3M2);
addressBookDao.save(ab);

What do you think will happen when we invoke the save(ab) method?

If you look carefully, you'll see that I've assigned a value to the ID field… so given my explanation above, that means that Hibernate will perform an UPDATE.

Now, what happens if we get rid of the line of code that assigns the ID?

AddressBook ab = new AddressBook();
//ab.setId(1L);
ab.setCity("Toronto");
ab.setCountry("Canada");
ab.setEmailAddress("trevor@javavideotutorials.net");
ab.setName("Trevor Page");
ab.setPhoneNumber("555-555-1234");
ab.setRegion("Ontario");
ab.setStreetAddress("123 Fake St");
ab.setZipCode("M1M 3M2);
addressBookDao.save(ab);

Now when we run the save(ab) method, hibernate sees that there's no ID set, so it will perform an INSERT.

The functionality described above is critical to understand!

How do we Read from the Database with Hibernate?

Another great question, here we will make use of something called Criteria. Criteria is the object that we will use to create SQL queries in Java… if you like you can also create native SQL queries with Hibernate, but it's actually a LOT easier to use Criterias.

In the example below, you will see how we create the Criteria to search the address_book table for the name that we will pass in:

public List getAddressBookByName (String name)
{
  	Session currentSession = sessionFactory.getCurrentSession();

  	List list = currentSession.createCriteria(AddressBook.class)
                             .add(Restrictions.eq("name", name))
                             .list();
  	return list;
}

We use a Session to create the Criteria and we add Restrictions to filter our results.

To illustrate how this works, let's assume we just use this Criteria:

List list = currentSession.createCriteria(AddressBook.class).list();

This will create the following SQL query:

select * from address_book;

This is a very broad search, and thus we need to add a filter on it to make it more narrow. Remember that our current mission is to retrieve a particular person's address information. We do this by adding Restrictions, and in our example we restrict the broad results by searching for a name.

We then invoke the list() method which will actually execute the query and return a list of results. If there are no matching entries then it will be an empty list, if there are one or more entries, then they will be populated in our list.

Easy peasy.

There is lots more we can do with the Criteria object in Hibernate, such as grouping and ordering our data… but that's a topic for discussion later.

How do we Delete Rows from the Database?

Our final topic will be about deleting rows.

The only thing you need to know here is that you actually need to LOAD the row from the database before you can delete it. This is something built into the Hibernate framework and it's another concept that is important to understand. If you simply just create your own object manually and then pass it in to a delete method, hibernate won't be able to carry out the operation as the object you've asked to be deleted is “detached”.

There's some great information on the “state” of objects as they pertain to the Hibernate framework in this tutorial from JBoss. It's a bit of a heavy read, but it's definitely good to understand how this stuff works.

In any case, the point here is that you need to make sure the object that you wish to delete is the actual persistent version of the object. So this means you'll need to first load the object from the database before invoking the delete. Here's how to do it:

public void deleteById (Long id)
  {
  	Session currentSession = sessionFactory.getCurrentSession();

  	AddressBook result = (AddressBook) currentSession.createCriteria(AddressBook.class)
                             .add(Restrictions.idEq(id))
                             .uniqueResult();

  	if (result != null)
  	{
  		currentSession.delete(result);
  	}
  }

The only curve-ball in this code is the use of the uniqueResult() method. Previously when we read data from the database, we used the list() method to invoke our query, but here we have a slightly different scenario. We are loading the object by the ID, so we know there is only going to be ONE result back from the database… since we know we are only getting one object back, we can ask for a uniqueResult as opposed to getting list.

And that's really all there is to it in the simple cases.

You now know how to Create, Read, Update and Delete data using Hibernate! Congrats!

If you liked this tutorial, I'd highly recommend jumping on my mailing list. I will keep you up to date with all the need to know information related to Java programming, plus you'll get access to a list of the top 7 tools that Java professionals use every day, as well as invitations to all of my free webinars that I host where I sit down with you and teach important subjects in the Java world.

To join the mailing list just fill out your email in the popup below or navigate to this sign up page!

Free Java Beginners Course

Start learning how to code today with our free beginners course. Learn more.