stworzenie transactionManager i dataSource

0

Próbuję stworzyć aplikację z wykorzystaniem Springa i Hibernate. Sugeruję się m.in. tym tutorialem http://www.mkyong.com/spring-security/spring-security-hibernate-annotation-example/
Jednak ja korzystam z nowszej wersji Hibernate'a i musiałem dokonać paru zmian w klasie AppConfig. Wygląda ona u mnie tak:

@EnableWebMvc
@Configuration
@ComponentScan({ "com.myapp*" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
public class AppConfig {

	@Bean
	public InternalResourceViewResolver viewResolver()	{
		
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setPrefix("/WEB-INF/pages/");
		viewResolver.setSuffix(".jsp");
		
		return viewResolver;
	}

	@Bean(name = "sessionFactory")
	public SessionFactory sessionFactory(){
		org.hibernate.cfg.Configuration configuration = getHibernateConfiguration();
		
		StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder();
		serviceRegistryBuilder.applySettings(configuration.getProperties());
		StandardServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
		
		SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		
		return sessionFactory;
	}
	
	@Bean(name = "hibernateCfg")
	public org.hibernate.cfg.Configuration getHibernateConfiguration(){
		
		org.hibernate.cfg.Configuration conf = new  org.hibernate.cfg.Configuration();
		conf.addAnnotatedClass(User.class);
		conf.addAnnotatedClass(UserRole.class);
		conf.setProperty("hibernate.format_sql", "true");
		conf.setProperty("hibernate.show_sql", "true");
		conf.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
		conf.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
		conf.setProperty("hibernate.connection.url", "jdbc:mysql://127.0.0.1:3306/mydb");
		conf.setProperty("hibernate.connection.username", "root");
		conf.setProperty("hibernate.hbm2ddl.auto", "update");
		
		return conf;
	}
	
	@Bean(name = "dataSource")
	public BasicDataSource dataSource() {
 
		BasicDataSource ds = new BasicDataSource();
	        ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://127.0.0.1:3306/mydb");
		ds.setUsername("root");
		return ds;
	}
	
    @Bean
    public HibernateTransactionManager transactionManager()
    {
        return new HibernateTransactionManager(sessionFactory());
    }
	
}

Przy uruchamianiu aplikacji dostaję wyjątek

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class com.myapp.config.AppConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.orm.hibernate4.HibernateTransactionManager com.myapp.config.AppConfig.transactionManager()] threw exception; nested exception is org.hibernate.service.UnknownUnwrapTypeException: Cannot unwrap to requested type [javax.sql.DataSource]
  1. Czy ktoś spotkał się z takim problemem? Udało mi się znaleźć informację, że taki problem występował w Springu 3.
  2. Czy poprawnie dostosowałem tę klasę do nowszej wersji Hibernate?
  3. Czy można zaimplementować DAO bez HibernateTransactionManagera?

Używam
Hibernate 4.3.6.Final
Spring 4.0.6.RELEASE

0

Pierwsze co widzę to to, ze tworzysz data source a potem wcale go nie przekazujesz do session factory. Jak to tak?
I czemu goły Hibernate a nie JPA?

0
Shalom napisał(a):

I czemu goły Hibernate a nie JPA?

Mógłbyś wyjaśnić co w tym złego? Rozumiem, że chodzi o vendor lock-in, ale na 99,9% nie będzie potrzeby zmiany :)

0

Vendor lock to jedno, ale zauważ że JPA jest po prostu popularne bo różne firmy używają różnych vendorów. Ucząc się JPA niejako uczysz się jak stosować dowolnego, więc jesteś dużo bardziej elastyczny :)

0

Problem rozwiązałem w ten sposób.

	@Bean(name = "sessionFactory")
	public SessionFactory sessionFactory(){
		final ServiceRegistry serviceRegistry =  new StandardServiceRegistryBuilder()
		.applySettings( getHibernateProperties() )
		.build();
		
		LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
		builder.scanPackages("com.myapp.*");
		return builder.buildSessionFactory(serviceRegistry);
	}

	private Properties getHibernateProperties() {
		Properties prop = new Properties();
		prop.put("hibernate.format_sql", "true");
		prop.put("hibernate.show_sql", "true");
		prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
		return prop;
	}
