SpringBoot 集成 Hibernate 及事务管理配置

您所在的位置:网站首页 spring整合hibernate保存数据的方法 SpringBoot 集成 Hibernate 及事务管理配置

SpringBoot 集成 Hibernate 及事务管理配置

2023-09-23 14:20| 来源: 网络整理| 查看: 265

    笔者之前维护了一个 spring mvc + hibernate 4.x 的旧项目,最近将这个旧项目升级到了 spring boot 2.3.12 + hibernate 5.x,现将集成过程和一些需要注意的地方记录下来,方便后续继续研究。

一、pom.xml 引入与 hibernate 相关的依赖

org.springframework.boot spring-boot-starter-data-jpa mysql mysql-connector-java

    添加 spring-boot-starter-data-jpa 依赖会自动引入 hibernate 的 lib 包,如图:

二、在application.properties 对 hibernate 进行基础配置及数据源配置

# spring boot 2.3.12 hiberate spring.jpa.show-sql=true spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext # jdbc driver spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/project-name?useUnicode\=true&characterEncoding\=UTF-8&zeroDateTimeBehavior\=convertToNull spring.datasource.username=root spring.datasource.password=1234 # hikari datasource configuration spring.datasource.hikari.pool-name=KaolaHikariCp spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.idle-timeout=180000 spring.datasource.hikari.max-lifetime=180000 spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.connection-test-query=SELECT 1

三、Hebernate 配置类

    可以发现,Hebernate 配置类中的一些属性是从 application.properties 文件里获取到的。

import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.hibernate5.HibernateTransactionManager; import org.springframework.orm.hibernate5.LocalSessionFactoryBean; import java.util.Properties; @Configuration public class HibernateConfig { @Autowired private Environment environment; /** * 配置SessionFactory会话工厂注入到spring容器 * @return */ @Bean LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean(); localSessionFactoryBean.setDataSource(getDataSource()); localSessionFactoryBean.setPackagesToScan("com.hibernate.demo"); //dao与entity的公共包,这里写错,请求接口会抛出异常:org.hibernate.MappingException: Unknown entity localSessionFactoryBean.setHibernateProperties(hibernateProperties()); return localSessionFactoryBean; } /** * 配置数据源 * @return */ private DriverManagerDataSource getDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(environment.getProperty("spring.datasource.driver-class-name")); dataSource.setUsername(environment.getProperty("spring.datasource.username")); dataSource.setPassword(environment.getProperty("spring.datasource.password")); dataSource.setUrl(environment.getProperty("spring.datasource.url")); return dataSource; } /** * 设置hibernate属性配置 * @return */ private Properties hibernateProperties() { Properties properties = new Properties(); properties.setProperty("hibernate.naming-strategy", environment.getProperty("spring.jpa.hibernate.naming-strategy")); properties.setProperty("hibernate.dialect", environment.getProperty("spring.jpa.properties.hibernate.dialect")); properties.setProperty("hibernate.current_session_context_class", environment.getProperty("spring.jpa.properties.hibernate.current_session_context_class")); properties.setProperty("hibernate.show_sql", environment.getProperty("spring.jpa.show-sql")); //根据需要配置 //properties.setProperty("hibernate.hbm2ddl.auto", environment.getProperty("spring.jpa.hibernate.ddl-auto")); return properties; } /** * 配置事务管理:由HibernateTransactionManager处理 * @param sessionFactory * @return */ @Bean @Autowired public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) { HibernateTransactionManager txManager = new HibernateTransactionManager(); txManager.setSessionFactory(sessionFactory); return txManager; } }

 四、启动类配置

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.transaction.annotation.EnableTransactionManagement; //开启事务管理 @EnableTransactionManagement(proxyTargetClass = true)//启用注解事务 @SpringBootApplication(exclude = { HibernateJpaAutoConfiguration.class }) public class App extends SpringBootServletInitializer { public static void main( String[] args ) { SpringApplication.run(App.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(App.class); } }

    注意:在第三步的 hibernate 配置类里将事务管理交给 HibernateTransactionManager 来处理, 需要在 @SpringBootApplication注解里添加(exclude = { HibernateJpaAutoConfiguration.class }),否则会抛出异常:

java.lang.ClassCastException: org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder

五、其他异常状况的分析

    如果在第三步的 hibernate 配置类里不配置事务管理(即:不将事务管理交给 HibernateTransactionManager 类来处理),并且启动类@SpringBootApplication注解不额外添加(exclude = { HibernateJpaAutoConfiguration.class })的情况下,笔者为了验证事务管理是否正常,在一个声明为 @Transactional(readOnly = true) 的方法里执行 update 数据库的操作,代码如下:

@Transactional(readOnly = true) public Test getTest(int id) { testDAO.update(1, "hahaha"); //test rollback //int i = 1/0; return testDAO.get(id); }

    但是很奇怪,并没有抛出我预期中的异常,并且成功更新了数据库的数据:

java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

    另外,添加代码 int i = 1/0;  故意在更新操作完成后抛出异常时,结果显示事务管理正常执行了回滚操作,并没有更新数据库中的数据。既然事务管理已经发生作用,为什么「readonly = true」这一禁止更新操作的配置却不起作用呢?如果按照步骤四进行设置,则可以正常抛出上面的异常,同时异常回滚操作也是正常的。

    所以,目前的结论是如果将事务处理交给 HibernateTransactionManager 来处理,就需要在启动类添加@SpringBootApplication(exclude = { HibernateJpaAutoConfiguration.class }),上面提到的异常情况,具体的原因还没有搞清楚,只是猜测是因为 Springboot Jpa 自动配置的事务管理发生了异常,这里只能先记录下来,等继续学习后再来解决了,如果有了解的同学知道具体原因,还希望可以留言指导^_^

参考:

1. https://blog.csdn.net/weixin_44341110/article/details/115208375

2. https://blog.csdn.net/u011930054/article/details/106856750

3. https://www.modb.pro/db/148743

4. https://blog.csdn.net/kimheesunliulu/article/details/99550748



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3