发生背景
Srping Boot集成Hibernate,使用SessionFactory对象进行数据库操作
问题
事务配置及事务不生效的问题
相关代码
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
HibernateConfig配置
@Configuration
@Slf4j
public class HibernateConfig {
@Autowired
private DataSource dataSource;
/**
* 配置会话工厂
*/
@Bean
public LocalSessionFactoryBean sessionFactoryBean() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
// 设置数据源
sessionFactoryBean.setDataSource(dataSource);
// entity包路径
sessionFactoryBean.setPackagesToScan("cn.ybzy.demo.entity");
// 配置hibernate属性
Properties properties = new Properties();
// sql方言
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
// 自动创建|更新|验证数据库表结构
properties.setProperty("hibernate.hbm2ddl.auto", "update");
// 输出sql到控制台
properties.setProperty("hibernate.show_sql", "true");
// 打印漂亮的sql
properties.setProperty("hibernate.format_sql", "true");
properties.setProperty("hibernate.current_session_context_class", "org.springframework.orm.hibernate5.SpringSessionContext");
sessionFactoryBean.setHibernateProperties(properties);
return sessionFactoryBean;
}
/**
* 配置事务管理器
*/
@Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
// 设置 sessionFactory
transactionManager.setSessionFactory(sessionFactoryBean().getObject());
return transactionManager;
}
}
Dao层
@Repository
public class MyUserDaoImpl implements IMyUserDao {
@Autowired
private SessionFactory sessionFactory;
Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
// @Autowired
// private EntityManagerFactory entityManagerFactory;
//
// Session getCurrentSession() {
// return entityManagerFactory.unwrap(SessionFactory.class).getCurrentSession();
// }
@Override
public void saveUser(User user) {
getCurrentSession().save(user);
}
}
Service层
@Transactional(rollbackFor = Exception.class)
@Service
public class UserServiceImpl implements UserService {
@Autowired
private IMyUserDao userDao;
@Override
public void saveUser(User user) {
userDao.saveUser(user);
int a=1/0;
}
}
运行结果及报错内容
1.当service层使用@Transactional(rollbackFor = Exception.class)
注解。数据查询正常,但是插入事务是生效的。报错如下,
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Aug 11 16:18:12 CST 2022
There was an unexpected error (type=Internal Server Error, status=500).
org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder
java.lang.ClassCastException: org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder
at org.springframework.orm.hibernate5.HibernateTransactionManager.doGetTransaction(HibernateTransactionManager.java:407)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:347)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:574)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:361)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy77.saveUser(Unknown Source)
at cn.ybzy.demo.controller.Controller.insert(Controller.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
2.当service层不使用@Transactional(rollbackFor = Exception.class)
注解。数据插入、查询正常,但插入若异常事务不生效。
我的解答思路和尝试过的方法
出现org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder
错误。使用@SpringBootApplication(exclude = {HibernateJpaAutoConfiguration.class})
可解决,但是事务失效。
如果service层类或方法不使用@Transactional(rollbackFor = Exception.class)
注解,则事务不生效,但是异常报错更加正常
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Aug 11 16:21:47 CST 2022
There was an unexpected error (type=Internal Server Error, status=500).
/ by zero
java.lang.ArithmeticException: / by zero
at cn.ybzy.demo.service.impl.UserServiceImpl.saveUser(UserServiceImpl.java:25)
at cn.ybzy.demo.controller.Controller.insert(Controller.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
我想要达到的结果
事务生效且报错信息正常。
There was an unexpected error (type=Internal Server Error, status=500).
/ by zero
java.lang.ArithmeticException: / by zero
at cn.ybzy.demo.service.impl.UserServiceImpl.saveUser(UserServiceImpl.java:25)
at cn.ybzy.demo.controller.Controller.insert(Controller.java:31)