Spring整合Hibernate,花了很长时间研究,其中碰到的比较多问题。
使用的是Spring3.0+Hibernate4.1.6,Spring整合最新版本的Hibernate4.5,会抛些奇奇怪怪的异常。这个官网有说明。
先上代码。
spring的xml配置:springContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1/test" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value>com.my.entity</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQL5Dialect hibernate.hbm2ddl.auto=update hibernate.show_sql=true hibernate.format_sql=false hibernate.cache.use_second_level_cache=true hibernate.cache.use_query_cache=false hibernate.cache.provider_class=org.hibernate.cache.internal.NoCacheProvider hibernate.current_session_context_class= org.springframework.orm.hibernate4.SpringSessionContext </value> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <context:component-scan base-package="com.my" /> <tx:annotation-driven transaction-manager="txManager" /> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" read-only="true"/> <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="create*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="remove*" propagation="REQUIRED" rollback-for="Exception"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="allServiceMethods" expression="execution(* com.my.service.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="allServiceMethods"/> </aop:config> </beans>
逐一解释下这个XML,这是最关键的地方:
1、dataSource,这里所使用的是spring自带的org.springframework.jdbc.datasource.DriverManagerDataSource,但这个一般用于个人开发或非并发小项目是可以的,如果用于大型的项目,需要把它替换使用proxool。proxool与spring配置,可以网上搜索下。
2、sessionFactory,里头有个property值为packagesToScan,应该是hibernate所使用的annotation object(即POJO)。使用这个packagesToScan,会自动扫描代码,无需一个个写了。
3、txManager,这是transation管理bean,意思是把声明一个transation bean,以待注入。
4、<context:component-scan base-package="com.my" />,这句是spring使用annotation做注入,基于com.my的命名空间下的所有包和类扫描
5、<tx:annotation-driven transaction-manager="txManager" />,声明一个annotation的transation,让AOP使用。
6、txAdvice,声明一个spring AOP的advice,其意思是内容中定义的attributes对应的方法是否需要开启或禁用transation,以及rollback条件。
7、<aop:config/>是spring的AOP,将txAdvice切入到对应的pointcut中。
补充:
因为测试时使用的是MySql,在测试transation时,发现怎么也不能回滚。原来是MySql数据库要把表引擎修改为InnoDB类型才支持事务。之前使用的是绿色版的MySql,设置了很久也没设置成功,最后去官网下了个安装版的5.7版本,装上默就是InnoDB。-_-#
贴代码:
DAO:
package com.my.dao; import javax.annotation.Resource; import org.hibernate.SessionFactory; import org.springframework.stereotype.Repository; import com.my.entity.Account; @Repository public abstract class AccountDaoFactory { @Resource private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } /* * Fin account by id */ public abstract Integer findAccount(Integer accountID); /* * Add account */ public abstract Account add(String name); /* * Delete account */ public abstract boolean delete(long id); }
package com.my.dao.mysql; import org.hibernate.Query; import org.hibernate.Session; import org.springframework.stereotype.Repository; import com.my.entity.Account; @Repository(value = "accountDao") public class AccountDao extends com.my.dao.AccountDaoFactory { /* * Find account by account id */ @Override public Integer findAccount(Integer accountID) { return accountID; } @Override public Account add(String name) { Session session = super.getSessionFactory().getCurrentSession(); Account account = new Account(); account.setName(name); session.save(account); Query query = session.createQuery("FROM Account AS A ORDER BY A.id DESC"); query.setMaxResults(1); account = (Account) query.uniqueResult(); return account; } @Override public boolean delete(long id) { Session session = super.getSessionFactory().getCurrentSession(); Account account = (Account) session.get(Account.class, id); session.delete(account); return true; } }
Service:
package com.my.service; import javax.annotation.Resource; import com.my.dao.AccountDaoFactory; import com.my.entity.Account; public abstract class AccountServiceFactory { @Resource(name="accountDao") protected AccountDaoFactory accountDao; public AccountDaoFactory getAccountDAO() { return accountDao; } public void setAccountDAO(AccountDaoFactory accountDAO) { this.accountDao = accountDAO; } /* * Find account by id */ public abstract Integer findAccount(Integer accountID); /* * Add account */ public abstract Account add(String name); /* * Delete account */ public abstract boolean delete(long id); /* * Add and Delete account, transaction test. */ public abstract boolean addAndDelete(String name); }
package com.my.service.mysql; import org.springframework.stereotype.Service; import com.my.entity.Account; import com.my.service.AccountServiceFactory; @Service(value="accountService") public class AccountService extends AccountServiceFactory { @Override public Integer findAccount(Integer accountID) { return accountDao.findAccount(accountID); } @Override public Account add(String name) { return accountDao.add(name); } @Override public boolean delete(long id) { return accountDao.delete(id); } @Override public boolean addAndDelete(String name) { Account account = accountDao.add(name); boolean result = accountDao.delete(account.getId()); return result; } }
Controller:
package com.my.controller; import javax.annotation.Resource; import org.springframework.stereotype.Controller; import com.my.entity.Account; import com.my.service.AccountServiceFactory; @Controller public class SpringController { @Resource(name="accountService") private AccountServiceFactory accountService; public AccountServiceFactory getAccount() { return accountService; } public void setAccount(AccountServiceFactory account) { this.accountService = account; } public Integer findAccount(Integer accountID){ return accountService.findAccount(accountID); } public Account add(String name){ return accountService.add(name); } public boolean delete(long id){ return accountService.delete(id); } public boolean addAndDelete(String name){ return accountService.addAndDelete(name); } }
POJO entity:
package com.my.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "account") public class Account { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private long id; @Column(name = "name", length = 200) private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
JUnit测试:
package com.my.controller; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringControllerTest { private SpringController springController; private ApplicationContext context; @Before public void setUp() throws Exception { context = new ClassPathXmlApplicationContext("springContext.xml"); // Use class load springController = (SpringController)context.getBean(SpringController.class); } @Test public void testFindAccount() { String name = "Robin"; boolean result = springController.addAndDelete(name); assertTrue(result); } }
输出结果:
项目结构:
Spring所需要用到的Jar包:
Hibernate4.1.6所需要用到的Jar包: