您的位置:首页 > 编程语言 > Java开发

Spring4.0学习笔记--整合Hibernate

2016-03-16 14:08 441 查看
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">•Spring 支持大多数流行的 ORM 框架, 包括 Hibernate JDO, TopLink, Ibatis 和 JPA。</span>

•Spring 对这些ORM
框架的支持是一致的, 因此可以把和 Hibernate 整合技术应用到其他 ORM 框架上.
•Spring 2.0 同时支持 Hibernate 2.x 和 3.x. 但 Spring 2.5 只支持 Hibernate 3.1 或更高版本

在Spring
中配置SessionFactory


•对于 Hibernate而言, 必须从原生的 Hibernate API 中构建 SessionFactory. 此外, 应用程序也无法利用Spring 提供的数据存储机制(例如: Spring 的事务管理机制)
•Spring 提供了对应的工厂 Bean, 可以用单实例的形式在 IOC 容器中创建 SessionFactory 实例.

•可以利用 LocalSessionFactoryBean 工厂 Bean, 声明一个使用 XML 映射文件的 SessionFactory 实例.
•需要为该工厂 Bean 指定 configLocation 属性来加载 Hibernate配置文件.



•如果在 SpringIOC 容器中配置数据源. 可以将该数据源注入到 LocalSessionFactoryBean 的 dataSource 属性中. 该属性可以指定的数据源会覆盖掉 Hibernate配置文件里的数据库配置.



•可以将所有配置合并到 LocalSessionFactoryBean 中,从而忽略 Hibernate 配置文件.
•可以在 LocalSessionFactoryBean 的
mappingResources 属性中指定 XML 映射文件的位置.该属性为 String[] 类型. 因此可以指定一组映射文件.
•在 hibernateProperties 属性中指定数据库方言等.



用Spring
的ORM
模板持久化对象


•在单独使用 ORM 框架时, 必须为每个 DAO 操作重复某些常规任务. 例如: 打开关闭 Session 对象; 启动, 提交, 回滚事务等.
•同 JDBC 一样, Spring 采取了相同的方法 ------ 定义模板类和DAO
支持类来简化 ORM 框架的使用. 而且 Spring 在不同的事务管理 API 之上定义了一个事务抽象层. 对于不同的 ORM 框架, 只需要选择相应的事务管理器实现.

Spring对不同数据存储策略的支持类



•HibernateTemplate 确保了 Hibernate会话能够正确地打开和关闭.

•HibernateTemplate 也会让原生的 Hibernate事务参与到 Spring 的事务管理体系中来. 从而利用 Spring 的声明式事务管理事务.

使用Hibernate模板

•HibernateTemplate 中的模板方法管理会话和事务. 如果在一个支持事务的 DAO 方法中有多个 Hibernate操作, 模板方法可以确保它们会在同一个会话和事务中运行. 因此没有必要为了会话和事务管理去和 Hibernate API 打交道.
•通过为 DAO 方法添加 @Transactional 注解将其声明为受事务管理的.
•HibernateTemplate 类是线程安全的, 因此可以在 Bean 配置文件中只声明一个实例, 并将该实例注入到所有的 Hibernate DAO 中.





在HibernateTemplate中访问
Hibernate底层Session







继承Hibernate的DAO
支持类


•Hibernate DAO 可以通过继承 HibernateDaoSupport 来继承 setSessionFactory() 和 setHibernateTemplate() 方法. 然后, 只要在 DAO 方法中调用 getHibernateTemplate() 方法就可以获取到模板实例.
•如果为 HibernateDaoSupport 实现类注入了 SessionFactory 实例, 就不需要在为之注入 HibernateTemplate 实例了, 因为HibernateDaoSupport  会根据传入的 SessionFactory 在其构造器内创建 HibernateTemplate 的实例, 并赋给 hibernateTemplate 属性

用Hibernate的上下文Session
持久化对象


•Spring 的 HibernateTemplate 可以管理会话和事务, 简化 DAO 实现. 但使用 HibernateTemplate 意味着DAO 必须依赖于 Spring 的 API
•代替 HibernateTemplate 的另一种办法是使用 Hibernate 的上下文 Session 对象.
•Hibernate 上下文Session
对象和 Spring
的事务管理合作的很好,但此时需保证所有的DAO
方法都支持事务
•注意此时不需在 beans.xml 文件中配置, 因为 Spring 此时已经开始事务, 所以已经在 ThreadLocal 对象中绑定了 Session 对象 



•在 Hibernate会话中调用原生的方法时, 抛出的异常依旧是原生的 HibernateException.
•为了保持一致的异常处理方法, 即把 Hibernate异常转换为 Spring 的 DataAccessException 异常, 那么必须为需要异常转换的DAO 类添加 @Respository 注解.
•然后在注册一个

实例, 将原生的 Hibernate 异常转换为 Spring 的 DataAccessException 层次结构中的数据存取异常. 这个 Bean 后置处理器只为添加了@Respository 注解的 Bean 转换异常. 

