Spring启动hibernate 5集成错误

Ama*_*Dev 1 java hibernate spring-boot

我正在尝试使用Java配置将spring Boot与Hibernate 5集成.我使用Hibernate已经有一段时间了.我得到了下面提到的例外.有人可以建议如何解决这个问题吗?

以下是我的java配置文件,后跟异常堆栈跟踪.

package com.example;

import com.example.dao.CustomerDao;
import com.example.model.Customer;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

@SpringBootApplication
@EnableTransactionManagement
public class SpringHibernateDemoApplication implements CommandLineRunner {

    public static void main(String[] args) {

        SpringApplication.run(SpringHibernateDemoApplication.class, args);
    }

    @Bean
    public DataSource dataSource() throws ClassNotFoundException {
        //SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        // dataSource.setDriverClass((Class<? extends Driver>)Class.forName("com.mysql.jdbc.Driver"));
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/customerDB");
        dataSource.setUsername("root");
        dataSource.setPassword("welcome");
        return  dataSource;
    }

    @Bean
    public LocalSessionFactoryBean  sessionFactory() throws ClassNotFoundException {
        Properties properties = new Properties();
        properties.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.hbm2ddl.auto","create");
       // properties.put("hibernate.connection.provider_class","org.hibernate.connection.DatasourceConnectionProvider");
        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setDataSource(dataSource());
        localSessionFactoryBean.setPackagesToScan("com.example.model");
        localSessionFactoryBean.setHibernateProperties(properties);
        /*SessionFactory sessionFactory = new LocalSessionFactoryBuilder(dataSource()).
                addAnnotatedClass(Customer.class).setProperties(properties).buildSessionFactory();*/
        return localSessionFactoryBean;
    }

    @Bean(name = "hibernateTemplate")
    public HibernateTemplate hibernateTemplate() throws ClassNotFoundException {

        return new HibernateTemplate(sessionFactory().getObject());
    }

    @Bean
    public CustomerDao customerDao() {
        return  new CustomerDao();
    }

    @Override
    public void run(String... args) throws Exception {
        Customer customer = new Customer();
        customer.setFistName("amar");
        customer.setLastName("dev");
        customer.setEmail("amar@gmail.com");
        customerDao().saveCustomer(customer);
    }
}
Run Code Online (Sandbox Code Playgroud)

