一.整合目標(biāo)
(1)又IOC容器來管理Hibernate的SessionFactory
(2)讓Hibernate使用上Spring的生命式事務(wù)
二.整合步驟
1.加入hibernate
(1)加入jar包

Paste_Image.png
(2)新建hibernate配置文件hibernate.cfg.xml
<session-factory>
<!-- 配置hibernate基本屬性 -->
<!-- 1.數(shù)據(jù)源配置到IOC容器中,所以在此不需要配置數(shù)據(jù)連接相關(guān)信息 -->
<!-- 2.關(guān)聯(lián)hbm.xml也在IOC容器配置SessionFactory實例時在進行配置 -->
<!-- 3.配置hibernate的基本屬性:方言,SQL顯示及格式,生成數(shù)據(jù)表的策略以及二級緩存 -->
<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>
(3)編寫持久化類以及對應(yīng)的.hbm.xml映射文件

Paste_Image.png
2.加入Spring
(1)加入jar包

Paste_Image.png
(2)配置Spring配置文件
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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- Spring與Hibernate整合 -->
<context:component-scan base-package="lxf.spring.hibernate"></context:component-scan>
<!-- 配置數(shù)據(jù)源 -->
<!-- 導(dǎo)入屬性文件 classpath代表類路徑 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置c3p0數(shù)據(jù)源 -->
<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實例 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 配置數(shù)據(jù)源屬性 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 配置Hibernate 配置文件的位置及名稱
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>-->
<!-- hibernate配置文件的內(nèi)容也可以作為Spring的屬性配置 -->
<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">true</prop>
</props>
</property>
<!-- 配置 Hibernate映射文件的位置以及名稱,可以使用通配符-->
<property name="mappingLocations" value="classpath:lxf/spring/hibernate/entiries/*.hbm.xml"></property>
</bean>
<!-- 配置Spring的聲明式事務(wù) -->
<!-- 1.配置事務(wù)管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 2.配置事務(wù)屬性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!-- 3.配置事務(wù)切點,并把切點和事務(wù)屬性關(guān)聯(lián) -->
<aop:config>
<!-- 配置切入點 -->
<aop:pointcut expression="execution( * lxf.spring.hibernate.service.impl.*.*(..))" id="txPointCut"/>
<!-- 將切入點和屬性關(guān)聯(lián) -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
(3)單元測試SpringHibernateTest.java
/**
* 單元測試Spring整合hibernate類
* @author lxf
*/
public class SpringHibernateTest {
private ApplicationContext ctx = null;
{
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
/**
* 測試數(shù)據(jù)源連接
* @throws SQLException
*/
@Test
public void testDataSource() throws SQLException {
DataSource dataSource = (DataSource)ctx.getBean("dataSource");
System.out.println(dataSource.getConnection());
}
}
如果配置沒有問題,單元測試會成功,而且會自動在數(shù)據(jù)庫中建立那兩張表
三.Spring hibernate事務(wù)流程
* 1.在方法開始之前
* (1)獲取Session
* (2)把Session和當(dāng)前線程綁定,這樣就可以在Dao中使用
* SessionFactory的getCurrentSession方法獲取Session了
* (3)開啟事務(wù)
*
* 2.若方法正常結(jié)束,則沒有出現(xiàn)異常,則
* (1)提交事務(wù)
* (2)使和當(dāng)前線程的Session解除綁定
* (3)關(guān)閉Session
*
* 3.若方法出現(xiàn)異常,則:
* (1)回滾事務(wù)
* (2)使和當(dāng)前線程的Session解除綁定
* (3)關(guān)閉Session
Spring Hibernate事務(wù)實現(xiàn)除了BookShopDaoImpl.java與其他文件不一樣,其他都一樣:
package lxf.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 lxf.spring.hibernate.dao.BookShopDao;
import lxf.spring.hibernate.exception.BookStockException;
import lxf.spring.hibernate.exception.UserAcountException;
@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {
@Autowired
private SessionFactory sessionFactory;
//獲得和當(dāng)前線程綁定的session
public Session getSession()
{
return sessionFactory.getCurrentSession();
}
@Override
public double findBookPriceBookId(Integer bookId) {
String hql ="SELECT b.price FROM Books b WHERE b.book_id = ?";
Query query = getSession().createQuery(hql).setInteger(0, bookId);
return (double)query.uniqueResult();
}
@Override
public void updateBookStock(Integer bookId) {
//先查詢是否有庫存
String hql ="SELECT b.stock FROM Books b WHERE b.book_id= ?";
Query query = getSession().createQuery(hql).setInteger(0, bookId);
int stock = (int)query.uniqueResult();
if(stock <= 0)
{
throw new BookStockException("圖書庫存不足!");
}
//修改庫存
String hql2 = "UPDATE Books b SET b.stock =b. stock-1 WHERE b.book_id = ?";
getSession().createQuery(hql2).setInteger(0, bookId).executeUpdate();
}
@Override
public void updateUserAccount(Integer userId, double price) {
//先查詢賬戶余額是否夠
String hql ="SELECT a.balance FROM Acount a WHERE a.id = ?";
Query query = getSession().createQuery(hql).setInteger(0, userId);
double balance = (double)query.uniqueResult();
if(balance <= 0)
{
throw new UserAcountException("用戶賬戶余額不足!");
}
//修改賬戶余額
String hql2 = "UPDATE Acount a SET a.balance = a.balance-? WHERE a.id = ?";
getSession().createQuery(hql2).setDouble(0, price).setInteger(1, userId).executeUpdate();
}
}