post-image

[Thực hành] Ứng dụng quản lý danh sách khách hàng

5. ORM

Mục tiêu

Thực hành sử dụng một framework ORM phổ biến là hibernate để ánh xạ bộ nhớ của chương trình với database.

Mô tả

Bổ sung khả năng ngoại hóa cơ sở dữ liệu cho chương trình quản lý danh sách khách hàng.

Hướng dẫn

Bước 1: thăm dò chương trình có sẵn

Tải chương trình tại file đính kèm, thực hiện các bước cài đặt cần thiết để khởi động chương trình, đọc mã và thăm dò chức năng của chương trình.

Bước 2: mô tả entity

Mô tả dữ liệu cần ngoại hóa như là các entity, mỗi entity như một dòng dữ liệu trong cơ sở dữ liệu quan hệ. Mỗi trường của entity như giá trị tại một cột tương ứng của dòng dữ liệu đó.

Với Hibernate, việc mô tả một entity được thực hiện trên class, việc mô tả một class tương ứng với một entity được thực hiện bởi hành động đánh annotation cho class và cho các trường của class đó.

Trước tiên, bổ sung thư viện Hibernate:

compile group: 'org.hibernate', name: 'hibernate-core', version: '5.4.3.Final'
Đánh dấu rằng class Customer là tương ứng với một entity:

import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table
public class Customer implements Cloneable {
   // ...
}

Hibernate cần biết cách gắn một đối tượng của class customer với một dòng dữ liệu cụ thể tại database, do đó nó cần biết trường nào trong class Customer là tương ứng với khóa chính:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

Bước 3: tạo database để Hibernate kết nối tới

Bước 4: Bổ sung một triển khai khác của CustomerService

Tạo một class mới để viết triển khai mới cho CustomerService

public class HibernateCustomerServiceImpl implements CustomerService {

  @Override
  public List<Customer> findAll() {
    return Collections.emptyList();
  }

  @Override
  public Customer findOne(Long id) {
    return null;
  }

  @Override
  public Customer save(Customer customer) {
    return null;
  }

  @Override
  public List<Customer> save(List<Customer> customers) {
    return null;
  }

  @Override
  public boolean exists(Long id) {
    return false;
  }

  @Override
  public List<Customer> findAll(List<Long> ids) {
    return Collections.emptyList();
  }

  @Override
  public long count() {
    return 0;
  }

  @Override
  public void delete(Long id) {
  }

  @Override
  public void delete(Customer customer) {
  }

  @Override
  public void delete(List<Customer> customers) {
  }

  @Override
  public void deleteAll() {
  }
}

Thay đổi bean để app chuyển sang  sử dụng triển khai này:

@Bean
public CustomerService customerService() {
    return new HibernateCustomerServiceImpl();
}

Bước 5: chuẩn bị để hibernate có thể kết nối tới database

Để việc ánh xạ có thể diễn ra, trước tiên hibernate cần khởi động phiên làm việc của nó với database. Để thực hiện việc này trước tiên cần có drive jdbc, bổ sung thư viện này, lưu ý sử dụng đúng phiên bản phù hợp với mysql đang sử dụng:

compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.11'

Ngoài ra, hibernate cần có cấu hình kết nối, phương thức xác thực, cùng với tên drive jdbc. Tất cả những thông tin này có thể được mô tả trong một file cấu hình. Tạo file hibernate.conf.xml vào trong thư mục src/main/resources:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/cms</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">123456</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    <property name="show_sql">true</property>
    <property name="hbm2ddl.auto">update</property>
    <mapping class="cg.wbd.grandemonstration.model.Customer"/>
  </session-factory>
</hibernate-configuration>

“show_sql” gợi ý rằng các câu SQL mà Hibernate sử dụng sẽ được log ra logstream của hệ thống, “hbm2ddl.auto” gợi ý rằng khi database không có bảng, hay các bảng trong database cũ hơn so với mô tả tại entity class, hibernate sẽ tiến hành cập nhật cấu trúc các bảng.
Trong jdbc URL, cms chính là tên của database đã tạo ở bước 3 

Bước 6: cho hibernate tạo kết nối tới database

Thêm đoạn mã static sau vào class service, deploy lại dự án và xác nhận rằng không có lỗi xảy ra, kiểm tra database để thấy rằng bảng Customer đã được tạo.

static {
  try {
    SessionFactory sessionFactory = new Configuration()
        .configure("hibernate.conf.xml")
        .buildSessionFactory();
    sessionFactory.close();
  } catch (HibernateException e) {
    e.printStackTrace();
  }
}

Bước 7: tạo entityManager

Sau khi thành công, xóa bỏ dòng lệnh đóng session, tạo một entityManager, và lưu trữ cả sessionFactory lẫn entityManager vào những biến static để dùng trong service:

private static SessionFactory sessionFactory;
private static EntityManager entityManager;

static {
  try {
    sessionFactory = new Configuration()
        .configure("hibernate.conf.xml")
        .buildSessionFactory();
    entityManager = sessionFactory.createEntityManager();
  } catch (HibernateException e) {
    e.printStackTrace();
  }
}

Bước 8: triển khai các phương thức publish của service

Dùng sessionFactory để lấy entityManager, sau đó sử dụng entityManager để chạy query cần thiết để lấy danh sách customer:

@Override
public List<Customer> findAll() {
  String queryStr = "SELECT c FROM Customer AS c";
  TypedQuery<Customer> query = entityManager.createQuery(queryStr, Customer.class);
  return query.getResultList();
}

Tương tự, triển khai phương thức lấy thông tin customer:

@Override
public Customer findOne(Long id) {
  String queryStr = "SELECT c FROM Customer AS c WHERE c.id = :id";
  TypedQuery<Customer> query = entityManager.createQuery(queryStr, Customer.class);
  query.setParameter("id", id);
  return query.getSingleResult();
}

Bước 9: triển khai phương thức update Customer

Update là một thao tác sửa đổi dữ liệu. Các thao tác dạng này bắt buộc phải được thực hiện trong một transaction.

@Override
public Customer save(Customer customer) {
  Session session = null;
  Transaction transaction = null;
  try {
    session = sessionFactory.openSession();
    transaction = session.beginTransaction();
    Customer origin = findOne(customer.getId());
    origin.setName(customer.getName());
    origin.setEmail(customer.getEmail());
    origin.setAddress(customer.getAddress());
    session.saveOrUpdate(origin);
    transaction.commit();
    return origin;
  } catch (Exception e) {
    e.printStackTrace();
    if (transaction != null) {
      transaction.rollback();
    }
  } finally {
    if (session != null) {
      session.close();
    }
  }
  return null;
}

Leave a Reply

Your email address will not be published. Required fields are marked *