Spring4---整合Hibernate

  1. spring整合Hibernate需要整合两个方面
    1. 由IOC容器来生成Hibernate的SessionFactory
    2. 让Hibernate使用上Spring的声明式事物
  • 整合步骤
  1. 先加入Hibernate
    • 加入Hibernate的jar包
    • 配置Hibernate的配置文件
    • 编写持久化类对应的*.hbm.xml文件
  2. 再加入Spring
    • 加入jar包
    • 加入Spring的配置文件
      • 配置数据源
      • 配置Hibernate的SessionFactory示例
      • 配置Spring声明式事务

hibernate.cfg.xml文件配置

  • 虽然在整合Spring的时候,这个文件可以不用设置,但是最好还是保留一个hibernat配置文件,有些配置写在这里里面更加合适
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>

    <!--数据库链接源由Spring4完成配置-->
    <!--Hibernate的映射文件 *.hbm.xml文件也由在配置SessionFactory时配置-->
    <!--配置Hibernate的基本操作-->
    <!--配置Sql方言-->
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
    <!--设置自动生成数据表策略-->
      <property name="hibernate.hbm2ddl.auto">update</property>
      <!--打印sql语句-->
      <property name="hibernate.show_sql">true</property>
      <!--格式化sql语句-->
      <property name="hibernate.format_sql">true</property>

  </session-factory>
</hibernate-configuration>
  • 准备数据表

  • account描述用户信息

在这里插入图片描述

  1. book,描述书籍信息

在这里插入图片描述

  1. book_stock描述书的库存信息

在这里插入图片描述

  • 准备出数据表的持续化类和对应的hibernate映射文件

在这里插入图片描述

Spring配置文件设置

  • 定义数据库连接信息,设置db…properties文件
jdbc.user=root
jdbc.password=mysqladmin
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/maoshu
  • 定义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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--读取资源文件-->
    <context:property-placeholder location="classpath:db.properties"/>

    <!--配置数据源-->
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
    </bean>


    <!--配置Hibernate的SessionFactory实例:通过Spring的LocalhostSessionFactory配置-->
    <!--要根据Hibernate的开发包版本选择对应的类-->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <!--配置数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置Hibernate的配置文件-->
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
        <!--配置Hibernate映射文件名称以及位置-->
        <!--"*" 表示通配符,匹配所有的*.hbm.xml文件-->
        <property name="mappingLocations" value="classpath:mao/shu/vo/*.hbm.xml"/>

    </bean>

    <!--配置Spring的声明式事物-->
    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!--配置事务属性-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get" read-only="true"/>
            <tx:method name="find" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切点,并将事务属性于切点关联起来-->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="txPointcut" expression="execution(* mao.shu.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

    </aop:config>
</beans>

测试代码

  • 编写DAO层
  • IBookShopDao接口
package mao.shu.dao;


public interface IBookShopDao{

    /**
     * 根据书的编号查询数据价格
     * @param isban 书的编号
     * @return
     */
    public double findPriceByisban(Integer isban);

    /**
     * 更新书的库存
     * @param isbn 书的编号
     * @param number 更新的数量
     * @return
     */
    public boolean updateBookStock(Integer isbn, Integer number);

    /**
     * 更新账户的余额
     * @param uid 账户编号
     * @param consumption 消费金额
     * @return
     */
    public boolean updateAccount(Integer uid, Double consumption);
}

  • BookShopDaoimpl实现BookShopDao接口
    • DAO层中使用SessionFactory获取当前线程绑定的Session
    • 不建议使用HibernateTemplate和HibernateSupport这样会使DAO和Spring的API耦合.可移植性变差
package mao.shu.dao.impl;

import mao.shu.dao.IBookShopDao;
import mao.shu.util.BookStockException;
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 BookShopDaoImpl implements IBookShopDao {
    @Autowired
    private SessionFactory sessionFactory;

    public Session getSession(){
        return this.sessionFactory.getCurrentSession();
    }
    @Override
    public double findPriceByisban(Integer isbn) {
        String hql = "SELECT b.price FROM Book b WHERE b.isbn = ?";
        Query query = this.getSession().createQuery(hql).setInteger(0,isbn);
        Double price = (Double) query.uniqueResult();
        return price;
    }

    @Override

    public boolean updateBookStock(Integer isbn, Integer number) {
        int stock = this.getStockByIsbn(isbn);
        if(stock == 0){
            throw new BookStockException("库存不足");
        }
        String hql = "UPDATE BookStock b SET b.stock = b.stock+? WHERE b.isbn=?";
        int result = this.getSession().createQuery(hql).setInteger(0,number).setInteger(1,isbn).executeUpdate();
        return result > 0;
    }

    @Override
    public boolean updateAccount(Integer uid, Double consumption) {
        if(this.getBalanceByUid(uid) < consumption){
            throw new BookStockException("余额不足");
        }
        String hql = "UPDATE Account a SET a.balance = a.balance-? WHERE a.uid=?";
        int result = this.getSession().createQuery(hql).setDouble(0,consumption).setInteger(1,uid).executeUpdate();
        return result > 0;
    }

    /**
     * 通过书的编号查询书的库存
     * @param isbn
     * @return
     */
    public Integer getStockByIsbn(Integer isbn){
        String hql = "SELECT b.stock FROM BookStock b WHERE b.isbn = ?";
        Query query = this.getSession().createQuery(hql).setInteger(0,isbn);
        Integer stock = (Integer) query.uniqueResult();
        return stock;
    }

    /**
     * 查询指定的账户余额
     * @param uid
     * @return
     */
    public Double getBalanceByUid(Integer uid){
        String hql = "SELECT a.balance FROM Account a WHERE a.uid= ?";
        Query query = this.getSession().createQuery(hql).setInteger(0,uid);
        Double balance = (Double) query.uniqueResult();
        return balance;
    }
}


  • 定义Service层接口
    1. ShopService
    2. Cashier
