频道栏目
首页 > 资讯 > 其他 > 正文

Spring整合Hibernate实战教程

18-01-18        来源:[db:作者]  
收藏   我要投稿

? ? ? ? 之前讲过纯粹的Hibernate开发,但是需要手动创建SessionFactory实例。在实际开发中,应该利用Spring容器声明式管理的特点,以配置文件来管理SessionFactory实例。Spring的IoC容器不仅能以声明式的方式配置SessionFactory实例,也可充分利用IoC容器的作用,为SessionFactory注入数据源引用。以下讲解的是Spring整合Hibernate的示例,从而理清整个过程具体步骤。

? ? ? ? 我接下来举的例子就是有一家餐厅,假设每个来吃饭的用户都会带一张充值卡来消费,然后根据菜单点菜,点完之后要进行刷卡,如果正常则保存余额,如果菜品不足或者余额不足则会进行提醒。那么从该例子可以看出持久化实体类有菜品和卡账户相关信息。

1.持久化类的创建并完成映射

1.1.持久化类的创建

? ? ? ? 何谓持久化类,简单来说就是要映射成数据库的对象,该例子涉及到数据操作的是菜品数量变化,以及消费卡账户余额的变化。所以接下来进行持久化类的创建,分别是Food类和Customer类。
package spring.hibernate.plugin.entity;

public class Food {
	private int id;  
    private String foodName;  
    private String identi;  
    private float price;  
    private int stock;  
  
    public int getId() {  
        return id;  
    }  
  
    public void setId(int id) {  
        this.id = id;  
    }  
  
    public String getFoodName() {  
        return foodName;  
    }  
  
    public void setfoodName(String foodName) {  
        this.foodName = foodName;  
    }  
  
    public String getIdenti() {  
        return identi;  
    }  
  
    public void setIdenti(String identi) {  
        this.identi = identi;  
    }  
  
    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;  
    }  
      

}
package spring.hibernate.plugin.entity;

public class Customer {
	private int id;  
    private String customername;  
    private float balance;  
      
    public int getId() {  
        return id;  
    }  
  
    public void setId(int id) {  
        this.id = id;  
    }  
  
    public String getCustomername() {  
        return customername;  
    }  
  
    public void setCustomername(String customer) {  
        this.customername = customer;  
    }  
  
    public float getBalance() {  
        return balance;  
    }  
  
    public void setBalance(float balance) {  
        this.balance = balance;  
    }  

}?

1.2.映射配置--hbm.xml文件

? ? ?接下来对持久化类进行映射,这里采用*.hbm.xml文件分别对每个类进行映射配置,配置文件如下:
Food.hbm.xml:
   
 
  
      
          
              
              
          
          
          
              
          
          
          
              
          
          
          
              
          
          
          
              
          
          
      
  
Customer.hbm.xml:
  
  
  
      
          
              
              
          
          
          
              
          
          
          
              
          
          
      
  
? ? ? ? 其实,配置文件比较简单,根据模板修改即可,主要是对持久化类属性的配置。

1.3.hibernate配置文件-hibernate.cfg.xml

? ? ? ? 这里的hibernate配置文件有别于纯粹的hibernate开发,这里只需要一些hibernate基本配置即可,并不需要跟纯粹的hibernate开发那样将hbm.xml文件配置其中,注意,整合开发的hbm.xml是和hibernate.cfg.xml文件一起配置到Spring容器之中的,整合开发将Spring容器的工厂作用发挥的淋漓尽致。以下是hibernate.cfg.xml文件。
  
  
  
      
        
        
        
        
      org.hibernate.dialect.MySQL5InnoDBDialect  
        
      true  
      true  
        
      update
      false
      org.springframework.orm.hibernate4.SpringSessionContext 
      
        
      
 
? ? ? ? 注意:上面配置文件中"hibernate.temp.use_jdbc_metadata_defaults"和"hibernate.current_session_context_class"这两个属性的配置最好添加,在有的环境没有这两个属性则会报错,所以建议一开始就配置好这两个属性。
 

2.Spring容器的配置文件applicationContext.xml文件

 


	  
   	  
	
	
	
	  
     
         
         
         
         
         
        
    
	
	
? ? ? ? ?在纯粹的Hibernate访问中,应用程序需要手动创建SessionFactory,而这里使用的是声明式管理SessionFactory实例,可以把它放进Spring大容器进行管理。目前的applicationContext.xml文件先把持久类配置文件现装入其中,然后将管理Hibernate的SessionFactory实例化,而SessionFactory需要传入数据源,所以在这之前先将数据源进行Bean实例化,并对数据源进行参数设置。这样SessionFactory实例就放入了Spring大容器中进行管理了。

