Spring整合Hibernate的步驟
第一步、HIbernate部分
1、匯入Hibernate的lib包
2、新建一個Hibernate的cfg檔案
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> <!--1.配置資料庫屬性 --> <!-- 2.配置對映檔案 --> <!-- 3.配置方言 、顯示mysql資料、生成資料庫表的策略等等 --> <!--前面兩個可以在Spring的配置檔案中設定就可以了 --> <!-- 配置方言:生成sql語言 換一句話就是說我們的查詢語句會自動轉化成底層sql語句去查詢sql表--> <property name="hibernate.dialect">org.hibernate.dialect.Dialect</property> <!-- 在日誌中顯示sql語句 --> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <!--有了這句話的話,只需要根據持久類的對映檔案就可以生成sql表 --> <property name="hibernate.hbm2ddl.auto">update</property> </session-factory> </hibernate-configuration>
3、新建兩個實體類
Account.java
package cn.spring.hibernate; public class Account { private int id; private String username; private int account; private int stock; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAccount() { return account; } public void setAccount(int account) { this.account = account; } public void setStock(int stock) { this.stock = stock; } public int getStock() { return stock; } }
BookInfo.java
package cn.spring.hibernate; public class BookInfo { private int id; private String bookname; private String isbn; private int price; public int getId() { return id; } public void setId(int 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) { this.isbn = isbn; } public void setPrice(int price) { this.price = price; } public int getPrice() { return price; } }
配置對映檔案Account.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="cn.spring.hibernate.Account" table="Account" catalog="lf">
<id column="id" name="id" type="int">
<generator class="native"></generator>
</id>
<property name="username" column="username" type="string"></property>
<property name="account" column="account" type="int"></property>
<property name="stock" column="stock" type="int"></property>
</class>
</hibernate-mapping>
配置對映檔案BookInfo.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="cn.spring.hibernate.Account" table="Account" catalog="lf">
<id column="id" name="id" type="int">
<generator class="native"></generator>
</id>
<property name="username" column="username" type="string"></property>
<property name="account" column="account" type="int"></property>
<property name="stock" column="stock" type="int"></property>
</class>
</hibernate-mapping>
4、在Spring的配置檔案裡面做如下的任務
4.1 、配置jdbc
4.2、配置hibernate的核心檔案
4.3、配置持久類的對映檔案
4.4、事務的宣告
如下是具體的實現過程,
新建一個applicationContexts.xml
配置jdbc
新建一個db.properties
jdbc.username=root
jdbc.password=123456
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///lf
配置hibernate的核心檔案和配置持久類的對映檔案
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!--配置資料庫 -->
<context:property-placeholder location="classpath:db.properties" />
<bean id="da" class="org.apache.commons.dbcp.BasicDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
</bean>
<!-- 配置hibernate的sessionFactory例項 -->
<bean id="localSessionFactoryBean"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="da"></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="mappingLocations" value="classpath:cn/spring/hibernate/*.hbm.xml">
</property>
</bean>
</beans>
測試類如下
package cn.com.text;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContexts.xml");
DataSource da=ioc.getBean(DataSource.class);
try {
System.out.println(da.getConnection());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
執行程式
結果:不報錯,開啟資料庫,自動生成了兩張表
注意:是執行程式自動生成的,不是我事先新建的表;
是 <property name="hibernate.hbm2ddl.auto">update</property>起到作用的
在配置檔案裡面Spring對事務的宣告
1、配置事務管理器
2、配置事務的屬性
3、把切點和事務關聯起來
疑問?為什麼需要用到事務?為什麼需要用到切面??
解答:事務的目的就是保證可以讓整個過程只有兩個結果,全部失敗或者全部成功,不存在有的完成了,有的沒有完成
為什麼用到切面,事務用到哪些包哪些方法,針對哪個類而言的,
配置檔案的程式碼如下
<!-- 配置Spring的申明式事務 -->
<!-- 1、事務管理器 -->
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="localSessionFactoryBean"></property>
</bean>
<!-- 配置事務的屬性 -->
<tx:advice transaction-manager="hibernateTransactionManager"
id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!--把事務的屬性和切點關聯起來 -->
<aop:config>
<aop:pointcut expression="execution(* cn.com.service.*.*(..))"
id="pointvut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointvut" />
</aop:config>
現在就是介面和實現類了
BookShopDao.java
package cn.com.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 cn.com.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;
import cn.com.dao.exception.BookCountException;
import cn.com.dao.exception.BookStockException;
@Repository(value="bookShopDao")
public class BookShopDaoImpl implements BookShopDao {
/*
* 在這裡只能用hibernate,不能跟之前一樣用的是底層的sql程式碼
* date:2018/12/27
*/
@Autowired
private SessionFactory sessionFactory;
// 獲取和當前執行緒繫結的session
private Session getSession() {
return sessionFactory.getCurrentSession();
}
public int findBookPriceByIsbn(String isbn) {
String sql = "SELECT b.price FROM BookInfo b WHERE b.isbn = ?";
System.out.println("sql:"+sql);
Query query = getSession().createQuery(sql);
query.setString(0, isbn);
int bi = (int) query.uniqueResult();
System.out.println("hahah"+bi);
return bi;
}
public void updateBookStock(String isbn) {
// 首先看一下庫存夠不夠
String sql0 = "select stock from BookInfo where isbn = ?";
int stock = (int) getSession().createQuery(sql0).setString(0, isbn)
.uniqueResult();
if (stock == 0) {
throw new BookStockException("庫存不足...");
}
// 查詢庫存
String sql = "update BookInfo set stock = stock-1 where isbn = ?";
getSession().createQuery(sql).setString(0, isbn).executeUpdate();
}
public void updateUserAccount(String username, int price) {
// 首先看一下餘額足不足
String sql = "select account from Account where username = ?";
int account = (int) getSession().createQuery(sql)
.setString(0, username).uniqueResult();
if (account < price) {
throw new BookCountException("餘額不足...");
}
// 扣除金額
String sqls = "update Account set account = ? where username = ?";
Query query=getSession().createQuery(sqls);
query.setInteger(0, account-price);
query.setString(1,username);
query.executeUpdate();
}
}
BookCountException.java
package cn.com.dao.exception;
public class BookCountException extends RuntimeException {
public BookCountException() {
super();
// TODO Auto-generated constructor stub
}
public BookCountException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public BookCountException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public BookCountException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public BookCountException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
BookStockException.java
package cn.com.dao.exception;
public class BookStockException extends RuntimeException{
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
}
}
BookShopList.java
package cn.com.dao.service;
import java.util.List;
public interface BookShopList {
public void getpurchare(String name,List<String> isbns);
}
BookShopListImpl.java
package cn.com.dao.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository(value="list")
public class BookShopListImpl implements BookShopList {
@Autowired
private BookShopService bookShopService;
public void getpurchare(String name, List<String> isbns) {
// TODO Auto-generated method stub
for (String isbn : isbns) {
bookShopService.purchase(name, isbn);
}
}
}
BookShopService.java
package cn.com.dao.service;
public interface BookShopService {
public void purchase(String username,String isbn);
}
BookShopServiceImpl.java
package cn.com.dao.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import cn.com.dao.BookShopDao;
@Repository(value="book")
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bookShopDaoImpl;
/* @Transactional(isolation=Isolation.READ_COMMITTED)*/
public void purchase(String username, String isbn) {
// 1.根據isbn來查詢價格和庫存
int price = bookShopDaoImpl.findBookPriceByIsbn(isbn);
// 2.更新庫存
bookShopDaoImpl.updateBookStock(isbn);
// 3.扣除賬戶餘額
bookShopDaoImpl.updateUserAccount(username, price);
}
}
最終版本的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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 掃描元件 -->
<context:component-scan base-package="cn.com.dao"></context:component-scan>
<!--配置資料庫 -->
<context:property-placeholder location="classpath:db.properties" />
<bean id="da" class="org.apache.commons.dbcp.BasicDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
</bean>
<!-- 配置hibernate的sessionFactory例項 -->
<bean id="localSessionFactoryBean"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="da"></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="mappingLocations" value="classpath*:cn/com/spring/hibernate/*.hbm.xml">
</property>
</bean>
<!-- 配置Spring的申明式事務 -->
<!-- 1、事務管理器 -->
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="localSessionFactoryBean"></property>
</bean>
<!-- 配置事務的屬性 -->
<tx:advice transaction-manager="hibernateTransactionManager"
id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="purchase" propagation="REQUIRES_NEW"/>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!-- 把事務的屬性和切點關聯起來 -->
<aop:config>
<aop:pointcut expression="execution(* cn.com.dao.service.*.*(..))"
id="pointcut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
</aop:config>
<!--使得註解生效 -->
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
</beans>
測試類
package cn.com.dao.com;
import java.util.Arrays;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.dao.service.BookShopList;
public class Test {
public static void main(String[] args) {
ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
/* 一個人買一本書
* BookShopService bs=(BookShopService) ioc.getBean("book");
bs.purchase("aa", "0102");
* */
//一個人買多本書
BookShopList bp=(BookShopList) ioc.getBean("list");
bp.getpurchare("bb", Arrays.asList(new String[]{"0101","0102"}));
}
}
測試無誤
注意兩個點
1、<!-- 配置事務的屬性 -->
<tx:advice transaction-manager="hibernateTransactionManager"
id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="purchase" propagation="REQUIRES_NEW"/>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
和@Transactional(isolation=Isolation.READ_COMMITTED)
一個是基於xml的配置,另一個是註解的方式配置事務的屬性
2、在類BookShopListImpl裡面的方法名不可以是getpurchare,不然會報錯,因為在配置檔案裡面有一個
<tx:method name="purchase" propagation="REQUIRES_NEW"/>