•从 Hibernate3 开始, SessionFactory 新增加了 getCurrentSession() 方法, 该方法可直接获取“上下文“相关的 Session.
•Hibernate 通过 CurrentSessionContext 接口的实现类和 配置参数hibernate.current_session_context_class定义 “上下文”
–JTASessionContext: 根据 JTA 来跟踪和界定 Session 对象.
–ThreadLocalSessionContext: 通过当前正在执行的线程来跟踪和界定 Session 对象
–ManagedSessionContext: 通过正在当前执行来跟踪和界定 Session 对象. 但程序需要调用该类的静态方法来绑定 Sessio 对象, 取消绑定, flush 或者关闭 Session 对象.

•如果使用 ThreadLocalSessionContext 策略,Hibernate 的 Session 会随着 getCurrentSession() 方法自动打开, 随着事务提交自动关闭.
• 若当前应用是基于 JTA 的分布式事务, 通常采用第一种方式; 而对于独立的 Hibernate 应用则使用第二种应用.
•配置:
–根据 JTA 来跟踪和界定 Session 对象:



–通过当前正在执行的线程来跟踪和界定 Session 对象:



代码实现
1. Spring 整合 Hibernate 整合什么 ?

1). 有 IOC 容器来管理 Hibernate 的 SessionFactory

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

2. 整合步骤:

1). 加入 hibernate

①. jar 包

②. 添加 hibernate 的配置文件: hibernate.cfg.xml

③. 编写了持久化类对应的 .hbm.xml 文件。 

2). 加入 Spring

①. jar 包

②. 加入 Spring 的配置文件

3). 整合.

3. 编写代码



数据库
use spring;
create table book(
isbn varchar(50) primary key,
book_name varchar(100),
price int
);

create table book_stock(
isbn varchar(50) primary key,
stock int,
check(stock > 0)
);

create table account(
username varchar(50) primary key,
balance int,
check(balance > 0)
);


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>

<!-- 配置 hibernate 二级缓存相关的属性. -->

</session-factory>

</hibernate-configuration>


db.properties

jdbc.user=root
jdbc.password=1230
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spring7

jdbc.initPoolSize=5
jdbc.maxPoolSize=10


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.0.xsd 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"> 
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.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>
-->
<!-- 使用 hibernateProperties 属相来配置 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 映射文件的位置及名称, 可以使用通配符 -->
<property name="mappingLocations"
value="classpath:com/atguigu/spring/hibernate/entities/*.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="get*" read-only="true"/>
<tx:method name="purchase" propagation="REQUIRES_NEW"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- 3. 配置事务切点, 并把切点和事务属性关联起来 -->
<aop:config>
<aop:pointcut expression="execution(* com.atguigu.spring.hibernate.service.*.*(..))"
id="txPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

</beans>


BookShopDao.java
package com.atguigu.spring.hibernate.dao;

public interface BookShopDao {

//根据书号获取书的单价
public int findBookPriceByIsbn(String isbn);

//更新数的库存. 使书号对应的库存 - 1
public void updateBookStock(String isbn);

//更新用户的账户余额: 使 username 的 balance - price
public void updateUserAccount(String username, int price);
}


BookShopDaoImpl.java
package com.atguigu.spring.hibernate.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 com.atguigu.spring.hibernate.dao.BookShopDao;
import com.atguigu.spring.hibernate.exceptions.BookStockException;
import com.atguigu.spring.hibernate.exceptions.UserAccountException;

@Repository
public class BookShopDaoImpl implements BookShopDao {

@Autowired
private SessionFactory sessionFactory;

//不推荐使用 HibernateTemplate 和 HibernateDaoSupport
//因为这样会导致 Dao 和 Spring 的 API 进行耦合
//可以移植性变差
//	private HibernateTemplate hibernateTemplate;

//获取和当前线程绑定的 Session.
private Session getSession(){
return sessionFactory.getCurrentSession();
}

@Override
public int findBookPriceByIsbn(String isbn) {
String hql = "SELECT b.price FROM Book b WHERE b.isbn = ?";
Query query = getSession().createQuery(hql).setString(0, isbn);
return (Integer)query.uniqueResult();
}

@Override
public void updateBookStock(String isbn) {
//验证书的库存是否充足.
String hql2 = "SELECT b.stock FROM Book b WHERE b.isbn = ?";
int stock = (int) getSession().createQuery(hql2).setString(0, isbn).uniqueResult();
if(stock == 0){
throw new BookStockException("库存不足!");
}

String hql = "UPDATE Book b SET b.stock = b.stock - 1 WHERE b.isbn = ?";
getSession().createQuery(hql).setString(0, isbn).executeUpdate();
}

@Override
public void updateUserAccount(String username, int price) {
//验证余额是否足够
String hql2 = "SELECT a.balance FROM Account a WHERE a.username = ?";
int balance = (int) getSession().createQuery(hql2).setString(0, username).uniqueResult();
if(balance < price){
throw new UserAccountException("余额不足!");
}

String hql = "UPDATE Account a SET a.balance = a.balance - ? WHERE a.username = ?";
getSession().createQuery(hql).setInteger(0, price).setString(1, username).executeUpdate();
}

}


