• 第五节 事务[注解方式]


    什么要使用连接池?

    连接数据库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的官方文档,很有收获!慢慢看,耐住性子的看!

       

       

       

       

       

       

       

       

       

       

       

       

       

  • 相关阅读:
    Struts2中There is no Action mapped for namespace错误解决方法
    String字符串常量池简介
    main方法中参数"String[ ] args"详解
    自定义异常基本用法
    finally关键字执行的底层原理
    Linux环境下安装mysql5.6(二进制包不是rpm格式)
    finalize关键字小结
    "=="和equals小结
    super关键字小结(构造方法的执行是不是一定会创建对象?)
    冒泡排序
  • 原文地址:https://www.cnblogs.com/pangxiansheng/p/5451118.html
Copyright © 2020-2023  润新知