package mao.shu.service;

public interface ShopService {

    /**
     * 账户消费操作
     * @param uid 账户id
     * @param isbn 购买的书本编号
     * @return 成功返回true,否则返回false;
     */
    public boolean purchase(Integer uid, Integer isbn);
}

package mao.shu.service;

import java.util.List;

public interface Cashier {
    /**
     *  进行顾客结账操作,
     * @param uid 账户id
     * @param isbns 书本编号集合
     * @return
     */
    public boolean checkout(Integer uid, List<Integer> isbns);
}

  • 定义Service接口的实现子类
    1. ShopServiceImpl
    2. CashierImpl
package mao.shu.service.impl;

import mao.shu.dao.IBookShopDao;
import mao.shu.dao.impl.BookShopDaoImpl;
import mao.shu.service.ShopService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ShopServiceImpl implements ShopService {
    @Autowired
    private BookShopDaoImpl bookShopDao;

    @Override
    public boolean purchase(Integer uid, Integer isbn) {
        double bookPrice = this.bookShopDao.findPriceByisban(isbn);
        if(!(this.validateAccount(uid,bookPrice)&& this.validateStock(isbn,1))){
            return false;
        }
       if (this.bookShopDao.updateBookStock(isbn,-1)){
           return this.bookShopDao.updateAccount(uid,bookPrice);
       }
       return false;
    }

}

package mao.shu.service.impl;

import mao.shu.service.Cashier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
@Service
public class CashierImpl implements Cashier {
    @Autowired
    private ShopServiceImpl shopService;
    @Override
    public boolean checkout(Integer uid, List<Integer> isbns) {
        for (Integer isbn:isbns){
            if (!this.shopService.purchase(uid,isbn)){
                return false;
            }
        }
        return true;
    }
}

  • 编写测试类
package mao.shu.service.impl;

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

import java.util.Arrays;

import static org.junit.Assert.*;

public class ShopServiceImplTest {
    private ApplicationContext app;
    private ShopServiceImpl shopService;
    private CashierImpl cashier;
    @Before
    public void before(){
        this.app = new ClassPathXmlApplicationContext("application.xml");
        this.shopService = this.app.getBean("shopServiceImpl",ShopServiceImpl.class);
        this.cashier = this.app.getBean("cashierImpl",CashierImpl.class);
    }
    @Test
    public void purchase() {
        this.shopService.purchase(1,1);
    }
    @Test
    public void checkout(){
        this.cashier.checkout(1, Arrays.asList(1,1,1,1));
    }
}
  • 在使用注解的方式注入Bean实例的时候,需要在Spring的配置文件中添加注解扫描位置
  <!--设置Spring注解扫描基包-->
    <context:component-scan base-package="mao.shu" />
  • 在<tx:advice>标签中定义事务属性
 <!--配置事务属性-->
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
     <tx:attributes>
         <!--定义事务属性-->
         <tx:method name="get" read-only="true"/>
         <tx:method name="find" read-only="true"/>
         <tx:method name="checkout" propagation="REQUIRES_NEW"/>
         <tx:method name="*"/>
     </tx:attributes>
 </tx:advice>

不使用Hibernate配置文件

  • Hibernate中的配置可以直接在Spring文件中配置
    在配置LocalSessionFactoryBean实例中,使用 <property name=“hibernateProperties”>标签配置Hibernate属性
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
   <!--配置数据源-->
   <property name="dataSource" ref="dataSource"/>

   <!--配置Hibernate属性-->
   <property name="hibernateProperties">
       <props>
           <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
           <prop key="hibernate.show_sql">true</prop>
           <prop key="hibernate.format_sql">true</prop>
           <prop key="hibernate.hbm2ddl.auto">update</prop>
       </props>
   </property>
   
   <!--配置Hibernate映射文件名称以及位置-->
   <!--"*" 表示通配符,匹配所有的*.hbm.xml文件-->
   <property name="mappingLocations" value="classpath:mao/shu/vo/*.hbm.xml"/>

</bean>	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值