Account.java
package com.atguigu.spring.hibernate.entities;

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;
}

}


Account.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="com.atguigu.spring.hibernate.entities.Account" table="SH_ACCOUNT">

<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>

<property name="username" type="java.lang.String">
<column name="USERNAME" />
</property>

<property name="balance" type="int">
<column name="BALANCE" />
</property>

</class>
</hibernate-mapping>


Book.java
package com.atguigu.spring.hibernate.entities;

public class Book {

private Integer id;
private String bookName;
private String isbn;
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 getIsbn() {
return isbn;
}

public void setIsbn(String isbn) {
t
aa6e
his.isbn = isbn;
}

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;
}

}


Book.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="com.atguigu.spring.hibernate.entities.Book" table="SH_BOOK">

<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>

<property name="bookName" type="java.lang.String">
<column name="BOOK_NAME" />
</property>

<property name="isbn" type="java.lang.String">
<column name="ISBN" />
</property>

<property name="price" type="int">
<column name="PRICE" />
</property>

<property name="stock" type="int">
<column name="STOCK" />
</property>

</class>
</hibernate-mapping>


BookShopService.java
package com.atguigu.spring.hibernate.service;

public interface BookShopService {

public void purchase(String username, String isbn);

}


Cashier.java
package com.atguigu.spring.hibernate.service;

import java.util.List;

public interface Cashier {

public void checkout(String username, List<String> isbns);

}


BookShopServiceImpl.java
package com.atguigu.spring.hibernate.service.impl;

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

import com.atguigu.spring.hibernate.dao.BookShopDao;
import com.atguigu.spring.hibernate.service.BookShopService;

@Service
public class BookShopServiceImpl implements BookShopService {

@Autowired
private BookShopDao bookShopDao;

/**
* Spring hibernate 事务的流程
* 1. 在方法开始之前
* ①. 获取 Session
* ②. 把 Session 和当前线程绑定, 这样就可以在 Dao 中使用 SessionFactory 的
* getCurrentSession() 方法来获取 Session 了
* ③. 开启事务
*
* 2. 若方法正常结束, 即没有出现异常, 则
* ①. 提交事务
* ②. 使和当前线程绑定的 Session 解除绑定
* ③. 关闭 Session
*
* 3. 若方法出现异常, 则:
* ①. 回滚事务
* ②. 使和当前线程绑定的 Session 解除绑定
* ③. 关闭 Session
*/
@Override
public void purchase(String username, String isbn) {
int price = bookShopDao.findBookPriceByIsbn(isbn);
bookShopDao.updateBookStock(isbn);
bookShopDao.updateUserAccount(username, price);
}

}


CashierImpl.java
package com.atguigu.spring.hibernate.service.impl;

import java.util.List;

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

import com.atguigu.spring.hibernate.service.BookShopService;
import com.atguigu.spring.hibernate.service.Cashier;

@Service
public class CashierImpl implements Cashier{

@Autowired
private BookShopService bookShopService;

@Override
public void checkout(String username, List<String> isbns) {
for(String isbn:isbns){
bookShopService.purchase(username, isbn);
}
}

}


BookStockException.java
package com.atguigu.spring.hibernate.exceptions;

public class BookStockException extends RuntimeException{

/**
*
*/
private static final long serialVersionUID = 1L;

public BookStockException() {
super();
// TODO Auto-generated constructor stub
}

public BookStockException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}

public BookStockException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}

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

public BookStockException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}

}


UserAccountException.java
package com.atguigu.spring.hibernate.exceptions;

public class UserAccountException extends RuntimeException{

/**
*
*/
private static final long serialVersionUID = 1L;

public UserAccountException() {
super();
// TODO Auto-generated constructor stub
}

public UserAccountException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}

public UserAccountException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}

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

public UserAccountException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}

}


SpringHibernateTest.java
package com.atguigu.spring.hibernate.test;

import java.sql.SQLException;
import java.util.Arrays;

import javax.sql.DataSource;

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

import com.atguigu.spring.hibernate.service.BookShopService;
import com.atguigu.spring.hibernate.service.Cashier;

public class SpringHibernateTest {

private ApplicationContext ctx = null;
private BookShopService bookShopService = null;
private Cashier cashier = null;

{
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
bookShopService = ctx.getBean(BookShopService.class);
cashier = ctx.getBean(Cashier.class);
}

@Test
public void testCashier(){
cashier.checkout("aa", Arrays.asList("1001","1002"));
}

@Test
public void testBookShopService(){
bookShopService.purchase("aa", "1001");
}

@Test
public void testDataSource() throws SQLException {
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource.getConnection());
}

}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring