Spring整合Hibernate

  • 整合什么?

    1. 让Spring的IOC容器生成Hibernate的SessionFactory。

    2. 让Hibernate使用上Spring的事务声明。

  • 整合步骤

    1. 加入Hibernate。

              (1) 导入Hibernate开发包。

              (2) 编写Hibernate配置文件:hibernate.cfg.xml。我们在文件只需要配置方言、SQL显示及其格式化、生成数据库表的策略以及二级缓存的

         的相关信息。对于数据源信息我们配置到Spring的配置文件中,让Spring的IOC容器来管理数据源,关联的映射文件.hbm.xml也配置在Spring

         的配置文件中。

         2. 加入Spring

               (1) 导入开发包。

               (2) 编写Spring的配置文件。配置数据源、配置Hibernate的SessionFactory、配置Spring的事务声明。

  • 代码展示

模拟情景:用户去买书(规定每次只能买一本书),用户的账户余额会减少,同时书本的库存也会减少。

1. 实体类

package hibernate.entity;

/**
 * 账户
 * @author SHI
 */
public class Account {
    private Integer id;
    private String username;// 账户名称
    private int balance;//账户余额

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account [id=" + id + ", username=" + username + ", balance="
                + balance + "]";
    }
}

 

package hibernate.entity;
/**
 * 书本
 * @author SHI
 */
public class Book {
    private Integer id;
    private String bookName;//书本名称
    private String bookId;//书本编号
    private int price;//书本价格
    private int stock;//书本库存

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookId() {
        return bookId;
    }

    public void setBookId(String bookId) {
        this.bookId = bookId;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getStock() {
        return stock;
    }

    public void setStock(int stock) {
        this.stock = stock;
    }

    @Override
    public String toString() {
        return "Book [id=" + id + ", bookName=" + bookName + ", bookId=" + bookId
                + ", price=" + price + ", stock=" + stock + "]";
    }
}

2. DAO层代码

package hibernate.dao;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class BookDao {
    
    @Autowired
    private SessionFactory sessionFactory;
    /*
     * 不推荐使用 HibernateTemplate 和 HibernateDaoSupport,因为
     * 这样会导致DAO和Spring API进行耦合,可移植性差。
     * private HibernateTemplate hibernateTemplate;
     * private HibernateDaoSupport daoSupport;
     */
    
    //获取和当前线程绑定的Session
    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }    
    
    /**
     * 根据书本编号查询书本的价格
     * @param bookId
     * @return
     */
    public double bookPriceById(String bookId) {
        String hql = "select b.price from Book b where b.bookId = ?";
        Query query = this.getSession().createQuery(hql).setString(0, bookId);
        return (Integer) query.uniqueResult();
    }
    /**
     * 根据书本编号更新书本的库存数量
     * @param bookId
     */
    public void updateBookStock(String bookId)  {
        //1.检查库存数量
        String _hql = "select b.stock from Book b where b.bookId = ?";
        int result = (Integer) getSession().createQuery(_hql).setString(0, bookId).uniqueResult();
        if(result <= 0) {
            throw new RuntimeException("库存不足...");
        }
        String hql = "update Book b set b.stock = b.stock - 1 where b.bookId = ?";
        Query query = getSession().createQuery(hql).setString(0, bookId);
        query.executeUpdate();
    }
    /**
     * 更新账户余额
     * @param username
     * @param price
     */
    public void updateUserAccount(String username, double price)  {
        //1.检查账户余额
        String _hql = "select a.balance from Account a where a.username = ?";
        int balance = (Integer) getSession().createQuery(_hql).setString(0, username).uniqueResult();
        if(balance <= price) {
            throw new RuntimeException("余额不足...");
        }
        String hql = "update Account a set a.balance = a.balance - ? where a.username = ?";
        this.getSession().createQuery(hql).setDouble(0, price).setString(1, username).executeUpdate();
    }
}

 

3. 业务层代码

package hibernate.service;

import hibernate.dao.BookDao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {
    @Autowired
    private BookDao bookDao;
    
    /**
     * Spring整合Hibernate 事务的流程
     * 1. 在方法开始之前
     * ①. 获取 Session
     * ②. 把 Session 和当前线程绑定, 这样就可以在 Dao 中使用 SessionFactory 的
     * getCurrentSession() 方法来获取 Session 了
     * ③. 开启事务
     * 
     * 2. 若方法正常结束, 即没有出现异常, 则
     * ①. 提交事务
     * ②. 使和当前线程绑定的 Session 解除绑定
     * ③. 关闭 Session
     * 
     * 3. 若方法出现异常, 则:
     * ①. 回滚事务
     * ②. 使和当前线程绑定的 Session 解除绑定
     * ③. 关闭 Session
     */
    public void buyBook(String username,String bookId)  {
        //1.获取单价
        double price = bookDao.bookPriceById(bookId);
        //2.更新库存
        bookDao.updateBookStock(bookId);
        //3.更新余额
        bookDao.updateUserAccount(username, price);
    }
}

 

4. 配置文件

    (1) Hibernate的配置文件

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="hbm2ddl.auto">update</property>
    </session-factory>
</hibernate-configuration>

 

    (2) Spring配置文件

<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    
    <context:component-scan base-package="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:hibernate/hbm/*.hbm.xml"></property>
    </bean>
    
    <!-- 配置Spring事务管理
    1.配置事务管理器 -->
    <bean id="transactionManager" 
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <!-- 2.配置事务属性 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="buyBook"/>
        </tx:attributes>
    </tx:advice>    
    <!-- 3.配置事务切入点,以及把事务切入点和事务属性关联 -->
    <aop:config>
        <aop:pointcut expression="execution(* hibernate.service.*.*(..))" id="pointcut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

 

5. 测试代码。测试的时候可以手动的更改数据可表中的数据,让程序抛出异常,测试事务的使用。

 

package hibernate;

import hibernate.service.BookService;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringHibernateTest {
    private ApplicationContext ac;
    private BookService bookService; 
    
    {
        ac = new ClassPathXmlApplicationContext("bean.xml");
        bookService = ac.getBean(BookService.class);
    }
    
    @Test
    public void testBuyBook() {
        bookService.buyBook("Kate", "1");
    }
    
    @Test
    public void getDataSource() throws SQLException {
        DataSource dataSource = (DataSource) ac.getBean("dataSource");
        System.out.println(dataSource.getConnection());
    }
}
posted @ 2014-11-30 10:32  Love-Sky  阅读(223)  评论(0编辑  收藏  举报