写点什么

Java 高手速成 | Spring、JPA 与 Hibernate 的整合

作者:TiAmo
  • 2023-01-06
    江苏
  • 本文字数:5230 字

    阅读完需:约 17 分钟

Java高手速成 | Spring、JPA与Hibernate的整合

01、设置 Spring 的配置文件


在 Spring 的配置文件 applicationContext.xml 中,配置 C3P0 数据源、EntityManagerFactory 和 JpaTransactionManager 等 Bean 组件。以下是 applicationContext.xml 文件的源程序。

/* applicationContext.xml */<?xml version="1.0" encoding="UTF-8"?><beans xmlns=…>
<!-- 配置属性文件的文件路径 --> <context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3P0数据库连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="driverClass" value="${jdbc.driver.class}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
<!-- Spring 整合 JPA,配置 EntityManagerFactory--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa .LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor .HibernateJpaVendorAdapter">
<!-- Hibernate 相关的属性 --> <!-- 配置数据库类型 --> <property name="database" value="MYSQL"/> <!-- 显示执行的 SQL --> <property name="showSql" value="true"/> </bean> </property>
<!-- 配置Spring所扫描的实体类所在的包 --> <property name="packagesToScan"> <list> <value>mypack</value> </list> </property> </bean>
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean>
<bean id="CustomerService" class="mypack.CustomerServiceImpl" /> <bean id="CustomerDao" class="mypack.CustomerDaoImpl" />
<!-- 配置开启由注解驱动的事务处理 --> <tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置Spring需要扫描的包, Spring会扫描这些包以及子包中类的Spring注解 --> <context:component-scan base-package="mypack"/></beans>
复制代码

applicationContext.xml 配置文件的context:property-placeholder元素设定属性文件为 classpath 根路径下的 jdbc.properties 文件。C3P0 数据源会从该属性文件获取连接数据库的信息。以下是 jdbc.properties 文件的源代码。

/* jdbc.properties */jdbc.username=rootjdbc.password=1234jdbc.driver.class=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/sampledb?useSSL=false
复制代码

Spring 的 applicationContext.xml 配置文件在配置 EntityManagerFactory Bean 组件时,指定使用 HibernateJpaVendorAdapter 适配器,该适配器能够把 Hibernate 集成到 Spring 中。<property name="packagesToScan">属性指定实体类所在的包,Spring 会扫描这些包中实体类中的对象-关系映射注解。


applicationContext.xml 配置文件的tx:annotation-driven元素表明在程序中可以通过 @Transactional 注解来为委托 Spring 为一个方法声明事务边界。


02、编写范例的 Java 类


本范例运用了 Spring 框架,把业务逻辑层又细分为业务逻辑服务层、数据访问层和模型层。


在上图中,模型层包含了表示业务数据的实体类,数据访问层负责访问数据库,业务逻辑服务层负责处理各种业务逻辑,并且通过数据访问层提供的方法来完成对数据库的各种操作。CustomerDaoImpl 类、CustomerServiceImpl 类和 Tester 类都会用到 Spring API 中的类或者注解。其余的类和接口则不依赖 Spring API。


1●编写 Customer 实体类

Customer 类是普通的实体类,它不依赖 Sping API,但是会通过 JPA API 和 Hibernate API 中的注解来设置对象-关系映射。以下是 Customer 类的源代码。

