public
interface
BookShopDao {
//根据书号获取书的单价
public
int
findBookPriceByIsbn(String isbn);
//更新书的库存,使书号对应的库存-1
public
void
updateBookStock(String isbn);
//更新用户的账户余额,是username的balance-price
public
void
updateUserAccount(String username,
int
price);
}
@Repository
public
class
BookShopDaoImpl
implements
BookShopDao{
@Autowired
private
SessionFactory sessionFactory;
/**HibernateTemplate和HibernateDaoSupport是Spring API,不建议使用。
* 这样会导致Dao和Spring API的耦合。可移植性变差。
*private HibernateTemplate hibernateTemplate;
*/
private
Session getSession(){
//获取和当前线程绑定的session
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 hql =
"select b.stock from Book b where b.isbn = ?"
;
int
stock = (Integer) getSession().createQuery(hql).setString(
0
, isbn).uniqueResult();
if
(stock <=
0
) {
throw
new
BookStockException(
"库存不足"
);
}
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 hql =
"select a.balance from Account a where a.username = ?"
;
int
balance = (Integer) getSession().createQuery(hql).setString(
0
, username).uniqueResult();
if
(balance < price) {
throw
new
UserAccountException(
"余额不足"
);
}
hql =
"update Account a set a.balance = a.balance - ? where a.username = ?"
;
getSession().createQuery(hql).setInteger(
0
, price).setString(
1
, username).executeUpdate();
}
}
public
interface
BookShopService {
public
void
purchase(String username, String isbn);
}
@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) {
/*
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
//获取书的单价
int
price = bookShopDao.findBookPriceByIsbn(isbn);
//更新书的库存
bookShopDao.updateBookStock(isbn);
//更新用户余额
bookShopDao.updateUserAccount(username, price);
}
}
@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);
}
}
}
public
class
Account {
private
Integer id;
private
String username;
private
int
balance;
//..
}
public
class
Book {
private
Integer id;
private
String bookName;
private
String isbn;
private
int
price;
private
int
stock;
//...
}
jdbc.user=root
jdbc.password=123456
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:
///SpringHibernate
?createDatabaseIfNotExist\=
true
jdbc.initialPoolSize=5
jdbc.maxPoolSize=10
<?
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显示、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
>
<?
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:aop
=
"http://www.springframework.org/schema/aop"
xmlns:tx
=
"http://www.springframework.org/schema/tx"
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.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<!-- 配置自动扫描的包 -->
<
context:component-scan
base-package
=
"com.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.initialPoolSize}"
></
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
>
<!-- 配置Hibern配置文件的位置及名称 -->
<
property
name
=
"configLocation"
value
=
"classpath:hibernate.cfg.xml"
></
property
>
<!-- 配置Hibernate映射文件的位置及名称,可以只用通配符 -->
<
property
name
=
"mappingLocations"
value
=
"com/spring/hibernate/entity/*.hbm.xml"
></
property
>
</
bean
>
<!-- 配置Spring的声明式事务 -->
<!-- 1.配置事务管理器 -->
<
bean
id
=
"transactionManager"
class
=
"org.springframework.orm.hibernate4.HibernateTransactionManager"
>
<
property
name
=
"sessionFactory"
ref
=
"sessionFactory"
/>
</
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.spring.hibernate.service.*.*(..))"
id
=
"txPointcut"
/>
<
aop:advisor
advice-ref
=
"txAdvice"
pointcut-ref
=
"txPointcut"
/>
</
aop:config
>
</
beans
>
public
class
SpringHibernateTest {
private
ApplicationContext applicationContext =
null
;
private
BookShopService bookShopService =
null
;
private
Cashier cashier =
null
;
{
applicationContext =
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
bookShopService = applicationContext.getBean(BookShopService.
class
);
cashier = applicationContext.getBean(Cashier.
class
);
}
@Test
public
void
test3() {
cashier.checkout(
"umgsai"
, Arrays.asList(
"1001"
,
"1002"
));
}
@Test
public
void
test2() {
bookShopService.purchase(
"umgsai"
,
"1001"
);
}
@Test
public
void
test1() {
DataSource dataSource = applicationContext.getBean(DataSource.
class
);
try
{
System.out.println(dataSource.getConnection());
}
catch
(SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
<!-- 配置Hibernate的SessionFactory实例:通过Spring提供的LocalSessionFactoryBean进行配置 -->
<
bean
id
=
"sessionFactory"
class
=
"org.springframework.orm.hibernate4.LocalSessionFactoryBean"
>
<!-- 配置数据源属性 -->
<
property
name
=
"dataSource"
ref
=
"dataSource"
></
property
>
<!-- 配置Hibern配置文件的位置及名称 -->
<!--
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
-->
<
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
=
"com/spring/hibernate/entity/*.hbm.xml"
></
property
>
</
bean
>