Spring4整合Hibernate4详细示例

来源:互联网 发布:淘宝1分钱抢购在哪 编辑:程序博客网 时间:2024/05/17 08:56

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):

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

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

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

public class Book {   private int id;private String bookName;private String isbn;private float price;private int stock;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public String getIsbn() {return isbn;}public void setIsbn(String isbn) {this.isbn = isbn;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}public int getStock() {return stock;}public void setStock(int stock) {this.stock = stock;}}
public class Account {   private int id;private String username;private float balance;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public float getBalance() {return balance;}public void setBalance(float balance) {this.balance = balance;}}
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!-- Generated 2015-11-15 21:48:02 by Hibernate Tools 3.4.0.CR1 --><hibernate-mapping>    <class name="com.elgin.spring.hibernate.entity.Book" table="SH_BOOK">        <id name="id" type="int">            <column name="ID" />            <generator class="native" />        </id>                <property name="bookName" type="java.lang.String">            <column name="BOOKNAME" />        </property>                <property name="isbn" type="java.lang.String">            <column name="ISBN" />        </property>                <property name="price" type="float">            <column name="PRICE" />        </property>                <property name="stock" type="int">            <column name="STOCK" />        </property>            </class></hibernate-mapping>
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!-- Generated 2015-11-15 21:48:02 by Hibernate Tools 3.4.0.CR1 --><hibernate-mapping>    <class name="com.elgin.spring.hibernate.entity.Account" table="SH_ACCOUNT">        <id name="id" type="int">            <column name="ID" />            <generator class="native" />        </id>                <property name="username" type="java.lang.String">            <column name="USERNAME" />        </property>                <property name="balance" type="float">            <column name="BALANCE" />        </property>            </class></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 配置内容:          

<?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:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">      <!-- 配置注解自动扫描的包 -->   <context:component-scan base-package="com.elgin.spring.hibernate"></context:component-scan>         <!-- 配置数据源 -->   <!-- 导入资源文件 -->   <context:property-placeholder location="classpath:db.properties"/>      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">       <property name="user" value="${jdbc.user}"></property>       <property name="password" value="${jdbc.password}"></property>       <property name="driverClass" value="${jdbc.driverClass}"></property>       <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>              <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>       <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>   </bean>      <!-- 配置Hibernate的SessionFactory,通过spring提供的 LocalSessionFactoryBean配置-->   <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">       <!-- 配置依赖的数据源属性 -->       <property name="dataSource" ref="dataSource"></property>       <!-- hibernate 配置文件的路径 -->       <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>       <!-- 配置hibernate映射文件的路径,可以使用通配符 -->       <property name="mappingLocations" value="classpath:com/elgin/spring/hibernate/entity/*.hbm.xml"></property>   </bean>      <!-- 配置 Spring 的声明式事物 -->   <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">       <property name="sessionFactory" ref="sessionFactory"></property>   </bean>      <!-- 配置事物属性 ,需要事物管理器-->   <tx:advice id="txAdvice" transaction-manager="transactionManager">       <tx:attributes>          <tx:method name="get*" read-only="true"/>          <tx:method name="purchase" propagation="REQUIRES_NEW"/>          <tx:method name="*"/>       </tx:attributes>   </tx:advice>      <!-- 配置事物切点,并把事物属性和切点关联起来 -->   <aop:config>      <aop:pointcut expression="execution(* com.elgin.spring.hibernate.service.*.*(..))" id="txPointcut"/>      <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>   </aop:config>   </beans>
依赖的数据库配置文件db.properties:

jdbc.user=rootjdbc.password=root123jdbc.driverClass=com.mysql.jdbc.Driverjdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring_hibernatejdbc.initPoolSize=5jdbc.maxPoolSize=10
至此,Spring的配置、Hibernate的配置、以及二者整合的相关配置都配置完毕。下面通过代码测试。

3.整合测试:

工程目录:


新建上述各个目录:

1. 在dao下面新建接口:

public interface BookShopDao {    /** * 根据书号获取书的单价 * @param isbn * @return */public float  findPriceByIsbn(String isbn);/** * 更新书的库存,使书号对应的书本减少n本 * @param isbn * @param n */public void updateBookStock(String isbn,int n);/** * 更新账户余额,使当前账户金额减少 price*n * @param username * @param price * @param n * @throws BalanceNotEnough  */public void updateAccount(String username,float price,int n);}
对应的在impl下完成上述接口的实现类(注解@Repository,用来标注持久层,同时表示此组件交给spring的IOC容器管理)

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

