Spring4整合Hibernate4详细示例

来源:互联网 发布:网上免费打电话软件 编辑:程序博客网 时间:2024/06/07 05:59

原文:http://blog.csdn.net/kris234seth/article/details/49872867


1. Spring整合Hibernate,主要是解决什么问题?

       a、让Spring提供的IOC容器来管理Hibernate的SessionFactory

       b、让Hibernate使用Spring提供的声明式事物

2. 整合步骤:

        新建一个Java工程,并新建用来保存依赖jar包的lib目录

      ①.  加入Hibernate支持:

           1. 加入Hibernate的required的jar包:

     antlr-2.7.7.jar
    dom4j-1.6.1.jar
    hibernate-commons-annotations-4.0.2.Final.jar
    hibernate-core-4.2.5.Final.jar
    hibernate-jpa-2.0-api-1.0.1.Final.jar
    javassist-3.15.0-GA.jar
    jboss-logging-3.1.0.GA.jar
    jboss-transaction-api_1.1_spec-1.0.1.Final.jar

2.加入MySQL与C3p0连接池支持:

    c3p0-0.9.2.1.jar
    mchange-commons-java-0.2.3.4.jar
    mysql-connector-java-5.1.7-bin.jar

注意:jar包加入之后,需要全部选中,右键-》BuildPath,将其导入

3.添加Hibernate的配置文件(hibernate.cfg.xml):

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE hibernate-configuration PUBLIC  
  3.         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
  4.         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">  
  5. <hibernate-configuration>  
  6.     <session-factory>  
  7.       <!-- 配置hibernate基本信息 -->  
  8.       <!-- 1.数据源配置在IOC容器中,此处不需要额外配置 -->  
  9.       <!-- 2.关联的.hbm.xml文件也在IOC容器配置SessionFactory时配置 -->  
  10.       <!-- 3.此处配置hibernate的基本信息:数据库方言、SQL显示及格式化,及生成数据表的策略,二级缓存等 -->  
  11.       <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>  
  12.         
  13.       <property name="hibernate.show_sql">true</property>  
  14.       <property name="hibernate.format_sql">true</property>  
  15.         
  16.       <property name="hibernate.hbm2ddl.auto">update</property>  
  17.         
  18.     </session-factory>  
  19. </hibernate-configuration>  

4. 创建测试使用的持久化类以及生成Hibernate的映射文件

 本例所用到的持久化类以其映射文件如下:

[java] view plain copy
 print?
  1. public class Book {  
  2.      
  3.     private int id;  
  4.     private String bookName;  
  5.     private String isbn;  
  6.     private float price;  
  7.     private int stock;  
  8.   
  9.     public int getId() {  
  10.         return id;  
  11.     }  
  12.   
  13.     public void setId(int id) {  
  14.         this.id = id;  
  15.     }  
  16.   
  17.     public String getBookName() {  
  18.         return bookName;  
  19.     }  
  20.   
  21.     public void setBookName(String bookName) {  
  22.         this.bookName = bookName;  
  23.     }  
  24.   
  25.     public String getIsbn() {  
  26.         return isbn;  
  27.     }  
  28.   
  29.     public void setIsbn(String isbn) {  
  30.         this.isbn = isbn;  
  31.     }  
  32.   
  33.     public float getPrice() {  
  34.         return price;  
  35.     }  
  36.   
  37.     public void setPrice(float price) {  
  38.         this.price = price;  
  39.     }  
  40.   
  41.     public int getStock() {  
  42.         return stock;  
  43.     }  
  44.   
  45.     public void setStock(int stock) {  
  46.         this.stock = stock;  
  47.     }  
  48.       
  49. }  
[java] view plain copy
 print?
  1. public class Account {  
  2.      
  3.     private int id;  
  4.     private String username;  
  5.     private float balance;  
  6.       
  7.     public int getId() {  
  8.         return id;  
  9.     }  
  10.   
  11.     public void setId(int id) {  
  12.         this.id = id;  
  13.     }  
  14.   
  15.     public String getUsername() {  
  16.         return username;  
  17.     }  
  18.   
  19.     public void setUsername(String username) {  
  20.         this.username = username;  
  21.     }  
  22.   
  23.     public float getBalance() {  
  24.         return balance;  
  25.     }  
  26.   
  27.     public void setBalance(float balance) {  
  28.         this.balance = balance;  
  29.     }  
  30.           
  31. }  