/* Customer.java */@Entity@Table(name="CUSTOMERS")public class Customer implements java.io.Serializable {  @Id  @GeneratedValue(generator="increment")  @GenericGenerator(name="increment", strategy = "increment")  @Column(name="ID")  private Long id;
@Column(name="NAME") private String name;
@Column(name="AGE") private int age;
//此处省略Customer类的构造方法、set方法和get方法}
复制代码

2●编写 CustomerDao 数据访问接口和类

CustomerDao 为 DAO(Data Access Object,数据访问对象)接口,提供了与 Customer 对象有关的访问数据库的各种方法。以下是 CustomerDao 接口的源代码。

/* CustomerDao.java */public interface CustomerDao {  public void insertCustomer(Customer customer);  public void updateCustomer(Customer customer);  public void deleteCustomer(Customer customer);  public Customer findCustomerById(Long customerId);  public List<Customer>findCustomerByName(String name);}
复制代码

CustomerDaoImpl 类实现了 CustomerDao 接口,通过 Spring API 和 JPA API 来访问数据库。以下是 CustomerDaoImpl 类的源代码。

/* CustomerDaoImpl.java */package mypack;import org.springframework.stereotype.Repository;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import java.util.List;
@Repository("CustomerDao")public class CustomerDaoImpl implements CustomerDao {
@PersistenceContext(name="entityManagerFactory") private EntityManager entityManager;
public void insertCustomer(Customer customer) { entityManager.persist(customer); }
public void updateCustomer(Customer customer) { entityManager.merge(customer); }
public void deleteCustomer(Customer customer) { Customer c = findCustomerById(customer.getId()); entityManager.remove(c); }
public Customer findCustomerById(Long customerId) { return entityManager.find(Customer.class, customerId); }
public List<Customer> findCustomerByName(String name) { return entityManager .createQuery("from Customer c where c.name = :name", Customer.class) .setParameter("name", name) .getResultList(); }}
复制代码

在 CustomerDaoImpl 类中使用了以下来自 Spring API 的两个注解。

(1) @Repository 注解:表明 CustomerDaoImpl 是 DAO 类,在 Spring 的 applicationContext.xml 文件中通过<bean>元素配置了这个 Bean 组件,Spring 会负责创建该 Bean 组件,并管理它的生命周期,如:

 <bean id="CustomerDao"  class="mypack.CustomerDaoImpl" />


(2)@PersistenceContext 注解:表明 CustomerDaoImpl 类的 entityManager 属性由 Spring 来提供,Spring 会负责创建并管理 EntityManager 对象的生命周期。Spring 会根据 @PersistenceContext(name="entityManagerFactory")注解中设置的 EntityManagerFactory 对象来创建 EntityManager 对象,而 EntityManagerFactory 对象作为 Bean 组件,在 applicationContext.xml 文件中也通过<bean>元素做了配置,EntityManagerFactory 对象的生命周期也由 Spring 来管理。

从 CustomerDaoImpl 类的源代码可以看出,这个类无须管理 EntityManagerFactory 和 EntityManager 对象的生命周期,只需用 Spring API 的 @Repository 和 @PersistenceContext 注解来标识,Spring 就会自动管理这两个对象的生命周期。


在 applicationContext.xml 配置文件中 ,context:component-scan元素指定 Spring 所扫描的包,Spring 会扫描指定的包以及子包中的所有类中的 Spring 注解,提供和注解对应的功能。


3●编写 CustomerService 业务逻辑服务接口和类

CustomerService 接口作为业务逻辑服务接口,会包含一些处理业务逻辑的操作。本范例做了简化,CustomerService 接口负责保存、更新、删除和检索 Customer 对象,以下是它的源代码。

/* CustomerService.java */public interface CustomerService {  public void insertCustomer(Customer customer);  public void updateCustomer(Customer customer);  public Customer findCustomerById(Long customerId);  public void deleteCustomer(Customer customer);  public List<Customer> findCustomerByName(String name);}
复制代码

CustomerServiceImpl 类实现了 CustomerService 接口,通过 CustomerDao 组件来访问数据库,以下是它的源代码。

/* CustomerServiceImpl.java */package mypack;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.List;
@Service("CustomerService")public class CustomerServiceImpl implements CustomerService{ @Autowired private CustomerDao customerDao;
@Transactional public void insertCustomer(Customer customer){ customerDao.insertCustomer(customer); }
@Transactional public void updateCustomer(Customer customer){ customerDao.updateCustomer(customer); }
@Transactional public Customer findCustomerById(Long customerId){ return customerDao.findCustomerById(customerId); }
@Transactional public void deleteCustomer(Customer customer){ customerDao.deleteCustomer(customer); }
@Transactional public List<Customer> findCustomerByName(String name){ return customerDao.findCustomerByName(name); }}
复制代码

在 CustomerServiceImpl 类中使用了以下来自 Spring API 的三个注解。

(1)@Service 注解:表明 CustomerServiceImpl 类是服务类。在 Spring 的 applicationContext.xml 文件中通过<bean>元素配置了这个 Bean 组件,Spring 会负责创建该 Bean 组件,并管理它的生命周期,如:

<bean id="CustomerService"  class="mypack.CustomerServiceImpl" />


(2)@Autowired 注解:表明 customerDao 属性由 Spring 来提供。

(3)@Transactional 注解:表明被注解的方法是事务型的方法。Spring 将该方法中的所有操作加入到事务中。

从 CustomerServiceImpl 类的源代码可以看出,CustomerServiceImpl 类虽然依赖 CustomerDao 组件,但是无须创建和管理它的生命周期,而且 CustomerServiceImpl 类也无须显式声明事务边界。这些都由 Spring 代劳了。

4●编写测试类 Tester

Tester 类是测试程序,它会初始化 Spring 框架,并访问 CustomerService 组件,以下是它的源代码。

/* Tester.java */package mypack;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.context.ApplicationContext;import org.springframework.context.support                      .ClassPathXmlApplicationContext;import java.util.List;
public class Tester{ private ApplicationContext ctx = null; private CustomerService customerService = null;
public Tester(){ ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); customerService = ctx.getBean(CustomerService.class); }
public void test(){ Customer customer=new Customer("Tom",25); customerService.insertCustomer(customer); customer.setAge(36); customerService.updateCustomer(customer);
Customer c=customerService.findCustomerById(customer.getId()); System.out.println(c.getName()+": "+c.getAge()+"岁");
List<Customer> customers= customerService.findCustomerByName(c.getName()); for(Customer cc:customers) System.out.println(cc.getName()+": "+cc.getAge()+"岁");
customerService.deleteCustomer(customer); }
public static void main(String args[]) throws Exception { new Tester().test(); }}
复制代码

在 Tester 类的构造方法中,首先根据 applicationContext.xml 配置文件的内容,来初始化 Spring 框架,并且创建了一个 ClassPathXmlApplicationContext 对象,再调用这个对象的 getBean(CustomerService.class)方法,就能获得 CustomerService 组件。

发布于: 2023-01-06阅读数: 21
用户头像

TiAmo

关注

有能力爱自己,有余力爱别人! 2022-06-16 加入

CSDN全栈领域优质创作者;阿里云创作者社区专家博主、技术博主、星级博主;华为云享专家;

评论

发布
暂无评论
Java高手速成 | Spring、JPA与Hibernate的整合_hibernate_TiAmo_InfoQ写作社区