第五节 事务[注解方式]

什么要使用连接池?

连接数据库5步骤:

1. 加载驱动类

2.获取连接

3.创建执行SQL语句的对象[Statement和PrepareStatement(预处理方式,问号的索引值是从1开始)]

4.获取结果集对象

5.关闭资源[有序的关闭]

连接池就是预先建立好一些连接,放置到一个容器当中,当你使用的时候,从改缓存池当中取,用完之后需要归还

[如何去自己实现连接池?]

都是使用开源的连接池!

----针对于JDBC[驱动类,访问路径,用户名,密码]

   

当你去使用别人的项目或者你要把项目发布到服务器端时候,需要注意一下几个问题:

版本!

如果有疑问请查看: 博客文档

还有如果是一个web项目,注意修改为自己的Tomcat版本

----------------------------------------

<?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:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">

<!-- 启动Spring注解 -->

<context:annotation-config/>

<!-- 扫描 -->

<context:component-scan base-package="com.shxt"/>

<!-- 加载外部的属性文件 -->

<context:property-placeholder location="classpath:/jdbc.properties" />

<!-- 配置数据源 -->

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"

destroy-method="close">

<property name="driverClassName" value="${jdbc.driverClassName}" />

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

   

<!-- 配置初始化大小、最小、最大 -->

<property name="initialSize" value="3" />

<!-- 最大空闲时,当经过一个高峰之后,连接池可以将一些用不到的连接释放,一直减少到maxIdle为止 -->

<property name="minIdle" value="5" />

<!-- 连接池的最大值 -->

<property name="maxActive" value="20" />

<!-- 配置获取连接等待超时的时间 -->

<property name="maxWait" value="60000" />

<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->

<property name="timeBetweenEvictionRunsMillis" value="60000" />

<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->

<property name="minEvictableIdleTimeMillis" value="300000" />

   

<property name="validationQuery" value="SELECT 'x'" />

<property name="testWhileIdle" value="true" />

<property name="testOnBorrow" value="false" />

<property name="testOnReturn" value="false" />

   

</bean>

<!-- 使用JDBC连接数据库,进行测试 -->

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

<property name="dataSource" ref="dataSource"/>

</bean>

 

 

 

</beans>

  

   

测试的项目,通过模拟情况进行了解!

项目经理,进行调研:

1.买书,一次有且只能买一本书,不支持现金,都是通过书店发账号--充值,问买书的过程需要完成那些组成?

{书属性: ISBN-价钱} {库存: ISBN-数量} {用户: 账号--金钱}

A.通过你的账号,查询你的余额是多少?

B.库存 减少

C. 余额需要减去价格

数据访问层:

package com.shxt.dao;

   

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

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.stereotype.Repository;

@Repository // --数据访问层,使用注解@Repository ,默认的ID为: bookShopDaoImpl

public class BookShopDaoImpl implements IBookShopDao {

@Autowired //

private JdbcTemplate jdbcTemplate;

   

/**

* 通过书的编号获取书的价格

*/

@Override

public int findBookPriceByIsbn(String isbn) {

String sql = "SELECT price FROM tx_book WHERE isbn = ?";

return jdbcTemplate.queryForObject(sql, Integer.class, isbn);

}

/**

* 更新库存

* @throws RuntimeException

*/

@Override

public void updateBookStock(String isbn) throws RuntimeException {

String sql = "UPDATE tx_book_stock SET stock = stock -1 WHERE isbn = ?";

jdbcTemplate.update(sql, isbn);

}

/**

* 更新用户卡里面的余额

* @throws RuntimeException

*/

@Override

public void updateUserAccount(String account, int price) throws RuntimeException {

//简单判断

String sql = "UPDATE tx_user SET balance = balance - ? WHERE account = ?";

jdbcTemplate.update(sql, price, account);

}

   

   

}

   

业务逻辑层

@Service //

public class BookShopServiceImpl implements IBookShopService {

private IBookShopDao bookShopDao; 

@Autowired

public void setBookShopDao(IBookShopDao bookShopDao) {

this.bookShopDao = bookShopDao;

}

   

/**

* 模拟买书的业务包含3步骤

*/

public void purchase(String account, String isbn) throws RuntimeException {

// 1.通过ISBN查询价格

int price = this.bookShopDao.findBookPriceByIsbn(isbn);

// 2.更新库存

this.bookShopDao.updateBookStock(isbn);

// 3.更新余额

this.bookShopDao.updateUserAccount(account, price);

}

   

}

   

修改DAO层代码: [加入简单的判断,使用的runtimeException]

package com.shxt.dao;

@Repository //

public class BookShopDaoImpl implements IBookShopDao {

@Autowired //

private JdbcTemplate jdbcTemplate;

   

/**

* 通过书的编号获取书的价格

*/

@Override

public int findBookPriceByIsbn(String isbn) {

String sql = "SELECT price FROM tx_book WHERE isbn = ?";

return jdbcTemplate.queryForObject(sql, Integer.class, isbn);

}

/**

* 更新库存

* @throws RuntimeException

*/

@Override

public void updateBookStock(String isbn) throws RuntimeException {

String sql = "select stock from tx_book_stock where isbn = ?";

Integer stock = jdbcTemplate.queryForObject(sql, Integer.class, isbn);

if(stock==0){

throw new RuntimeException("库存不足,请等待.....");

}

sql = "UPDATE tx_book_stock SET stock = stock -1 WHERE isbn = ?";

jdbcTemplate.update(sql, isbn);

}

/**

* 更新用户卡里面的余额

* @throws RuntimeException

*/

@Override

public void updateUserAccount(String account, int price) throws RuntimeException {

//简单判断

String sql = "select balance from tx_user where account = ?";

Integer balance = jdbcTemplate.queryForObject(sql, Integer.class, account);

if(balance<price){

throw new RuntimeException("您卡内余额不足,请充值");

}

sql = "UPDATE tx_user SET balance = balance - ? WHERE account = ?";

jdbcTemplate.update(sql, price, account);

}

   

} 

   

