- Hibernate and Spring Integration Tutorial
- Watch Out
- Dependency Workout
- Let’s Start
- Listing 1: spring.xml configuring Spring and Hibernate
- Listing 2: Contact.java model class for Contact
- Listing 3: Address.java model class for Address
- Listing 6: Main.java, from where we test our application
- Conclusion
- Spring + Hibernate для новичков
- Что такое ORM?
- Быстрый старт
Hibernate and Spring Integration Tutorial
Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.
The data support framework of Spring provides extensive utilities to integrate Hibernate. It is common to find many production applications using Hibernate as an ORM framework in Spring applications. In fact, they go pretty well with each other in leveraging the productivity of the developer.
Watch Out
As a Java programmer, sooner or later, you will encounter these two architectures and any seasoned programmer will tell you that the worst part of integrating two frameworks can be a nightmare. The dependency and configuration issues can be irritating at times, especially due to version mismatch or any other configuration changes, etc. While integrating Hibernate and Spring there are a lot of configuration, stereotype annotation issues that needs to be taken care of. However, do not let that stop you; be assured that the end result is always sweet. Assuming one has some experience with Spring and Hibernate but has never combined them, let us integrate and go hands-on with the help of a sample application.
Dependency Workout
We can use any project management and comprehension tool for integrating the required dependencies in our project. This can be especially helpful while dealing with complex dependencies. Maven is a popular project management tool that provides a uniform build system. But we will be a little rigid here, and go the old-fashioned way of downloading the frameworks and required jars individually. Once downloaded, create a library of each of them and import them into the project. To be specific our project has following dependencies apart from Java SDK, Java EE7 (especially for using JPA), MySQL5 and Netbeans IDE.
1. Spring Framework (version 4.x): Spring is comprehensively featured framework, specifically for enterprise development. Creating EJB in J2EE used to be a cumbersome experience, however that is not the case now, especially from EE7. Spring eased this difficulty to a great extent with many other features. However, one thing for sure Spring framework provides almost every feature that the current trend of enterprise development needs and one may not have to look back for more.
2. Hibernate ORM Framework (version 4.x): Where iBatis retired to namesake MyBatis, Hibernate rules the ORM world in Java. This de-facto standard of object relational modeling influenced JPA specification when Entity Beans of EJB were fumbling for an inspiration. Hibernate is going to stay in the time line of oblivion for a many years to come and evolve significantly. This can be an important ORM sidekick of the Spring framework when used effectively.
3. Apache Commons DBCP (version 2.x) and Commons Pool (version 2.x): Jestingly, Apache is full of commons (sense). They invariably provide something or the other for almost every framework in the market. These two jars provide data source related implementation and pooling of database connection. However, Spring also provides an inherent data source related implementation, for example, DriverManagerDataSource for JDBC. But apart from many other third party implementations, DBCP along with Commons Pool are some of the popular connection and pooling related implementations used in the industry. Read DBCP overview and Commons Pool overview for more detail.
4. Apache Commons AOP Alliance (Version 1.0.0): See, common (sense) again. This is one of the dependencies for the Spring framework especially for AOP (Aspect Oriented Programming). It generally comes with the Spring library. But the case is that a little older version of the Spring framework provides the beta version of this jar. So depending on the version one is using one may or may not have to specifically download this jar and add on to the project. I found a lot of errors and warnings due to the beta version of this jar in my Spring library.
5. Apache Commons Logging (Version 1.x): And yet again, this jar is necessary only if the logging feature is used in the project and it’s a common practice to log information of various actions at application run time. As said, unnecessary but good to include one.
6. MySQL Connector/J (Version 5.x): This is MySQL JDBC driver and comes in a jar file. Since we will be using MySQL database at the back end, this driver is a must.
Let’s Start
Our project will have two model classes – Contact and Address with one to many relation between them. One data access object interface – ContactDao and its implementation class ContactDaoImpl. The code given below is simple and self-explanatory for anyone with a little familiarity with these frameworks. Use the Java docs for additional information. The XML configuration file, spring.xml is the crux of integrating Spring and Hibernate.
Listing 1: spring.xml configuring Spring and Hibernate
--> org.hibernate.dialect.MySQLDialect true create-drop
org.mano.app.model.Contact org.mano.app.model.Address
Listing 2: Contact.java model class for Contact
package org.mano.app.model; //. import statements @Entity @Table(name = "contact") public class Contact implements Serializable < private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ID") private long id; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @Temporal(TemporalType.DATE) @Column(name = "BIRTH_DATE") private Date birthDate; @Column(name = "EMAIL") private String email; @Column(name = "PHONE_NUMBER") private String phoneNumber; @OneToMany(fetch = FetchType.EAGER, mappedBy = "contact", cascade = CascadeType.ALL, orphanRemoval = true) private SetcontactAddress = new HashSet<>(); public Contact() < super(); >public Contact(String firstName, String lastName, Date birthDate, String email, String phoneNumber) < this.firstName = firstName; this.lastName = lastName; this.birthDate = birthDate; this.email = email; this.phoneNumber = phoneNumber; >public void addAddress(Address address) < address.setContact(this); getContactAddress().add(address); >public void removeAddress(Address address) < getContactAddress().remove(address); >//. getters and setters @Override public String toString() < return firstName + " " + lastName + "nBirth Date: " + birthDate + "nEmail: " + email + " nPhone Number: " + phoneNumber ; >>
Listing 3: Address.java model class for Address
package org.mano.app.model; //. import statements @Entity @Table(name = "contact_address") public class Address implements Serializable < private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ID") private long id; @Column(name = "STREET") private String street; @Column(name = "CITY") private String city; @Column(name = "COUNTRY") private String country; @Column(name = "ZIP") private String zip; @ManyToOne @JoinColumn(name = "CONTACT_ID") private Contact contact; public Address() < super(); >public Address(String street, String city, String country, String zip) < super(); this.street = street; this.city = city; this.country = country; this.zip = zip; >//. getters and setters @Override public String toString() < return street + ", city=" + city + ", country=" + country + ", zip contactDao") @Transactional public class ContactDaoImpl implements ContactDao < private final Log log = LogFactory.getLog(ContactDaoImpl.class); @Autowired private SessionFactory sessionFactory; @Override public ListfindAll() < return sessionFactory.getCurrentSession().createQuery("from Contact c").list(); >@Override public Contact save(Contact contact) < sessionFactory.getCurrentSession().saveOrUpdate(contact); log.info("Contact Saved. " + contact.getId()); return contact; >@Override public void delete(Contact contact) < sessionFactory.getCurrentSession().delete(contact); log.info("Contact removed. " + contact.getId()); >>
Listing 6: Main.java, from where we test our application
package org.mano.app; //. import statements public class Main < public static void main(String[] args) < ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring.xml"); ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class); Contact c[] = new Contact[5]; c[0] = new Contact("Andrew", "Jones", new Date(), "aj@gmail.com", "123456789"); c[0].addAddress(new Address("111 ABC Street", "LA", "US", "112233")); c[0].addAddress(new Address("222 ERT Street", "CA", "US", "445566")); c[0].addAddress(new Address("333 PPP Street", "LA", "US", "667788")); c[1] = new Contact("Peter", "Parker", new Date(), "pp@hotmail.com", "654213688"); c[1].addAddress(new Address("999, XYZ street", "SOMEWHERE", "UK", "223344")); c[1].addAddress(new Address("888, KKK street", "ANYWHERE", "UK", "776644")); c[2] = new Contact("Lee", "Falk", new Date(), "lf@hotmail.com", "73645542"); c[2].addAddress(new Address("555, QPQ street", "NOWHERE", "IN", "776655")); c[2].addAddress(new Address("444, WIW street", "INWHERE", "IN", "775544")); c[3] = new Contact("Arun", "Roy", new Date(), "ar@gmail.com", "617864872"); c[3].addAddress(new Address("767, TTT street", "DL", "IN", "667788")); c[3].addAddress(new Address("898, YYY street", "MB", "IN", "554477")); c[4] = new Contact("Simrit", "Ahuja", new Date(), "sa@hotmail.com", "78766542"); c[4].addAddress(new Address("90, ZZZ street", "GK", "SA", "339988")); for (int i = 0; i < 5; i++) < contactDao.save(c[i]); >List contacts = contactDao.findAll(); for (Contact con : contacts) < System.out.println("---------------------------------------------------"); System.out.println(con.toString()); Setaddresses = con.getContactAddress(); int i=1; for (Address a : addresses) < System.out.printf("Address %d: %s", i, a.toString()); System.out.println(); i++; >> > >
Fig 1: Snapshot of the project output from Netbeans
Conclusion
The main hurdle for first time users would be writing the right configuration parameters in the XML file. Working individually with Spring and Hibernate is not much of a problem. Watch out for version mismatch between Hibernate and Spring and any other jars; consult their manual if any error crops up during compilation or runtime execution. Also watch out for in spring.xml declaration parameters. A mistake in the code is visible most of the time but a mistake in the configuration parameters is not always obvious. Happy coding!
Spring + Hibernate для новичков
На Хабре уже есть множество статей на тему работы с Hibernate, однако, как мне показалось, все они довольно сложные для новичков. Эта статья направлена на разъяснение основ работы с ORM и будет полезна в первую очередь тем, кто только начинает разрабатывать собственные приложения и имеет мало опыта работы с базами данных в общем, и с инструментами, вроде Hibernate, в частности. Матерые разработчики вряд ли найдут в статье для себя что-то новенькое; всех остальных прошу под кат.
Что такое ORM?
Ни одно современное веб-приложение не обходится без хранения огромного количества различной информации. Эту задачу обычно возлагают на специальные программы — Систему Управления Базами Данных СУБД. По схеме организации базы данных делятся на несколько видов, и так сложилось, что самым распространенным видом оказались реляционные.
В реляционных базах, данные организованны в виде сущностный (таблиц) и связей между ними. Программисты, работающие с объектно-ориентированными языками программирования, зачастую сталкиваются с задачей преобразования данных из формы, понятной СУБД в привычную объектную форму. Почти всегда решение этих задач занимает огромное количество времени и заставляет писать такие конструкции:
public ArrayList getBooksByGenreId (int genre_id) < ArrayListresult = new ArrayList<>(); try < int i = 1; String query = "SELECT * FROM books " + "LEFT JOIN genres2books " + "ON genres2books.book_id=books.id " + "WHERE genre_id=? AND books.approved = 1 " + "ORDER BY user_rating DESC LIMIT 250"; connection = getConnection(); ps = connection.prepareStatement(query); ps.setInt(i++, genre_id); resultSet = ps.executeQuery(); while (resultSet.next()) < String name = resultSet.getString("name"); String summary = resultSet.getString("summary"); String cover_url = resultSet.getString("cover_url"); String cover_min_url = resultSet.getString("cover_min_url"); String example = resultSet.getString("example"); String isbn = resultSet.getString("isbn"); String foreign_id = resultSet.getString("foreign_id"); double rev_rating = resultSet.getDouble("rev_rating"); double usr_rating = resultSet.getDouble("user_rating"); int user_id = resultSet.getInt("user_id"); int int approved = resultSet.getInt("approved"); int top = resultSet.getInt("top"); int partner_id = resultSet.getInt("partner_id"); long sum_mark = resultSet.getLong("sum_mark"); long votes_num = resultSet.getLong("votes_num"); result.add( new BookBean(id, name, summary, cover_url, cover_min_url, example, rev_rating, usr_rating, user_id, top, approved, sum_mark, votes_num, isbn, foreign_id, partner_id) ); >> catch (SQLException | IllegalArgumentException e) < e.printStackTrace(); >finally < try < if (ps!=null) ps.close(); if (connection!=null) connection.close(); >catch (Exception e) < e.printStackTrace(); >> return result; >
И это только один SELECT, а ведь нужно еще и организовать правильное подключение к СУБД и обеспечить нормальную одновременную работу нескольких пользователей.
Облегчить жизнь программистам и освободить нас от рутины призвана технология Object-Relational Mapping (ORM), которую реализует популярная библиотека Hibernate. Hibernate берет на себя задачу преобразования данных их реляционного вида в объектный, для чтения, и из объектного вида в реляционный — для записи. Кроме того, библиотека позволяет легко настроить подключение к СУБД и с помощью нее очень легко управлять транзакциями.
Быстрый старт
Сейчас мы попробуем с помощью с помощью Hibernate создать отображение в объектную форму вот такой таблицы, которая используется для хранения сессий:
Создадим Bean SessionBean. Бин — это класс, у которого есть констурктор без параметров, конструктор со всеми параметрами и определены get- и set- методы для всех полей.
@Entity //аннотация, регистрирующая класс как сущность БД @Table(name = "sessions") //связываем с конкретной таблицей по названию public class SessionBean implements Serializable < @Column(name = "username") //название таблицы в БД private String username; //название поля класса @Id //указывает на то, что следующее поле является ID и будет использоваться для поиска по умолчанию @Column(name = "series") private String series; @Column(name = "token") private String token; @Column(name = "last_used") private Timestamp lastUsed; public SessionBean() <>public SessionBean(String username, String series, String token, Timestamp lastUsed) < this.username = username; this.series = series; this.token = token; this.lastUsed = lastUsed; >public String getUsername() < return username; >public void setUsername(String username) < this.username = username; >public String getSeries() < return series; >public void setSeries(String series) < this.series = series; >public String getToken() < return token; >public void setToken(String token) < this.token = token; >public Timestamp getLastUsed() < return lastUsed; >public void setLastUsed(Timestamp last_used) < this.lastUsed = last_used; >>
Также создадим DAO (Data Access Object) — специальный класс, который будет обеспечивать для нас операции чтения и записи в базу данных
public class NEXEntityDAO < protected final ClasstypeParameterClass; public NEXEntityDAO(Class typeParameterClass) < this.typeParameterClass = typeParameterClass; >@Override public void delete(int id) < Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Bean del = (Bean) session.get(typeParameterClass, id); session.delete(del); session.getTransaction().commit(); if (session.isOpen()) < session.close(); >> @Override public ArrayList getAll() < Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); String hql = String.format("from %s",typeParameterClass.getCanonicalName()); Query SQLQuery = session.createQuery(hql); ArrayListresult = (ArrayList) SQLQuery.list(); session.getTransaction().commit(); if (session.isOpen()) < session.close(); >return result; > public Bean getById(int id) < Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Bean result = (Bean) session.get(typeParameterClass, id); session.getTransaction().commit(); if (session.isOpen()) < session.close(); >return result; > @Override public void update(Bean object) < Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); session.update(object); session.getTransaction().commit(); if (session.isOpen()) < session.close(); >> @Override public void add(Bean object) < Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); session.save(object); session.getTransaction().commit(); if (session.isOpen()) < session.close(); >> @Deprecated public void clear() < Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); String hql = String.format("delete from %s",typeParameterClass.getCanonicalName()); Query query = session.createQuery(hql); query.executeUpdate(); session.getTransaction().commit(); if (session.isOpen()) < session.close(); >> >
После чего становится очень просто извлекать, редактировать и добавлять данные в БД.
NEXEntityDAO sessionDAO = new NEXEntityDAO<>(SessionBean.class); SessionBean session = sessionDAO.getById(5) //Получить сессию с ид = 5 ArrayList allSessions = sessionDAO.getAll(); //получить список всех сессий session.setToken(“21313”); sessionDAO.update(session); //обновить существующую запись SessionBean adding = new SessionBean(“st”,”ri”,”ng”,ts); sessionDAO.add(adding); //добавить новую запись
На этом закончим знакомство с ORM. В следующих статьях мы рассмотрим наиболее интересные тонкости работы с этой технологией, а также приёмы тестирования баз данных.