<!-- 配置注解自动扫描的包 -->   <context:component-scan base-package="com.elgin.spring.hibernate"/>

import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;import com.elgin.spring.hibernate.dao.BookShopDao;import com.elgin.spring.hibernate.exception.BalanceNotEnough;import com.elgin.spring.hibernate.exception.BookStockNotEnoughException;@Repositorypublic class BookShopDaoImpl implements BookShopDao {    @Autowiredprivate SessionFactory sessionfactory;/** * 获取与当前线程绑定的session * @return */private Session getSession(){return sessionfactory.getCurrentSession();}@Overridepublic float findPriceByIsbn(String isbn) {String hql="select b.price from Book b where b.isbn=?";float price=(float) getSession().createQuery(hql).setString(0, isbn).uniqueResult();return price;}@Overridepublic void updateBookStock(String isbn, int n) {//验证书的库存是否充足String hq="Select b.stock from Book b where b.isbn=?";int stock=(int) getSession().createQuery(hq).setString(0, isbn).uniqueResult();if(stock < n){ throw new BookStockNotEnoughException("库存不足");}String hql="update Book b set b.stock=b.stock-? where b.isbn=?";Query query=getSession().createQuery(hql).setInteger(0, n).setString(1, isbn);query.executeUpdate();}@Overridepublic void updateAccount(String username, float price, int n) {//验证余额是否足够String hql="select a.balance from Account a where a.username=?";float balance=(float) getSession().createQuery(hql).setString(0, username).uniqueResult();        if(balance < n*price){        throw new BalanceNotEnough("余额不足");        }        String hql1="update Account a set a.balance=a.balance-? where a.username=?";        getSession().createQuery(hql1).setFloat(0, n*price).setString(1, username).executeUpdate();}}
实现类中用到的2个异常类:

public class BalanceNotEnough extends RuntimeException {/** *  */private static final long serialVersionUID = 1L;public BalanceNotEnough(String msg) {super(msg);}}
public class BookStockNotEnoughException extends RuntimeException {/** *  */private static final long serialVersionUID = 1L;    public BookStockNotEnoughException(String msg) {super(msg);}}
在service包下新建下面的接口:

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

@Servicepublic class BookShopSeviceImpl implements BookShopService {@Autowiredprivate BookShopDao bookShopDao;/** * Spring Hibernate的事物流程 * 1、方法开始之前 * ①. 获取session * ②. 把Session与当前线程绑定,这样就可以使用sessionFactory的getCurrentSession()方法来获取session了 * ③. 开启事务 *  * 2、若方法正常结束,未出现异常,则 * ①.提交事物 * ②.把session与当前线程解除绑定 * ③.关闭session *  * 3、若方法执行出现异常,则 * ①.回滚事务 * ②.把session与当前线程解除绑定 * ③.关闭session */@Overridepublic void purchase(String username, String isbn, int n) {float price=bookShopDao.findPriceByIsbn(isbn);bookShopDao.updateBookStock(isbn, n);bookShopDao.updateAccount(username, price, n);}}
编写单元测试类:

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

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringHibernateTest {    @Autowired private BookShopService bookShopService;  @Test public void testPurchaseBook(){ bookShopService.purchase("aaa", "java-1122", 2); }}
首先,注释掉测试方法中额外的代码,启动单元测试,让Hibernate生成用到的数据表:SH_BOOK 与SH_ACCOUNT

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


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

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

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

查看数据库发现:

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

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

本次整合测试代码:

本次整合测试代码

 



4 0
原创粉丝点击