【Spring】Spring ORM 深度解析

Spring ORM 详细介绍

Spring ORM 是 Spring Framework 的数据访问体系的核心模块,它提供了与主流 ORM 框架的深度集成,在保留 ORM 原生功能的同时,注入了 Spring 的声明式事务、依赖注入和异常转换等企业级能力。


一、核心定位与优势

1. 解决的问题

  • 模板代码消除:避免重复的 Session/EntityManager 开启、关闭、异常处理
  • 事务统一管理:将 ORM 操作纳入 Spring 声明式事务体系
  • 异常体系标准化 :将 ORM 原生异常转换为 Spring DataAccessException 体系
  • 资源生命周期管理:自动管理数据库连接和 ORM 会话
  • 松耦合设计:通过 IoC 容器管理 ORM 组件,便于测试和切换实现

2. 集成的 ORM 框架

  • Hibernate (最成熟):SessionFactorySession 集成
  • JPA (标准规范):EntityManagerFactoryEntityManager 集成
  • JDOPersistenceManagerFactory 集成
  • MyBatisSqlSessionFactory 集成(通过 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 应用数据访问层的基石。

相关推荐
申城异乡人2 小时前
使用Java Stream,将集合转换为一对一Map
java
嘻哈baby2 小时前
数据库连接池原理与HikariCP调优实战
后端
自由生长20242 小时前
系统的雪崩-反脆弱设计
后端
bbq粉刷匠2 小时前
Java--二叉树概念及其基础应用
java·数据结构·算法
卜锦元2 小时前
Golang后端性能优化手册(第二章:缓存策略与优化)
开发语言·数据库·后端·性能优化·golang
掘金酱2 小时前
🏆2025 AI/Vibe Coding 对我的影响 | 年终技术征文
前端·人工智能·后端
青衫码上行2 小时前
【JavaWeb学习 | 第23篇】监听器、RBAC权限模型
java·学习·servlet·jsp
狗头大军之江苏分军2 小时前
2026年了,前端到底算不算“夕阳行业”?
前端·javascript·后端
宋情写2 小时前
Springboot基础篇01-创建一个SpringBoot项目
java·spring boot·后端