1. 程式人生 > >SSH框架學習之Spring ---- 4、Spring的事務管理和jdbcTemplate

SSH框架學習之Spring ---- 4、Spring的事務管理和jdbcTemplate

本節講的是spring對dao層的封裝,之前可能有更好的做法,但是要知道spring也提供了這種技術。

本節的主要內容是:

1、spring的jdbcTemplate操作(實現事務crud操作)

2、spring配置連線池
(1)配置c3p0連線池
(2)service和dao注入操作

3、spring事務管理
(1)事務的概念
(2)spring進行事務的api
(3)spring進行事務配置

一、使用jdbcTemplate對jdbc進行封裝(需要自己建立表)

第一步:匯入jar包,注意還需匯入jdbc驅動的jar包
在這裡插入圖片描述
第二步:建立物件,設定資料庫資訊
在這裡插入圖片描述
第三步:建立jdbcTemole物件,設定資料來源

在這裡插入圖片描述
第四步:呼叫jdbcTemplate的介面,進行資料庫操作crud

code:JdbcTemplateDemo.class

package com.test.dao;

import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

public class JdbcTemplateDemo {
    @Test
    public void test() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///spring_day03");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        String sql = "insert into account values(?,?,?)";
        int row = jdbcTemplate.update(sql,3,"lucy",100);
        System.out.println(row);
    }
}

效果是:表中多了一項lucy 100。

二、案例實戰:spring配置連線池和dao使用jdbcTemplate

本場案例:完成銀行轉賬的操作,在Service實現業務邏輯,呼叫Dao,Dao是封裝了JdbcTemplate的對資料庫操作。

知識回顧

  • service層又叫業務邏輯層, 比如說小王多1000,小馬少1000.
  • 而dao層不涉及業務邏輯,僅僅封裝對資料庫的操作(crud)

什麼是連線池?

一般我們在專案中操作資料庫時,都是每次需要操作資料庫就建立一個連線,操作完成後釋放連線。因為jdbc沒有保持連線的能力,一旦超過一定時間沒有使用(大約幾百毫秒),連線就會被自動釋放掉。而每次新建連線都需要140毫秒左右的時間,所以耗費時間比較多。若使用C3P0連線池來池化連線,隨時取用,則平均每次取用只需要10-20毫秒。這在高併發隨機訪問資料庫的時候對效率的提升有很大幫助。

使用步驟

第一步:匯入jar包
在這裡插入圖片描述
第二步:建立OrdersService.class方法實現業務邏輯,在這個類中呼叫Dao層的方法

code:OrdersService.class
public class OrdersService {
    public void setOrdersDao(OrdersDao ordersDao) {
        this.ordersDao = ordersDao;
    }
    private OrdersDao ordersDao;
    // 呼叫dao
    //業務邏輯,寫轉賬業務
    public void accountMoney() {
        ordersDao.addMoney();
        ordersDao.lessMoney();
    }
}

第三步:建立OrderDao.class,封裝了lessMoney()和addMoney(),本質上是對jdbcTemplate的封裝

code:OrdersDao.class

//dao層完成對資料庫的編寫
public class OrdersDao {
    // 注入jdbcTemplate
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    // 少錢的方法
    public void lessMoney() {
        System.out.println("少錢執行");
        String sql = "update account set salary=salary-? where username=?";
        jdbcTemplate.update(sql, 1000, "xiaowang");
    }
    // 多錢的方法
    public void addMoney() {
        System.out.println("多錢執行");
        String sql = "update account set salary=salary+? where username=?";
        jdbcTemplate.update(sql, 1000, "xiaoma");
    }
}

第四步:配置Spring的核心配置檔案,在配置檔案中,建立連結和資料來源dataSource,完成Service和Dao物件的建立。

注意:這裡其實是把dataSource用IOC創建出來。

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

    <!-- 配置c3p0連線池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 注入屬性值 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_day03"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    
    <!--service中注入dao-->
    <bean class="tx.itcast.service.OrdersService" id="ordersService">
        <property name="ordersDao" ref="ordersDao"></property>
    </bean>
    <!--dao注入jdbcTemplate物件-->
    <bean class="tx.itcast.dao.OrdersDao" id="ordersDao">
        <property name="jdbcTemplate" ref="jdbcTemplate">
        </property>
    </bean>
    <!--jdbc模板物件注入dataSouce-->
    <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        <!--原始碼中有datesource的物件,所以要注入連線池提供的dataSourse-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