例外.

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:790) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:777) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1191) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1180) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at com.example.SpringHibernateDemoApplication.main(SpringHibernateDemoApplication.java:23) [main/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_74]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_74]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_74]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_74]
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) [idea_rt.jar:na]
Caused by: java.lang.IllegalStateException: Already value [org.springframework.orm.jpa.EntityManagerHolder@10753c9] for key [org.hibernate.internal.SessionFactoryImpl@ba5d30] bound to thread [main]
    at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:190) ~[spring-tx-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:127) ~[spring-orm-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:454) ~[hibernate-core-5.2.0.Final.jar:5.2.0.Final]
    at org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:326) ~[spring-orm-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.orm.hibernate5.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:309) ~[spring-orm-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.orm.hibernate5.HibernateTemplate.save(HibernateTemplate.java:616) ~[spring-orm-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at com.example.dao.CustomerDao.saveCustomer(CustomerDao.java:11) ~[main/:na]
    at com.example.dao.CustomerDao$$FastClassBySpringCGLIB$$fb200467.invoke(<generated>) ~[main/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) ~[spring-aop-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) ~[spring-tx-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ~[spring-aop-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at com.example.dao.CustomerDao$$EnhancerBySpringCGLIB$$22cf791b.saveCustomer(<generated>) ~[main/:na]
    at com.example.SpringHibernateDemoApplication.run(SpringHibernateDemoApplication.java:71) [main/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:806) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
Run Code Online (Sandbox Code Playgroud)

M. *_*num 11

问题是你没有定义HibernateTransactionManager下一个Spring Boot检测到hibernate和JPA并自动配置它.这两种技术都试图启动事务而失败.而不是使用框架,Spring Boot已经为您自动配置a DataSourceEntityManagerFactory(JPA变体SessionFactory).

失踪 HibernateTransactionManager

如果你真的想使用普通的Hibernate添加一个事务管理器.

@Bean
public HibernateTransactionManager transactionManager(SessionFactory sf) {
    return new HibernateTransactionManager(sf);
}
Run Code Online (Sandbox Code Playgroud)

使用Spring Boot配置DataSource

但是,我会敦促您使用该框架.创建一个名为application.propertiesin 的文件src/main/resources并在其中放入以下属性.

spring.datasource.url=jdbc:mysql://localhost:3306/customerDB
spring.datasource.username=root
spring.datasource.password=welcome
Run Code Online (Sandbox Code Playgroud)

现在你可以删除它DataSource,你可以重写你的sessionFactory方法来获取DataSourceas方法参数.

@Bean
public LocalSessionFactoryBean  sessionFactory(DataSource ds) throws ClassNotFoundException {
    LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
    localSessionFactoryBean.setDataSource(dataSource());
    ... // Other settings here
    return localSessionFactoryBean;
}
Run Code Online (Sandbox Code Playgroud)

使用JPA而不是普通的Hibernate

但是,我建议删除所有内容并将以下内容添加到您的配置中(而不是这样做application.properties).

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.database-platform=org.hibernate.dialect.MySQL57InnoDBDialect
Run Code Online (Sandbox Code Playgroud)

现在SpringHibernateDemoApplication你可以删除除了你CustomerDao之外的所有内容(除非@Repository你注释了它也可以删除它).Spring Boot已经检测并启用了事务,因此您也可以删除@EnableTransactionManagement.

@SpringBootApplication
public class SpringHibernateDemoApplication {

    public static void main(String[] args) {

        SpringApplication.run(SpringHibernateDemoApplication.class, args);
    }

    @Bean
    public CustomerDao customerDao() {
        return  new CustomerDao();
    }

    @Bean
    public CommandLineRunner runner(CustomerDao dao) {
        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                Customer customer = new Customer();
                customer.setFistName("amar");
                customer.setLastName("dev");
                customer.setEmail("amar@gmail.com");
                dao.saveCustomer(customer);
            }            
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

你要做的唯一事情是使用一个替换使用HibernateTemplate(首先不推荐使用!)EntityManager.请参阅参考指南的JPA部分.

@Repository
public class CustomerDao {

    @PersistenceContext
    private EntityManager em;

    public void saveCustomer(Customer customer) {
        em.persist(customer);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用Spring Data JPA

但是,如果您想真正减少代码,我建议添加spring-boot-starter-data-jpa.这将添加Spring Data JPA,并允许您删除当前CustomerDao并简单地用接口替换它.(以下代码假定Customer具有类型的id Long.).

public interface CustomerDao extends JpaRepository<Customer, Long> {}
Run Code Online (Sandbox Code Playgroud)

现在更换saveCustomersaveCommandLineRunner.(我添加了COmmandLineRunner作为内部bean,以便能够CustomerDao作为参数注入到方法中).

@SpringBootApplication
public class SpringHibernateDemoApplication {

    public static void main(String[] args) {

        SpringApplication.run(SpringHibernateDemoApplication.class, args);
    }

    @Bean
    public CommandLineRunner runner(CustomerDao dao) {
        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                Customer customer = new Customer();
                customer.setFistName("amar");
                customer.setLastName("dev");
                customer.setEmail("amar@gmail.com");
                dao.save(customer);
            }            
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

我强烈建议阅读Spring Boot 参考指南,了解它是什么以及它做了什么.我还建议学习像JPA这样的新技术和接受的技术,以及像Spring Data JPA这样的Spring项目如何帮助你解决这些问题.