第一步、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"/>