注意: 這裡和第一節的區別在於,建立DataSource方式的不同,第一節是

DriverManagerDataSource dataSource = new DriverManagerDataSource();

而這裡是通過連線池建立的dataSource。

第五步:呼叫Service物件,測試結果

  @Test
    public void test() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("beanTx.xml");
        OrdersService service = (OrdersService) context.getBean("ordersService");
        service.accountMoney();
    }
結果:資料庫中一個人少錢,一個人多錢,測試完畢!

三、本節核心:Spring的事務管理

上面的案例,完成後,不要高興的太早,我們並沒有對事務進行隔離,因此會發生事務的一系列錯誤,例如在A->B轉賬過程中,A賬戶-1000,接著斷電了,而B賬戶還未+1000,程式就結束,本小節要解決這個問題。

code:OrdersService.class
public class OrdersService {
    public void setOrdersDao(OrdersDao ordersDao) {
        this.ordersDao = ordersDao;
    }
    private OrdersDao ordersDao;
    // 呼叫dao
    //業務邏輯,寫轉賬業務
    public void accountMoney() {
        ordersDao.addMoney();
        //發生錯誤
        int i = 8/0;
        ordersDao.lessMoney();
    }
}

3.1 如何解決上訴問題 —> Spring的事務管理

spring封裝了事務管理的方法,我們只需把它增強到需要管理的方法即可,在本次案例中,增強到OrdersDao的方法裡。

code:beanTx.xml 在上一小節的基礎上額外新增的程式碼
<!--事務管理部分-->
    <!--第一步:配置事務管理器-->
    <bean id="DataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--對事務管理器的屬性進行注入
            dataSource
        -->
            <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--第二步: 配置事務增強
        規定一個名稱
        指定針對的事務管理器:DataSourceTransactionManager
    -->
    <tx:advice id="txadvice" transaction-manager="DataSourceTransactionManager">
        <!--做事務操作-->
        <tx:attributes>
            <!--設定進行事務操作的方法,匹配規則
                目的是規定對哪些方法進行增強
                propagation:隔離級別
            -->
            <tx:method name="account*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--第三步:配置切面-->
    <aop:config>
        <!--切入點-->
        <aop:pointcut id="pointcut1" expression="execution(* tx.itcast.service.OrdersService.*(..))"
        <!--切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
    </aop:config>

3.4 驗收

增加了上面的程式碼後,如果在事務處理過程中,發生了異常,那麼會自動回滾,保證了事務的一致性。

三、用註釋的方式實現事務管理

上面的程式碼太複雜了,貼心的Spring又支援註釋的方式來替代配置了,具體操作看程式碼

第一步:在beanTx.xml中,新增下面的程式碼

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

    <!--事務管理部分-->
    <!--第一步:配置事務管理器-->
    <bean id="DataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--對事務管理器的屬性進行注入
            dataSource
        -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--第二步:開啟事務註解-->
    <tx:annotation-driven transaction-manager="DataSourceTransactionManager"/>
 
	<!-- 下面的是第一節的內容 -->


    <!-- 配置c3p0連線池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 注入屬性值 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_day03"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--dao注入jdbcTemplate物件-->
    <bean class="tx.itcast.dao.OrdersDao" id="ordersDao">
        <property name="jdbcTemplate" ref="jdbcTemplate">
        </property>
    </bean>
    <!--service中注入dao-->
    <bean class="tx.itcast.service.OrdersService" id="ordersService">
        <property name="ordersDao" ref="ordersDao"></property>
    </bean>
    <!--jdbc模板物件-->
    <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        <!--原始碼中有datesource的物件,所以要注入連線池提供的dataSourse-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

第二步:在要增強事務管理功能的類上面加上註解

在這裡插入圖片描述

這樣能達到的效果也是一樣的!