3.DAO组件的基类与实现类以及相应的异常类

3.1.DAO组件的基类与实现类

? ? ? ?其实,DAO组件就是一种对数据库进行CRUD方法提取的基类。这里包含了各种操作方法,为了后面传给Service层。
package spring.hibernate.plugin.dao;

public interface RestaurantDao {
	/** 
     * 根据菜单上的菜品号获取食物价格 
     */  
    public float  findPriceByIdenti(String identi);  
      
    /** 
     * 更新书的库存,使菜品号对应的书本减少n份 
     *  
     */  
    public void updateFoodStock(String identi,int n);  
      
    /** 
     * 更新账户余额,使顾客所带钱减少 price*n 
     */  
    public void updateAccount(String customername,float price,int n);  

}
package spring.hibernate.plugin.dao.impl;
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 spring.hibernate.plugin.dao.RestaurantDao;
import spring.hibernate.plugin.exception.*;
/**
 * 用hql进行数据库操作
 * @author carson0408
 *
 */
//dao组件用@Repository注释
@Repository
public class RestaurantDaoImpl implements RestaurantDao {
	//自动装配,省去了setter方法
	@Autowired  
    private SessionFactory sessionfactory;  
      
    /**
     * 连接当前线程,使用SessionFactory的getCurrentSession()方法。
     * @return
     */
    private Session getSession(){  
        return sessionfactory.openSession();    
    }  
      
	@Override
	public float findPriceByIdenti(String identi) {
		// TODO Auto-generated method stub
		String hql="select f.price from Food f where f.identi=:a";  
        float price=(float) getSession().createQuery(hql).setString("a", identi).uniqueResult();  
        return price;  
	}

	@Override
	public void updateFoodStock(String identi, int n) {
		// TODO Auto-generated method stub
		String hq="Select f.stock from Food f where f.identi=:identi";  
        int stock=(int) getSession().createQuery(hq).setString("identi", identi).uniqueResult();  
        if(stock < n){  
             throw new OutofStockException("so sorry,this food is sold out");  
        }     
        String hql="update Food f set f.stock=f.stock-:a where f.identi=:b";  
        getSession().createQuery(hql).setInteger("a", n).setString("b", identi).executeUpdate();  //更新事物剩余量    

	}

	@Override
	public void updateAccount(String customername, float price, int n) {
		// TODO Auto-generated method stub
		//验证客户所持有的饭店支付卡余额是否足够 
		float cost=n*price;
        String hql="select c.balance from Customer c where c.customername=:a";  

        float balance=(float) getSession().createQuery(hql).setString("a", customername).uniqueResult();  
        if(balance < cost){  
            throw new OutofBalanceException("sorry,your card's money is not enough to pay for this food");  
        }  
        String hql1="update Customer c set c.balance=c.balance-:a where c.customername=:b";  
        getSession().createQuery(hql1).setFloat("a", cost).setString("b", customername).executeUpdate();  
    }  

	

}


 
? ? ? ? 由上DAO实现类可知,对数据库进行操作需要用到Session,所以需要开启Session,在applicationContext.xml中已经将SessionFactory实例化,说明已经在Spring中管理,所以利用Spring的自动装配,用@Autowired进行修饰SessionFactory,相当于setter方法,这里利用了自动装配可以省略setter方法。然后利用SessionFactory的openSession获取Session,然后进行操作。这里的操作都使用hql查询。这里的DAO类用@Repository注释。

3.2.异常类

? ? ? ? 上面DAO实现类中出现了异常,以下是DAO组件中用到的异常类:
package spring.hibernate.plugin.exception;

public class OutofStockException extends RuntimeException {

	public OutofStockException() {
		// TODO Auto-generated constructor stub
	}

	public OutofStockException(String arg0) {
		super(arg0);
		// TODO Auto-generated constructor stub
	}

}
package spring.hibernate.plugin.exception;

public class OutofBalanceException extends RuntimeException {

	public OutofBalanceException() {
		// TODO Auto-generated constructor stub
	}

	public OutofBalanceException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	
}
? ? ? ? 以上两个异常分别是菜品不足和余额不足,对应的是菜品对象以及客户对象。

 
 

4.Service层

? ? ? ? Service层主要是针对具体功能进行实际操作,比如进行实际的点菜消费等等。这里主要是指消费功能。
package spring.hibernate.plugin.service;

