前言
Hibernate 作为前些年广为流行的 ORM 框架,Spring 在诞生之初也进行了支持,并且抽象出一个 spring-orm 模块。
Spring 可以将 Hibernate 加入自身的事务管理,并且可以将 Hibernate 产生的异常转换为 Spring 数据访问异常,而且提供了一个便于数据库操作的 HibernateTemplate 类。
由于 Hibernate 设计较为复杂,因此在 《认识 ORM 框架 Hibernate,为什么 2022 年了还在谈论它?》 一篇中花了不少篇幅介绍 Hibernate 本身,这篇希望用简短的内容介绍如何在 Spring 项目中整合 Hibernate。
Spring Framework 整合 Hibernate
1. 依赖引入
Spring 整合 Hibernate 首先需要引入一些依赖,这里使用的依赖如下。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>4.0.3</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.6.9.Final</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.6.RELEASE</version> </dependency>
各依赖作用如下:
mysql-connector-java :Java 通过 JDBC 访问数据库必须依赖具体的数据库驱动,这里使用的是 MySQL 数据库驱动。
HikariCP :使用 JDBC 访问数据库需要建立连接和释放连接,为了降低这些开销通常使用带有连接池的数据源,HikariCP 就是一种常见的数据源实现,也是 Spring Boot 默认支持的。
hibernate-core :这个是使用 Hibernate 必须的依赖。
spring-orm :这个依赖是 Spring 整合 Hibernate 所使用的模块,可以将 Hibernate 加入 Spring 的事务管理。
spring-context : Spring 上下文所需的模块,包含 ApplicationContext 和一些 Spring 注解的定义。
2. 映射关系定义
Hibernate 作为一个 ORM 框架,映射关系的定义是必须的。这里测试使用的数据库表定义如下。
create table user ( id bigint unsigned auto_increment comment '主键' primary key, username varchar(20) not null comment '用户名', password varchar(20) not null comment '密码' );
数据库表对应的实体类如下。
@Data public class User { private Long id; private String username; private String password; }
映射关系可以使用 XML 文件定义,也可以使用 JPA 注解,这里使用 XML 文件定义,类路径下创建文件 hibernate/mapping/User.hbm.xml
,内容如下。
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.zzuhkp.hibernate.entity.User" table="user"> <id name="id" column="id"> <generator class="native"/> </id> <property name="username" column="username"/> <property name="password" column="password"/> </class> </hibernate-mapping>
3. Spring 配置
先看下定义的 Spring 配置类,然后再进行解释。
@Configuration @EnableTransactionManagement public class HibernateConfig { @Bean public DataSource dataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setDriverClassName(Driver.class.getName()); dataSource.setUsername("root"); dataSource.setPassword("12345678"); return dataSource; } @Bean public LocalSessionFactoryBean localSessionFactoryBean() { Properties properties = new Properties(); properties.put(AvailableSettings.SHOW_SQL, true); properties.put(AvailableSettings.FORMAT_SQL, true); LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean(); factoryBean.setDataSource(dataSource()); factoryBean.setHibernateProperties(properties); factoryBean.setMappingResources("hibernate/mapping/User.hbm.xml"); return factoryBean; } @Bean public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) { HibernateTransactionManager transactionManager = new HibernateTransactionManager(); transactionManager.setSessionFactory(sessionFactory); transactionManager.setDataSource(dataSource()); return transactionManager; } }
首先定义的是一个数据源 DataSource bean,这里我们使用的是 HikariCP。
然后配置类中定义了 LocalSessionFactoryBean 类型的 bean,使用 Hibernate 需要创建一个 SessionFactory,这个 bean 是 spring-orm 模块提供的用于创建 SessionFactory 的 FactoryBean。创建 SessionFactory 所使用的配置都在这个 bean 中定义,这里配置了数据源、Hibernate 的属性以及映射文件。
为了将 Hibernate 加入 Spring 的事务管理,这里定义了一个专用于 Hibernate 的事务管理器
HibernateTransactionManager,只需要设置事务管理器所使用的 SessionFacotry 以及数据源 DataSource 就可以了。
通过 LocalSessionFactoryBean 与 HibernateTransactionManager 的配合,已经可以实现通过编程的方式将 Hibernate 加入 Spring 的事务管理了,为了简化事务使用方式,这里通过 @EnableTransactionManagement 注解开启声明式事务,这样只需要在类或方法上添加 @Transactional 注解就可以了。
4. 数据库操作
必要的准备工作都做好了,下面就可以使用 Hibernate 提供的 API 操作数据库了,示例代码如下。
@Repository public class UserRepository { @Autowired private SessionFactory sessionFactory; @Transactional(rollbackFor = Exception.class) public void saveUser(User user) { Session session = sessionFactory.getCurrentSession(); session.save(user); System.out.println(user.getId()); } }
需要注意,为了将 Hibernate 加入事务管理,只能通过 SessionFactory.getCurrentSession 方法获取 Session,Spring 会在事务结束后自动提交事务和关闭会话,无需用户手动 close Session。
为了简化数据库操作,spring-orm 模块还提供了一个 HibernateTemplate 类,这个类的设计类似 JdbcTemplate,使用方式如下。
@Configuration public class HibernateConfig { @Bean public HibernateTemplate hibernateTemplate(SessionFactory sessionFactory) { HibernateTemplate hibernateTemplate = new HibernateTemplate(); hibernateTemplate.setSessionFactory(sessionFactory); return hibernateTemplate; } } @Repository public class UserRepository { @Autowired private HibernateTemplate hibernateTemplate; @Transactional(rollbackFor = Exception.class) public void saveUser(User user) { hibernateTemplate.save(user); } }
Spring Boot 整合 Hibernate
Spring Boot 项目确实对 Hibernate 进行了默认的支持,提供了一些自动化装配的特性,不过这种支持建立在 JPA 的 API 之上,而且没有提供 starter 供用户直接使用。
关于 Spring Boot 整合 Hibernate、JPA,很多博客都提到了 spring-boot-starter-data-jpa,其实这已经属于 Spring Data 项目范畴的内容了,这是 Spring Boot 对 spring-data-jpa 的支持,而非对 spring-orm 的直接支持。
关于 Spring Boot 通过 JPA API 的方式整合 Hibernate,将在下篇 Spring 整合 JPA 文章中介绍。
总结
Spring 对 Hibernate 提供了原生的支持,将 Hibernate 加入到 Spring 的事务管理,屏蔽了底层事务的差异。如果确实需要使用 Hibernate,推荐使用 Spring 提供的 HibernateTemplate 操作数据库。