[html] view plain copy
 print?
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  4. <!-- Generated 2015-11-15 21:48:02 by Hibernate Tools 3.4.0.CR1 -->  
  5. <hibernate-mapping>  
  6.     <class name="com.elgin.spring.hibernate.entity.Book" table="SH_BOOK">  
  7.         <id name="id" type="int">  
  8.             <column name="ID" />  
  9.             <generator class="native" />  
  10.         </id>  
  11.           
  12.         <property name="bookName" type="java.lang.String">  
  13.             <column name="BOOKNAME" />  
  14.         </property>  
  15.           
  16.         <property name="isbn" type="java.lang.String">  
  17.             <column name="ISBN" />  
  18.         </property>  
  19.           
  20.         <property name="price" type="float">  
  21.             <column name="PRICE" />  
  22.         </property>  
  23.           
  24.         <property name="stock" type="int">  
  25.             <column name="STOCK" />  
  26.         </property>  
  27.           
  28.     </class>  
  29. </hibernate-mapping>  
[html] view plain copy
 print?
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  4. <!-- Generated 2015-11-15 21:48:02 by Hibernate Tools 3.4.0.CR1 -->  
  5. <hibernate-mapping>  
  6.     <class name="com.elgin.spring.hibernate.entity.Account" table="SH_ACCOUNT">  
  7.         <id name="id" type="int">  
  8.             <column name="ID" />  
  9.             <generator class="native" />  
  10.         </id>  
  11.           
  12.         <property name="username" type="java.lang.String">  
  13.             <column name="USERNAME" />  
  14.         </property>  
  15.           
  16.         <property name="balance" type="float">  
  17.             <column name="BALANCE" />  
  18.         </property>  
  19.           
  20.     </class>  
  21. </hibernate-mapping>  

      ②. 加入Spring支持:               

       1. 加入Spring的required的jar包:

               com.springsource.net.sf.cglib-2.2.0.jar
                com.springsource.org.aopalliance-1.0.0.jar
              com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
             commons-logging-1.1.3.jar
             spring-aop-4.1.0.RELEASE.jar
             spring-aspects-4.1.0.RELEASE.jar
             spring-beans-4.1.0.RELEASE.jar
             spring-context-4.1.0.RELEASE.jar
            spring-core-4.1.0.RELEASE.jar
            spring-expression-4.1.0.RELEASE.jar
            spring-jdbc-4.1.0.RELEASE.jar
            spring-orm-4.1.0.RELEASE.jar
            spring-test-4.1.0.RELEASE.jar
            spring-tx-4.1.0.RELEASE.jar
            spring-web-4.1.0.RELEASE.jar
           spring-webmvc-4.1.0.RELEASE.jar

          同样需要BuildPath!

     2.加入Spring的配置文件:applicationContext.xml

            applicationContext.xml 配置内容:          

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:context="http://www.springframework.org/schema/context"  
  5.     xmlns:tx="http://www.springframework.org/schema/tx"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd  
  8.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  9.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd  
  10.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">  
  11.      
  12.    <!-- 配置注解自动扫描的包 -->  
  13.    <context:component-scan base-package="com.elgin.spring.hibernate"></context:component-scan>  
  14.      
  15.      
  16.    <!-- 配置数据源 -->  
  17.    <!-- 导入资源文件 -->  
  18.    <context:property-placeholder location="classpath:db.properties"/>  
  19.      
  20.    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  21.        <property name="user" value="${jdbc.user}"></property>  
  22.        <property name="password" value="${jdbc.password}"></property>  
  23.        <property name="driverClass" value="${jdbc.driverClass}"></property>  
  24.        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>  
  25.          
  26.        <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>  
  27.        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>  
  28.    </bean>  
  29.      
  30.    <!-- 配置Hibernate的SessionFactory,通过spring提供的 LocalSessionFactoryBean配置-->  
  31.    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
  32.        <!-- 配置依赖的数据源属性 -->  
  33.        <property name="dataSource" ref="dataSource"></property>  
  34.        <!-- hibernate 配置文件的路径 -->  
  35.        <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>  
  36.        <!-- 配置hibernate映射文件的路径,可以使用通配符 -->  
  37.        <property name="mappingLocations" value="classpath:com/elgin/spring/hibernate/entity/*.hbm.xml"></property>  
  38.    </bean>  
  39.      
  40.    <!-- 配置 Spring 的声明式事物 -->  
  41.    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">  
  42.        <property name="sessionFactory" ref="sessionFactory"></property>  
  43.    </bean>  
  44.      
  45.    <!-- 配置事物属性 ,需要事物管理器-->  
  46.    <tx:advice id="txAdvice" transaction-manager="transactionManager">  
  47.        <tx:attributes>  
  48.           <tx:method name="get*" read-only="true"/>  
  49.           <tx:method name="purchase" propagation="REQUIRES_NEW"/>  
  50.           <tx:method name="*"/>  
  51.        </tx:attributes>  
  52.    </tx:advice>  
  53.      
  54.    <!-- 配置事物切点,并把事物属性和切点关联起来 -->  
  55.    <aop:config>  
  56.       <aop:pointcut expression="execution(* com.elgin.spring.hibernate.service.*.*(..))" id="txPointcut"/>  
  57.       <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>  
  58.    </aop:config>  
  59.      
  60. </beans>  