Shalom napisał(a):

Pierwsze co widzę to to, ze tworzysz data source a potem wcale go nie przekazujesz do session factory. Jak to tak?
I czemu goły Hibernate a nie JPA?

Dopiero raczkuję w Javie i szczerze mówiąc jestem przytłoczony zróżnicowaniem bibliotek. Przyjrzę się JPA, dzięki za sugestię.

0

Nie pojmuję tego. Robiłem jeszcze zmiany w projekcie, ale przywróciłem wszystko do stanu kiedy to działało i znów dostaję
org.hibernate.service.UnknownUnwrapTypeException: Cannot unwrap to requested type [javax.sql.DataSource]

Czy sposób w jaki to rozwiązałem na pewno był prawidłowy?

0

No ale jak to teraz wygląda? Bo to co wstawiłeś ostatnio powinno być ok. Masz wywalić z konfiguracji session factory wszystko dotyczące bazy danych i przekazać tam datasource.

0

Wygląda to tak

@EnableWebMvc
@Configuration
@ComponentScan({ "com.myapp.*" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
public class AppConfig {

	@Bean
	public InternalResourceViewResolver viewResolver()	{

		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setPrefix("/WEB-INF/pages/");
		viewResolver.setSuffix(".jsp");

		return viewResolver;
	}

	@Bean(name = "sessionFactory")
	public SessionFactory sessionFactory(){
		final ServiceRegistry serviceRegistry =  new StandardServiceRegistryBuilder()
		.applySettings( getHibernateProperties() )
		.build();
		
		LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
		builder.scanPackages("com.myapp.*");
		
		return builder.buildSessionFactory(serviceRegistry);
	}

	private Properties getHibernateProperties() {
		Properties prop = new Properties();
		prop.put("hibernate.format_sql", "true");
		prop.put("hibernate.show_sql", "true");
		prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
		return prop;
	}

	@Bean(name = "dataSource")
	public BasicDataSource dataSource() {

		BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/mydb");
		ds.setUsername("root");
		return ds;
	}

	@Bean
	public HibernateTransactionManager transactionManager()
	{
		return new HibernateTransactionManager(sessionFactory());
	}

}
0

Wygląda na oko dobrze, ale nie jestem ani wielkim fanem ani znawcą konfiguracji springa w ten sposób. Moim zdaniem konfiguracja głównych beanów lepiej wygląda w XMLu (a reszta przez adnotacje w kodzie).

0

Ja mam contex do obsługi bazy danych napisany w taki sposób i moim zdaniem wygląda to lepiej niż konfiguracja za pomocą Javy:

context-store.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/tx
               http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
               http://www.springframework.org/schema/data/jpa
               http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <jpa:repositories base-package="com.webtradingplatform.repository"/>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${db.driverClassName}"/>
        <property name="url" value="${db.databaseurl}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="persistenceUnitName" value="JpaPersistenceUnit"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <tx:annotation-driven/>

</beans>

P.S. Korzystam z JPA oraz Spring Data

0

Bez konfiguracji JPA w pliku persistence.xml wygląda to tak:

context-store.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/tx
               http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
               http://www.springframework.org/schema/data/jpa
               http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
               http://www.springframework.org/schema/util 
               http://www.springframework.org/schema/util/spring-util.xsd">

    <jpa:repositories base-package="com.webtradingplatform.repository"/>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${db.driverClassName}"/>
        <property name="url" value="${db.databaseurl}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="packagesToScan" value="com.webtradingplatform.entity"/>
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter" ref="hibernateVendor"/>
        <property name="jpaPropertyMap" ref="jpaPropertyMap"/>
    </bean>
    
    <util:map id="jpaPropertyMap">
        <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgresPlusDialect"/>
        <entry key="hibernate.hbm2ddl.auto" value="update"/>
        <entry key="hibernate.show_sql" value="true" />
        <entry key="hibernate.jdbc.batch_size" value="0"/>
    </util:map>

    <bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="false"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <tx:annotation-driven/>

</beans>

1 użytkowników online, w tym zalogowanych: 0, gości: 1