day04_SSM技术之JDBC&声明式事务

JdbcTemplate

一 概念

1. Spring提供的一个持久化框架(模板),其核心对象JdbcTemplate(类似之前使用的DBUtils)

二 JdbcTemplate使用基本步骤

1. 导入jar包(5[spring核心]+3[jdbcTemplate]+2[德鲁伊+数据库驱动])
2. 配置文件
    * 编写db.properties(属性文件)
    * applicationContext.xml
        - 加载外部属性文件
        - 装配德鲁伊数据源
        - 装配JdbcTemplate对象
3. 使用JdbcTemplate中的核心方法,进行DRUD操作

applicationContext.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:context="http://www.springframework.org/schema/context"
       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.xsd">


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

    <!--    组件扫描-->
    <context:component-scan base-package="com.atguigu.spring"/>



    <!--    加载外部属性文件-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!--    装配数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
    </bean>
    <!--    装配JdbcTemplate对象
                javaWweb
                    Databaseutil->getConnection()  closeConnection()  [数据源]
                    BaseDao->CRUD通用方法
    -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--指定数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>



</beans>

三 JdbcTemplate的持久化方法(CRUD)

1. update()
    * 增删改的通用方法,常用构造方法如下:
        - update(String sql,Object... args)
2. batchUpdate()
    * 批处理增删改的通用方法,常用构造方法如下:
        - batchUpdate(String sql,List<Object[]> batchArgs)
3. queryForObject():获取单个数据的通用方法,常用其中两种形式
    * 获取单个对象(bean)
        - queryForObject(String sql,RowMapper rm):查询单个对象,无参数
          RowMapper<T> rm = new BeanPropertyRowMapper<>(T.class);
         - queryForObject(String sql,RowMapper rm,Object... args):查询单个对象,有参数
    * 获取当个数值(int count,double price)
        - queryForObject(String sql,Class type):查询单个数值,无参数
        - queryForObject(String sql,Class type,Object... args):查询单个数值,有参数
4. query()
    * 查询多个bean对象的通用方法,常用其构造方法如下:
        - query(String sql,RowMapper rm):查询多个bean对象,无参数
        - query(String sql,RowMapper rm,Object... args):查询多个bean对象,有参数
package com.atguigu.spring.test;

import com.atguigu.spring.bean.Dept;
import com.atguigu.spring.dao.DeptDao;
import com.atguigu.spring.dao.DeptDaoImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Study hard Java's Tang
 * @create 2020-03-11 9:36
 */
public class Demo {

    /**
     获取jdbcTemplate对象
     */

    //获取容器对象
    ApplicationContext context =
            new ClassPathXmlApplicationContext("applicationContext_jdbcTemplate.xml");
    //从容器对象中,获取jdbcTemplate对象
    JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);



    @Test
    public void testGetJdbcTemplate(){
        System.out.println("jdbcTemplate = " + jdbcTemplate);
    }

    /**
     测试update()方法,添加dept
     */
    @Test
    public void testUpdate(){
        //写sql语句
        String sql = "insert into depts(name) value(?) ";

        jdbcTemplate.update(sql, "气氛组");
    }

    /**
     测试批量处理,新增
     */
    @Test
    public void testBatchUpdate(){
        String sql = "insert into depts(name) value(?)";

        List<Object[]> list = new ArrayList<>();
        list.add(new Object[]{"拆迁队"});
        list.add(new Object[]{"砸钱队"});

        jdbcTemplate.batchUpdate(sql, list);
    }

    /**
     测试queryForObject,查询单个值
     */
    @Test
    public void testQuerySingleValue(){

        String sql = "select count(*) from depts";

        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);

        System.out.println("数据库部门数量count = " + count);
    }

    /**
     测试queryForObject,查询单个bean对象
     * BeanPropertyRowMapper
     * 将数据库查询结果集,与javaBean中的属性关联映射
     */
    @Test
    public void testQuerySingleBean(){
        String sql = "select id,name from depts where id = ?";

        RowMapper<Dept> rm = new BeanPropertyRowMapper<>(Dept.class);

        Dept detp = jdbcTemplate.queryForObject(sql, rm, 1);
        System.out.println(detp);
    }

    /**
     测试query()方法,查询多个bean对象
     */
    @Test
    public void testQueryObjects(){
        String sql = "select id,name deptName from depts";

        RowMapper<Dept> rm = new BeanPropertyRowMapper<>(Dept.class);

        List<Dept> query = jdbcTemplate.query(sql, rm);

        for (Dept detp : query) {
            System.out.println(detp);
        }

    }

    /**
     测试Dao(jdbcTemplate)
     */
    @Test
    public void testDao(){

        DeptDao deptDao = context.getBean("deptDaoImpl", DeptDaoImpl.class);

        Dept deptById = deptDao.getDeptById(1);

        System.out.println("deptById = " + deptById);


    }
}

四 使用JdbcTemplate实现Dao模式

Spring声明式事务管理

一 回顾事务基础知识

