java.lang.NoSuchMethodError: 'java.sql.Connection org.hibernate.engine.spi.SharedSessionContractImplementor.connection()'
Всем привет! Создаю веб-приложение на основе Spring-MVC, Hibernate, MySQL.
Проблема:
В DAO (репозиториях) у были написаны вручную транзакции с помощью Hibernate, но при переходе на @Transactional, начало кидать следующую ошибку: java.lang.NoSuchMethodError: 'java.sql.Connection org.hibernate.engine.spi.SharedSessionContractImplementor.connection()'.
Error Logs:
java.lang.NoSuchMethodError: 'java.sql.Connection org.hibernate.engine.spi.SharedSessionContractImplementor.connection()'
at org.springframework.orm.hibernate5.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:565)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:595)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:382)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at jdk.proxy5/jdk.proxy5.$Proxy271.create(Unknown Source)
at com.senla.hotel.controllers.ClientController.create(ClientController.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
Service Layer:
package com.senla.hotel.services;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.senla.hotel.dto.ServiceDto;
import com.senla.hotel.entities.Service;
import com.senla.hotel.repos.interfaces.IServiceRepository;
import com.senla.hotel.services.interfaces.IServiceService;
import com.senla.hotel.utils.comparators.ServiceComparatorsMap;
import com.senla.hotel.utils.enums.entities.SortMethods;
import com.senla.hotel.utils.mappers.EntityDtoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@org.springframework.stereotype.Service
public class ServiceService implements IServiceService {
@Autowired
private IServiceRepository serviceRepository;
@Autowired
private EntityDtoMapper mapper;
@Override
@Transactional
public ServiceDto create(ServiceDto serviceDto) {
return mapper.entity2dto(serviceRepository.create(mapper.dto2entity(serviceDto)));
}
@Override
@Transactional(readOnly = true)
public List<ServiceDto> getList(SortMethods sortMethod) {
List<Service> services = serviceRepository.getList();
if (sortMethod != SortMethods.NULL) {
Comparator<Service> comparator = ServiceComparatorsMap.getComparatorBySorting(sortMethod);
services.sort(comparator);
}
return services.stream().map(service -> mapper.entity2dto(service)).toList();
}
@Override
@Transactional
public List<ServiceDto> insert(List<ServiceDto> services) {
return serviceRepository.insert(services.stream().map(serviceDto -> mapper.dto2entity(serviceDto)).toList()).
stream().map(service -> mapper.entity2dto(service)).toList();
}
@Override
@Transactional(readOnly = true)
public ServiceDto findById(int serviceId) {
return mapper.entity2dto(serviceRepository.findById(serviceId));
}
@Override
@Transactional
public boolean importEntities(String filePath) {
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
try {
List<Service> services = mapper.readValue(new File(filePath), new TypeReference<List<Service>>() {
});
this.serviceRepository.insert(services);
return true;
} catch (IOException exc) {
exc.printStackTrace();
return false;
}
}
@Override
@Transactional(readOnly = true)
public Map<ServiceDto, Float> getServicesCosts(SortMethods sortMethod) {
Map<ServiceDto, Float> serviceCostMap = new LinkedHashMap<>();
List<Service> list = serviceRepository.getList();
if (sortMethod != SortMethods.NULL) {
Comparator<Service> comparator = ServiceComparatorsMap.getComparatorBySorting(sortMethod);
list.sort(comparator);
}
for (Service service : list) {
serviceCostMap.put(mapper.entity2dto(service), (float) (service.getCost() / 100.0));
}
return serviceCostMap;
}
@Override
@Transactional(readOnly = true)
public void exportEntities(String filePath) {
List<Service> servicesList = this.serviceRepository.getList();
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
try {
mapper.writeValue(new File(filePath), servicesList);
} catch (IOException exc) {
exc.printStackTrace();
}
}
}
DAO (Repository) Layer:
package com.senla.hotel.repos;
import com.senla.hotel.entities.Service;
import com.senla.hotel.repos.interfaces.IServiceRepository;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import lombok.Setter;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
@Setter
@Repository
public class ServiceRepository implements IServiceRepository {
@Autowired
SessionFactory sessionFactory;
@Override
public Service create(Service service) {
getCurrentSession().persist(service);
return service;
}
@Override
public Service updateById(int serviceId, Service service) {
service.setId(serviceId);
return getCurrentSession().merge(service);
}
@Override
public Service findById(Integer serviceId) {
return getCurrentSession().byId(Service.class).load(serviceId);
}
@Override
public boolean deleteById(int serviceId) {
Service service = findById(serviceId);
getCurrentSession().remove(service);
return true;
}
@Override
public List<Service> insert(List<Service> list) {
int batch_size = sessionFactory.getSessionFactoryOptions().getJdbcBatchSize();
Session session = getCurrentSession();
int i = 0;
for (Service service : list) {
if (i % batch_size == 0 && i > 0) {
session.flush();
session.clear();
}
session.persist(service);
i++;
}
return list;
}
@Override
public List<Service> getList() {
Session session = getCurrentSession();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Service> cq = cb.createQuery(Service.class);
Root<Service> root = cq.from(Service.class);
cq.select(root);
Query<Service> query = session.createQuery(cq);
return query.getResultList();
}
private Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
CONFIG Layer:
package com.senla.hotel.config;
import com.senla.hotel.entities.Client;
import com.senla.hotel.entities.ReleaseDate;
import com.senla.hotel.entities.Room;
import com.senla.hotel.entities.Service;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.Properties;
@Configuration
@EnableTransactionManagement
@ComponentScan("com.senla.hotel")
@PropertySource("classpath:/app.properties")
public class JavaConfig {
@Bean
public DriverManagerDataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource(
"jdbc:mysql://localhost/hoteldb?createDatabaseIfNotExist=true",
"root",
"poker88"
);
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
return dataSource;
}
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
// hibernate properties
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.setProperty("hibernate.show_sql", "false");
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.jdbc.batch_size", "25");
sessionFactory.setHibernateProperties(properties);
sessionFactory.setAnnotatedClasses(Client.class, Room.class, Service.class, ReleaseDate.class);
return sessionFactory;
}
@Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
@Bean
@Scope("prototype")
public Logger logger(final InjectionPoint ip) {
final Class<?> lClass;
if (null != ip.getMethodParameter()) {
lClass = ip.getMethodParameter().getContainingClass();
} else {
lClass = ip.getField().getDeclaringClass();
}
return LogManager.getLogger(lClass);
}
}
POM.XML:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.senla</groupId>
<artifactId>hotel</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${checkstyle.version}</version>
<configuration>
<configLocation>${resources.path}/checkstyle.xml</configLocation>
<suppressionsLocation>${resources.path}/suppressions.xml</suppressionsLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<linkXRef>false</linkXRef>
</configuration>
<executions>
<execution>
<id>verify</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat7-maven-plugin -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>maven-tomcat-war-deployment-server</server>
<path>/hotel</path>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
<properties>
<com.fasterxml.jackson.core.version>2.13.3</com.fasterxml.jackson.core.version>
<slf4j.version>1.7.36</slf4j.version>
<checkstyle.version>3.1.2</checkstyle.version>
<resources.path>src/main/resources</resources.path>
<spring.version>5.3.22</spring.version>
</properties>
<dependencies>
<!-- jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${com.fasterxml.jackson.core.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${com.fasterxml.jackson.core.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${com.fasterxml.jackson.core.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${com.fasterxml.jackson.core.version}</version>
</dependency>
<!-- javassist-->
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- reflections-->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
<!-- log4j2-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<!-- slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- checkstyle plugin-->
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${checkstyle.version}</version>
<type>maven-plugin</type>
</dependency>
<!-- JDBC Driver MySQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<!-- Javax Persistence-->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<!-- Hibernate-->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.1.Final</version>
</dependency>
<!-- Servlet API-->
<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- Spring-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
Дополнительно:
Как я понимаю, проблема в несовпадении зависимостей. У версии Hibernate, что я использую, в классе SharedSessionContractImplementor нет метода connection(), который пытается вызвать Spring в методе doBegin() Transaction Manager'а. Я смотрел зависимости hibernate-core и нашел этот метод connection() в версии 5.6.9 Final, но это уж слишком старая версия, где используются старые методы hibernate. Сомневаюсь, что переходить на нее - хорошая идея.
Я не нашел ни одного топика на эту тему (именно с SharedSessionContractImplementor.connection()), что ставит меня в затруднительное положение.
Помогите пж, я не знаю, что делать.