这样的判断我们还是无法解决买书中出现的问题,这样我们就需要告诉我们的程序,这个方法或者这个类下的方法是一个事务方法,它需要使用事务管理器对该方法进行事务管理,确保数据的完整性和一致性

<!-- 1.配置事务管理器 完成数据的完整性和一致性

MyBatis 应使用JDBC的事务管理器

-->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

 

<!-- 启动事务注解,可以标注在类或者方法上 -->

<tx:annotation-driven transaction-manager="transactionManager" />

package com.shxt.service;

   

@Service //补充说明,这默认id是什么( )

public class BookShopServiceImpl implements IBookShopService {

private IBookShopDao bookShopDao;

   

@Autowired

public void setBookShopDao(IBookShopDao bookShopDao) {

this.bookShopDao = bookShopDao;

}

   

/**

* 模拟买书的业务包含3步骤 什么是事务?

* 事务[买书业务]逻辑由多个动作组成了一个工作单元[买书的业务],3步骤组成,有一个步骤错了,那么应该都不起作用

* ACID概念 必须会

* @throws Exception

*

*

*/

@Transactional //告诉上面的事务管理器,我这个方法是事务方法

public void purchase(String account, String isbn) throws RuntimeException {

// 1.通过ISBN查询价格

int price = this.bookShopDao.findBookPriceByIsbn(isbn);

// 2.更新库存

this.bookShopDao.updateBookStock(isbn);

// 3.更新余额

this.bookShopDao.updateUserAccount(account, price);

}

   

}

  

: 如果使用try…catch进行捕获的话,应该如何处理,请补充答案[ ]

需要掌握的属性有: noRollbackFor RollbackFor readonly等属性,不需要要会

   

   

   

   

   

如果买两本书: 模拟情况,我们需要测试事务的传播性

   

买两本书的业务代码如下:

package com.shxt.service;

   

@Service

public class BookMoreServiceImpl implements IBookMoreService {

@Autowired

private IBookShopService bookShopService;

   

@Override

@Transactional(propagation=Propagation.REQUIRED)//标注为事务方法,这个传播性为默认值

public void playMore(String account, String... isbns) {

for (String isbn : isbns) {

bookShopService.purchase(account, isbn);

}

   

}

   

}

当一个方法[purchase]被另一个事务方法[playMore]调用{有标注注解哟!}的时候,默认有延续功能,如果所示

  

package com.shxt.service;

   

@Service //

public class BookShopServiceImpl implements IBookShopService {

private IBookShopDao bookShopDao;

   

@Autowired

public void setBookShopDao(IBookShopDao bookShopDao) {

this.bookShopDao = bookShopDao;

}

   

/**

* 注意这里没有标注该方法为事务方法

*

*/

   

public void purchase(String account, String isbn) throws RuntimeException {

// 1.通过ISBN查询价格

int price = this.bookShopDao.findBookPriceByIsbn(isbn);

// 2.更新库存

this.bookShopDao.updateBookStock(isbn);

// 3.更新余额

this.bookShopDao.updateUserAccount(account, price);

}

   

}

  

   

另一种情况描述:

package com.shxt.service;

   

@Service

public class BookMoreServiceImpl implements IBookMoreService {

@Autowired

private IBookShopService bookShopService;

   

@Override

@Transactional(propagation=Propagation.REQUIRED)//标注为事务方法,这个传播性为默认值

public void playMore(String account, String... isbns) {

for (String isbn : isbns) {

bookShopService.purchase(account, isbn);

}

   

}

   

}

  

package com.shxt.service;

   

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

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Propagation;

import org.springframework.transaction.annotation.Transactional;

   

import com.shxt.dao.IBookShopDao;

   

@Service //

public class BookShopServiceImpl implements IBookShopService {

private IBookShopDao bookShopDao;

   

@Autowired

public void setBookShopDao(IBookShopDao bookShopDao) {

this.bookShopDao = bookShopDao;

}

   

/**

* 模拟买书的业务包含3步骤 什么是事务?业务逻辑 由多个工作的任务,组成了一个工作单元 买书的业务,3步骤组成,有一个步骤错了,不起作用

* ACID概念

*

* @throws RuntimeException

*

*

*/

@Transactional(propagation=Propagation.REQUIRES_NEW)

public void purchase(String account, String isbn) throws RuntimeException {

// 1.通过ISBN查询价格

int price = this.bookShopDao.findBookPriceByIsbn(isbn);

// 2.更新库存

this.bookShopDao.updateBookStock(isbn);

// 3.更新余额

this.bookShopDao.updateUserAccount(account, price);

}

   

}

  

   

   

关于这段文字的描述: 请参考PPT的详细内容和Spring的官方文档,很有收获!慢慢看,耐住性子的看!

   

   

   

   

   

   

   

   

   

   

   

   

   

posted on 2016-05-01 20:43  胖先生  阅读(248)  评论(2编辑  收藏  举报