Spring ORM 详细介绍
Spring ORM 是 Spring Framework 的数据访问体系的核心模块,它提供了与主流 ORM 框架的深度集成,在保留 ORM 原生功能的同时,注入了 Spring 的声明式事务、依赖注入和异常转换等企业级能力。
一、核心定位与优势
1. 解决的问题
- 模板代码消除:避免重复的 Session/EntityManager 开启、关闭、异常处理
- 事务统一管理:将 ORM 操作纳入 Spring 声明式事务体系
- 异常体系标准化 :将 ORM 原生异常转换为 Spring
DataAccessException体系 - 资源生命周期管理:自动管理数据库连接和 ORM 会话
- 松耦合设计:通过 IoC 容器管理 ORM 组件,便于测试和切换实现
2. 集成的 ORM 框架
- Hibernate (最成熟):
SessionFactory、Session集成 - JPA (标准规范):
EntityManagerFactory、EntityManager集成 - JDO :
PersistenceManagerFactory集成 - MyBatis :
SqlSessionFactory集成(通过mybatis-spring模块)
二、核心组件架构
1. 通用抽象层
java
// 统一的事务管理接口
PlatformTransactionManager
├── DataSourceTransactionManager // JDBC
├── HibernateTransactionManager // Hibernate
├── JpaTransactionManager // JPA
└── JdoTransactionManager // JDO
2. 模板类模式
java
// 核心模板类
HibernateTemplate // Hibernate 专用
JpaTemplate // JPA 专用(已过时,推荐原生 API + @Transactional)
SqlSessionTemplate // MyBatis 专用
3. 异常转换机制
java
// 转换链
ORM 原生异常 (HibernateException, PersistenceException)
↓
Spring Translator (HibernateExceptionTranslator, JpaDialect)
↓
Spring DataAccessException 体系
├── DataIntegrityViolationException
├── OptimisticLockingFailureException
└── QueryTimeoutException 等
三、Hibernate 集成详解
1. 核心配置方式
Java Config(现代推荐):
java
@Configuration
@EnableTransactionManagement
public class HibernateConfig {
@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan("com.example.domain");
Properties props = new Properties();
props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
props.put("hibernate.hbm2ddl.auto", "update");
props.put("hibernate.show_sql", "true");
factory.setHibernateProperties(props);
return factory;
}
@Bean
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
@Bean
public HibernateTemplate hibernateTemplate(SessionFactory sessionFactory) {
return new HibernateTemplate(sessionFactory);
}
}
2. DAO 实现模式
传统 HibernateTemplate 方式:
java
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private HibernateTemplate hibernateTemplate;
public User findById(Long id) {
return hibernateTemplate.get(User.class, id);
}
public void save(User user) {
hibernateTemplate.save(user);
}
public List<User> findAll() {
return hibernateTemplate.loadAll(User.class);
}
}
推荐:原生 API + @Transactional:
java
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private SessionFactory sessionFactory;
protected Session getCurrentSession() {
return sessionFactory.getCurrentSession(); // 绑定到 Spring 事务
}
public User findById(Long id) {
return getCurrentSession().get(User.class, id);
}
public void save(User user) {
getCurrentSession().persist(user);
}
}
四、JPA 集成详解
1. EntityManagerFactory 配置
java
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class JpaConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource,
JpaVendorAdapter vendorAdapter) {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
emf.setPackagesToScan("com.example.domain");
emf.setJpaVendorAdapter(vendorAdapter);
Properties props = new Properties();
props.put("hibernate.format_sql", "true");
emf.setJpaProperties(props);
return emf;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase(Database.MYSQL);
adapter.setShowSql(true);
adapter.setGenerateDdl(true);
return adapter;
}
@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
}
2. Repository 模式
java
// 传统 JpaDaoSupport
@Repository
public class UserJpaDao extends JpaDaoSupport {
public User findById(Long id) {
return getJpaTemplate().find(User.class, id);
}
}
// 现代:Spring Data JPA(推荐)
public interface UserRepository extends JpaRepository<User, Long> {
// 自动生成实现
List<User> findByLastName(String lastName);
@Query("SELECT u FROM User u WHERE u.email = ?1")
User findByEmail(String email);
}
五、事务管理深度集成
1. 声明式事务配置
java
@Service
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
// 方法级事务控制
@Transactional(readOnly = true, timeout = 30)
public User getUser(Long id) {
return userDao.findById(id);
}
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED)
public void createUser(User user) {
userDao.save(user);
// 其他业务逻辑
}
}
2. 事务传播行为
java
// REQUIRED(默认):加入现有事务或创建新事务
// REQUIRES_NEW:挂起当前事务,创建新事务
// NESTED:嵌套事务(保存点)
// SUPPORTS:有事务则加入,无则非事务执行
// NOT_SUPPORTED:挂起事务,非事务执行
// MANDATORY:必须在事务中执行
// NEVER:必须非事务执行
六、Open Session In View 模式
问题场景
在 Web 层访问懒加载属性时,Session 已关闭导致 LazyInitializationException
解决方案
java
// Web 配置(Spring Boot 自动配置)
@Bean
public OpenSessionInViewFilter openSessionInViewFilter() {
return new OpenSessionInViewFilter();
}
// 或使用拦截器(JPA)
@Bean
public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() {
return new OpenEntityManagerInViewInterceptor();
}
注意事项:
- 延长 Session 生命周期,可能增加连接占用时间
- 推荐在 Service 层完成所有数据加载(DTO 模式)
- Spring Boot 2.x 后默认禁用,需手动开启
七、MyBatis 集成要点
1. 配置方式
java
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mappers/*.xml")
);
return factory.getSqlSessionFactory();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory factory) {
return new SqlSessionTemplate(factory);
}
// 自动扫描 Mapper 接口
@Bean
public MapperScannerConfigurer mapperScanner() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.example.mapper");
return configurer;
}
}
2. Mapper 使用
java
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User findById(@Param("id") Long id);
@Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insert(User user);
}
八、核心最佳实践
1. 项目结构建议
com.example
├── config // 配置类
├── domain // 实体类
├── repository // DAO/Repository 接口
├── service // 业务服务
└── web // 控制器
2. 性能优化策略
- 二级缓存:集成 Hibernate 二级缓存(EhCache、Redis)
- 批量操作 :使用
hibernate.jdbc.batch_size - 抓取策略 :
@BatchSize、@Fetch(FetchMode.SUBSELECT) - 连接池:HikariCP(Spring Boot 默认)
- 只读事务 :
@Transactional(readOnly = true)优化性能
3. 测试支持
java
@RunWith(SpringRunner.class)
@DataJpaTest // 自动配置内存数据库和 JPA
public class UserRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
public void testFindById() {
// 测试代码
}
}
九、Spring Boot 自动配置
1. 简化配置
yaml
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
# MyBatis 配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.domain
2. Starter 依赖
xml
<!-- JPA + Hibernate -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
十、总结对比
| 特性 | Hibernate | JPA | MyBatis |
|---|---|---|---|
| 抽象级别 | 全自动 ORM | 标准 ORM 规范 | 半自动 SQL 映射 |
| 学习曲线 | 陡峭 | 中等 | 平缓 |
| 灵活性 | 低 | 中 | 高 |
| 性能调优 | 较难 | 较难 | 容易 |
| SQL 控制 | 弱 | 弱 | 强 |
| Spring 集成 | 成熟 | 最推荐 | 良好 |
| 适用场景 | 快速开发 | 企业标准 | 复杂 SQL/遗留系统 |
选型建议:
- 新项目:优先 JPA + Spring Data JPA
- 复杂查询:JPA + QueryDSL 或 MyBatis
- 遗留系统:MyBatis 渐进式改造
- 性能极致:Hibernate 原生 SQL + 二级缓存
Spring ORM 的价值在于提供了统一的编程模型 和声明式基础设施,让开发者专注于业务逻辑而非资源管理,是企业级 Java 应用数据访问层的基石。