public interface RestaurantService {
	
	public void cost(String username,String identi,int n);

}
实现Service:
package spring.hibernate.plugin.service.impl;

import spring.hibernate.plugin.service.RestaurantService;
import spring.hibernate.plugin.dao.*;
import org.springframework.stereotype.*; 
import org.springframework.beans.factory.annotation.Autowired;  
@Service
public class RestaurantServiceImpl implements RestaurantService {
	
	
	@Autowired
	private RestaurantDao restaurantDao;

	@Override
	public void cost(String username, String identi, int n) {
		// TODO Auto-generated method stub
		float price=restaurantDao.findPriceByIdenti(identi);  
		restaurantDao.updateFoodStock(identi, n);  
		restaurantDao.updateAccount(username, price, n); 

	}

}


5.事务配置以及AOP配置

? ? ? ? 对其进行事务配置,比如出现异常之后要进行回滚。并且对每一个操作都进行增强处理,以下是完整的applicationContext.xml文件


	  
   	  
	
	
	
	  
     
         
         
         
         
         
        
    
	
	
	
	
	
	
	

	
	
		
		
			
			
			
			
		
	
	
	
		
		
		
		
	
	
	

   

6.测试

? ? ? ? 以下便是测试代码:
package spring.hibernate.plugin.test;
import spring.hibernate.plugin.service.*;
import org.springframework.beans.factory.annotation.*;  
import org.springframework.stereotype.Repository;  
import org.junit.Test;  
import org.junit.runner.RunWith; 
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;  
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration("classpath:applicationContext.xml")  
public class PluginTest {
	@Autowired  
    private RestaurantService restaurantService;  
      
    @Test  
    public void testCost(){  
    	restaurantService.cost("carson", "1102", 2);  
    }  

}
右键选择Run as->Run configurations然后选择Junit,这里将项目进行Junit测试。测试代码上需要有@RunWith(SpringJUnit4ClassRunner.class)和@ContextConfiguration("classpath:applicationContext.xml") ?两个注释,运行之后,刚开始若没有建表,相应的数据库中会生成两个相应的表,同时报错。这是因为没法对空表进行相应操作。所以对food_menu和customer两个表添加数据如下:
数据库spring_hibernate:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
food_menu:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
customer:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
 
? ? ? ? 然后再次进行测试,得到如下结果:
 
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? 由上面测试例子可以知道,客户"carson"买了两个菜品号为1102的食物,所以库存变为0,客户余额为60元,底层hibernate对数据库的操作代码如下:
Hibernate: 
    select
        food0_.PRICE as col_0_0_ 
    from
        FOOD_MENU food0_ 
    where
        food0_.IDENTI=?
Hibernate: 
    select
        food0_.STOCK as col_0_0_ 
    from
        FOOD_MENU food0_ 
    where
        food0_.IDENTI=?
Hibernate: 
    update
        FOOD_MENU 
    set
        STOCK=STOCK-? 
    where
        IDENTI=?
Hibernate: 
    select
        customer0_.BALANCE as col_0_0_ 
    from
        CUSTOMER customer0_ 
    where
        customer0_.CUSTOMERNAME=?
Hibernate: 
    update
        CUSTOMER 
    set
        BALANCE=BALANCE-? 
    where
        CUSTOMERNAME=?
? ? ? ? 接下来为了检测异常功能,将测试代码更改如下:
package spring.hibernate.plugin.test;
import spring.hibernate.plugin.service.*;
import org.springframework.beans.factory.annotation.*;  
import org.springframework.stereotype.Repository;  
import org.junit.Test;  
import org.junit.runner.RunWith; 
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;  
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration("classpath:applicationContext.xml")  
public class PluginTest {
	@Autowired  
    private RestaurantService restaurantService;  
      
    @Test  
    public void testCost(){  
    	restaurantService.cost("carson", "1101", 2); //1
    	restaurantService.cost("adam", "1102", 2);//2
    }  

}
分别测试1和2,分别得到报错:
spring.hibernate.plugin.exception.OutofBalanceException: sorry,your card's money is not enough to pay for this food和spring.hibernate.plugin.exception.OutofStockException: so sorry,this food is sold out并且当余额不足时不能购买,则余额不会改变,而东西卖完之后报错,也不会改变,说明了事务回滚到之前状态。
相关TAG标签
上一篇:C# Winform 嵌入Google浏览器 Chrome 与JS交互讲解
下一篇:springboot中properties文件不能自动提示解决方法
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站