首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring 整合 ORM 全攻略:Hibernate、JPA、MyBatis 統一資源管理、異常轉換與事務控制

     編輯:Java 相關知識

為什麼在 Spring 中使用 ORM?

Spring 不強制綁定特定 ORM,但提供一致性抽象層,讓你在保留各框架特性的同時,獲得:

  • 資源管理統一:SessionFactory、EntityManager、SqlSessionFactory 皆由容器生命週期管控
  • 異常體系統一:將 HibernateException、JDOException、SQLException 統一轉為 DataAccessException 體系(RuntimeException)
  • 事務管理統一:聲明式 @Transactional 橫跨 JDBC、Hibernate、JPA、MyBatis,支援 JTA 分散式事務
  • 測試友善:IoC 容器輕鬆替換 DataSource、SessionFactory 為測試雙重

核心整合模式

1. 資源定義於 ApplicationContext

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="org.postgresql.Driver"/>
    <property name="url" value="jdbc:postgresql://localhost:5432/mydb"/>
    <property name="username" value="app"/>
    <property name="password" value="secret"/>
</bean>

<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="com.myapp.domain"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<!-- JPA EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="com.myapp.domain"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="true"/>
        </bean>
    </property>
</bean>

<!-- MyBatis SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath*:mapper/**/*.xml"/>
</bean>

2. DAO 實作注入資源,而非自行查找

@Repository
public class HibernateUserDao implements UserDao {
    private final SessionFactory sessionFactory;

    @Autowired
    public HibernateUserDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public User findById(Long id) {
        return sessionFactory.getCurrentSession().get(User.class, id);
    }
}

@Repository
public class MyBatisUserDao implements UserDao {
    private final SqlSessionTemplate sqlSession;

    @Autowired
    public MyBatisUserDao(SqlSessionFactory sqlSessionFactory) {
        this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }

    @Override
    public User findById(Long id) {
        return sqlSession.selectOne("com.myapp.mapper.UserMapper.selectById", id);
    }
}

3. 模板類簡化樣板碼(可選)

  • HibernateTemplate / JpaTemplate:封裝 Session/EntityManager 獲取、關閉、異常轉換
  • SqlSessionTemplate:線程安全、自動參與 Spring 事務
  • 現代建議:直接注入原生 API(SessionFactory、EntityManager、SqlSessionTemplate),代碼更清晰、類型安全

異常轉換機制

Spring PersistenceExceptionTranslator 攔截底層異常,映射為 org.springframework.dao.DataAccessException 子類:

上層業務代碼僅捕獲具體語義異常,無需處理 checked exception,也不綁定特定 ORM。

事務管理:聲明式與編程式

@Configuration
@EnableTransactionManagement
public class TxConfig {
    @Bean
    public PlatformTransactionManager txManager(SessionFactory sf) {
        return new HibernateTransactionManager(sf); // 或 JpaTransactionManager / DataSourceTransactionManager
    }
}

@Service
@Transactional(readOnly = true)
public class OrderService {
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void placeOrder(Order order) { ... }
}

關鍵優勢:同一事務管理器可同時管控 Hibernate Session、JPA EntityManager、JDBC Connection,實現混合持久化技術的事務一致性。

混合持久化架構示例

@Service
@RequiredArgsConstructor
public class ReportService {
    private final JdbcTemplate jdbc;           // 複雜報表 SQL
    private final EntityManager em;            // 域模型持久化
    private final SqlSessionTemplate sqlSession; // MyBatis 映射查詢

    @Transactional
    public void generateMonthlyReport(YearMonth ym) {
        // 1. JPA 保存報表元數據
        ReportMeta meta = new ReportMeta(ym);
        em.persist(meta);

        // 2. JdbcTemplate 執行大數據聚合
        List agg = jdbc.query("SELECT ...", new SalesRowMapper());

        // 3. MyBatis 批次寫入明細
        sqlSession.insert("ReportMapper.batchInsertDetails", agg);

        // 4. 更新元數據狀態
        meta.setStatus(COMPLETED);
    }
}

最佳實踐清單

  1. 單一資料源原則:一個微服務/模組僅配置一個 DataSource,多 ORM 共享
  2. 事務邊界在 Service 層:DAO/Repository 不開啟事務,純粹執行持久化操作
  3. 異常不捕獲或轉換為業務異常:讓 Spring 統一轉換,Controller 層統一處理
  4. Session/EntityManager 綁定當前線程:由 OpenSessionInViewFilter (Web) 或 @Transactional (Service) 管理,避免手動 open/close
  5. 測試用內嵌資料庫:H2 / Testcontainers,配合 @DataJpaTest / @MybatisTest 极速驗證

總結

Spring 的 ORM 整合不僅是「配置方便」,更構建了技術無關的持久化抽象層。團隊可根據業務場景靈活選擇:核心域模型用 JPA/Hibernate 表達豐富語義,複雜查詢用 MyBatis/JdbcTemplate 精準控制 SQL,批次操作用 JDBC batch。統一的資源管理、異常體系與事務邊界,讓混合持久化不再是噩夢,而是架構靈活性的來源。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
底層異常Spring 異常語義
ConstraintViolationExceptionDataIntegrityViolationException唯一鍵/外鍵/非空約束違反
OptimisticLockExceptionObjectOptimisticLockingFailureException樂觀鎖衝突
QueryTimeoutExceptionQueryTimeoutException查詢超時
DeadlockLoserDataAccessExceptionDeadlockLoserDataAccessException死鎖受害者