依赖的数据库配置文件db.properties:

[html] view plain copy
 print?
  1. jdbc.user=root  
  2. jdbc.password=root123  
  3. jdbc.driverClass=com.mysql.jdbc.Driver  
  4. jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring_hibernate  
  5. jdbc.initPoolSize=5  
  6. jdbc.maxPoolSize=10  
至此,Spring的配置、Hibernate的配置、以及二者整合的相关配置都配置完毕。下面通过代码测试。

3.整合测试:

工程目录:


新建上述各个目录:

1. 在dao下面新建接口:

[java] view plain copy
 print?
  1. public interface BookShopDao {  
  2.       
  3.     /** 
  4.      * 根据书号获取书的单价 
  5.      * @param isbn 
  6.      * @return 
  7.      */  
  8.     public float  findPriceByIsbn(String isbn);  
  9.       
  10.     /** 
  11.      * 更新书的库存,使书号对应的书本减少n本 
  12.      * @param isbn 
  13.      * @param n 
  14.      */  
  15.     public void updateBookStock(String isbn,int n);  
  16.       
  17.     /** 
  18.      * 更新账户余额,使当前账户金额减少 price*n 
  19.      * @param username 
  20.      * @param price 
  21.      * @param n 
  22.      * @throws BalanceNotEnough  
  23.      */  
  24.     public void updateAccount(String username,float price,int n);  
  25. }  
对应的在impl下完成上述接口的实现类(注解@Repository,用来标注持久层,同时表示此组件交给spring的IOC容器管理)

在使用spring的相关注解时,需要在spring的配置文件中开启注解自动扫描:

[html] view plain copy
 print?
  1. <!-- 配置注解自动扫描的包 -->  
  2.    <context:component-scan base-package="com.elgin.spring.hibernate"/>  

[java] view plain copy
 print?
  1. import org.hibernate.Query;  
  2. import org.hibernate.Session;  
  3. import org.hibernate.SessionFactory;  
  4. import org.springframework.beans.factory.annotation.Autowired;  
  5. import org.springframework.stereotype.Repository;  
  6.   
  7. import com.elgin.spring.hibernate.dao.BookShopDao;  
  8. import com.elgin.spring.hibernate.exception.BalanceNotEnough;  
  9. import com.elgin.spring.hibernate.exception.BookStockNotEnoughException;  
  10.   
  11. @Repository  
  12. public class BookShopDaoImpl implements BookShopDao {  
  13.       
  14.     @Autowired  
  15.     private SessionFactory sessionfactory;  
  16.       
  17.     /** 
  18.      * 获取与当前线程绑定的session 
  19.      * @return 
  20.      */  
  21.     private Session getSession(){  
  22.         return sessionfactory.getCurrentSession();    
  23.     }  
  24.       
  25.     @Override  
  26.     public float findPriceByIsbn(String isbn) {  
  27.         String hql="select b.price from Book b where b.isbn=?";  
  28.         float price=(float) getSession().createQuery(hql).setString(0, isbn).uniqueResult();  
  29.         return price;  
  30.     }  
  31.   
  32.     @Override  
  33.     public void updateBookStock(String isbn, int n) {  
  34.         //验证书的库存是否充足  
  35.         String hq="Select b.stock from Book b where b.isbn=?";  
  36.         int stock=(int) getSession().createQuery(hq).setString(0, isbn).uniqueResult();  
  37.         if(stock < n){  
  38.              throw new BookStockNotEnoughException("库存不足");  
  39.         }     
  40.         String hql="update Book b set b.stock=b.stock-? where b.isbn=?";  
  41.         Query query=getSession().createQuery(hql).setInteger(0, n).setString(1, isbn);  
  42.         query.executeUpdate();        
  43.     }  
  44.   
  45.     @Override  
  46.     public void updateAccount(String username, float price, int n) {  
  47.         //验证余额是否足够  
  48.         String hql="select a.balance from Account a where a.username=?";  
  49.         float balance=(float) getSession().createQuery(hql).setString(0, username).uniqueResult();  
  50.         if(balance < n*price){  
  51.             throw new BalanceNotEnough("余额不足");  
  52.         }  
  53.         String hql1="update Account a set a.balance=a.balance-? where a.username=?";  
  54.         getSession().createQuery(hql1).setFloat(0, n*price).setString(1, username).executeUpdate();  
  55.     }  
  56.   
  57. }  