* 事务四大特性(ACID)
    - 原子性(atomicity):不可再分
    - 一致性(consistency):满足业务规则的一致性状态,要么同时提交,要么通知回滚
    - 隔离性(isolation):并发执行过程中不会互相干扰
    - 持久性(durability):对数据的更改,永久的保存

二 Spring中支持的事务管理

applicationContext_tx.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: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.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">



    <!--    组件扫描-->
    <context:component-scan base-package="com.atguigu.spring"/>



    <!--    加载外部属性文件-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>



    <!--    装配数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
    </bean>



    <!--    装配JdbcTemplate对象
                javaWweb
                    Databaseutil->getConnection()  closeConnection()  [数据源]
                    BaseDao->CRUD通用方法
    -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--指定数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>



<!--    装配数据源事务管理器:DataSourceTransactionManager-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>



<!--    启用事务注解-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>


</beans>
1 javaweb阶段事务管理不够优化 -> 书城项目 -> 去结账 -> (1. 生成订单2.生成订单详情3.减库存)
2 Spring编程式事务管理
    ①获取数据库连接Connection对象
    ②取消事务的自动提交
    ③执行操作
    ④正常完成操作时手动提交事务
    ⑤执行失败时回滚事务
    ⑥关闭相关资源
    * 问题:业务代码与事务管理代码相耦合,代码较分散&混乱。
    * 解决:使用AOP框架AspectJ,将事务管理代码(非核心业务代码)先提取到切面,再动态通知到核心业务                        代码中。
          注意:这种管理事务的方式,称之为声明式事务管理。
3 Spring声明式事务管理(推荐使用)
    * demo演示问题:当余额不足时,余额修改失败,但库存修改成功(违背了事务的一致性&原子性..)
    * 使用spring声明式事务管理(解决)步骤
        1. 加载外部属性文件
        2. 装配德鲁伊数据源:DruidDataSource
        3. 装配数据源事务管理器:DataSourceTransactionManager
        4. 启用事务注解
              <tx:annotation-driver transaction-manager="" >
        5. 在需要事务的业务上,添加注解:@Transactional
4 事务属性
    * propagation(事务传播行为),默认值:Propagation.REQUIRED
    * 一个事务(a)调用另一个事务(b)时,此时当前事务如何使用事务机制。
    * 属性值

          Propagation.REQUIRED:如果当前存在事务,就使用当前事务。
          如果当前不存在事务,就新建一个事务,去使用。

          Propagation.REQUIRES_NEW:无论当前是否存在事务,都必须创建新事物,去使用。
          如果当前存在事务,会将当前事务挂起。
          之后,等待新建事务执行结束后,再执行挂起事务。
    * isolation(事务隔离级别),默认值:-1(没有设置隔离级别)
        * 读未提交(1),存在问题:脏读
        * 读已提交(2),存在问题:不可重复读(建议使用)
        * 可重复读(4),存在问题:幻读(建议使用)
        * 串行化(8),存在问题:效率极低。
    * readOnly(事务只读)
        * true:查询功能时使用
        * false:默认值
    * timeout(事务超时)
          默认值:-1,不设置超时时间
          可以设置int毫秒数,在指定毫秒后,强制事务回滚。(释放事务资源)
    * rollbackFor| rollBackForClassName| noRollbackFor| noRollbackForClassName(事务异常回滚|事务异常不回滚)
        - 默认:事务遇到runtimeException&Error时回滚,遇到编译时异常不回滚。
/**
     * 去结账
     * @param username
     * @param isbns:书编号的集合
     */
    @Transactional
    @Override
    public void checkOut(String username, List<String> isbns) {
        /**
         * 业务:余额能买几本书,就允许顾客买几本。
         */
        for (String isbn : isbns) {
            bookService.purchase(username, isbn);
        }
    }
/**
     * 买书->查询book价格->修改库存->修改余额
     * @param username
     * @param isbn
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void purchase(String username, String isbn) {
        //查询book价格
        Integer price = bookDao.findBookPriceByIsbn(isbn);

        //修改库存
        bookDao.updateBookStock(isbn);

        //修改余额
        bookDao.updateUserAccount(username,price);

    }

三 基于xml方式配置声明式事务


            <!-- 配置事务切面 -->
                    <aop:config>
                        <aop:pointcut expression="execution(* com.atguigu.tx.component.service.BookShopServiceImpl.purchase(..))"
                            id="txPointCut"/>


                        <!-- 将切入点表达式和事务属性配置关联到一起 -->
                        <aop:advisor advice-ref="myTx" pointcut-ref="txPointCut"/>


                    </aop:config>
    
                    <!-- 配置基于XML的声明式事务  -->
                    <tx:advice id="myTx" transaction-manager="transactionManager">


                        <tx:attributes>


                            <!-- 设置具体方法的事务属性 -->
                            <tx:method name="find*" read-only="true"/>
                            <tx:method name="get*" read-only="true"/>


                            <tx:method name="purchase"
                                isolation="READ_COMMITTED"
                                no-rollback-for="java.lang.ArithmeticException,java.lang.NullPointerException"
                                propagation="REQUIRES_NEW"
                                read-only="false"
                                timeout="10"/>


                        </tx:attributes>
                    </tx:advice>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值