实现类中用到的2个异常类:

[java] view plain copy
 print?
  1. public class BalanceNotEnough extends RuntimeException {  
  2.   
  3.     /** 
  4.      *  
  5.      */  
  6.     private static final long serialVersionUID = 1L;  
  7.       
  8.     public BalanceNotEnough(String msg) {  
  9.         super(msg);  
  10.     }  
  11.   
  12. }  
[java] view plain copy
 print?
  1. public class BookStockNotEnoughException extends RuntimeException {  
  2.   
  3.     /** 
  4.      *  
  5.      */  
  6.     private static final long serialVersionUID = 1L;  
  7.       
  8.     public BookStockNotEnoughException(String msg) {  
  9.         super(msg);  
  10.     }  
  11. }  
在service包下新建下面的接口:

[java] view plain copy
 print?
  1. public interface BookShopService {  
  2.       
  3.     /** 用户购买n本书 
  4.      * @param username 
  5.      * @param isbn 
  6.      * @param n 
  7.      */  
  8.     public void purchase(String username,String isbn,int n);  
  9. }  
在service.impl下完成它的实现类(@Service 用来标注service层,表示此组件为service并交给Spring的IOC容器管理;@Autowired 自动注入 ,表示此对象由IOC容器负责初始化并注入):

[java] view plain copy
 print?
  1. @Service  
  2. public class BookShopSeviceImpl implements BookShopService {  
  3.   
  4.     @Autowired  
  5.     private BookShopDao bookShopDao;  
  6.       
  7.     /** 
  8.      * Spring Hibernate的事物流程 
  9.      * 1、方法开始之前 
  10.      * ①. 获取session 
  11.      * ②. 把Session与当前线程绑定,这样就可以使用sessionFactory的getCurrentSession()方法来获取session了 
  12.      * ③. 开启事务 
  13.      *  
  14.      * 2、若方法正常结束,未出现异常,则 
  15.      * ①.提交事物 
  16.      * ②.把session与当前线程解除绑定 
  17.      * ③.关闭session 
  18.      *  
  19.      * 3、若方法执行出现异常,则 
  20.      * ①.回滚事务 
  21.      * ②.把session与当前线程解除绑定 
  22.      * ③.关闭session 
  23.      */  
  24.     @Override  
  25.     public void purchase(String username, String isbn, int n) {  
  26.         float price=bookShopDao.findPriceByIsbn(isbn);  
  27.         bookShopDao.updateBookStock(isbn, n);  
  28.         bookShopDao.updateAccount(username, price, n);  
  29.     }  
  30.   
  31. }  
编写单元测试类:

若想使用如下配置进行单元测试,必须要加入spring单元测试的jar包:spring-test-4.1.0.RELEASE.jar

[java] view plain copy
 print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration("classpath:applicationContext.xml")  
  3. public class SpringHibernateTest {  
  4.      
  5.       
  6.      @Autowired  
  7.      private BookShopService bookShopService;  
  8.        
  9.      @Test  
  10.      public void testPurchaseBook(){  
  11.          bookShopService.purchase("aaa""java-1122"2);  
  12.      }  
  13.   
  14. }  
首先,注释掉测试方法中额外的代码,启动单元测试,让Hibernate生成用到的数据表:SH_BOOK 与SH_ACCOUNT

让后在2个表中各加入测试所需要的数据如下图:


运行上述单元测试方法,执行成功,查看数据库,book的库存STOCK变为43,account中的账户余额变为130.

再次运行,程序抛出异常:

com.elgin.spring.hibernate.exception.BalanceNotEnough: 余额不足

查看数据库发现:

book的库存STOCK仍旧为43,account中的账户余额仍旧为130.

这就是spring的事物的作用,程序出现异常,回滚事务,关闭session。

本次整合测试代码:

本次整合测试代码