第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Spring 的事務管理器

1. 前言

各位同學大家好,又輪到我的時間了。

在上一小節(jié)咱們已經(jīng)可以使用 Spring 集成了 Jdbc Template,并且實現(xiàn)了數(shù)據(jù)的基本操作基本使用,那么本小節(jié)我們在操作數(shù)據(jù)的基礎之上,講解一下 Spring 中的事務處理。

其實我們在前面的 AOP 相關的小節(jié)中,已經(jīng)實現(xiàn)了對事務的控制。只不過呢,之前的事務控制是由我們手動創(chuàng)建的類來管理事務。嘿嘿嘿,代碼略顯簡單,功能稍許單一。

而今天呢,我們使用 Spring 框架提供的事務管理器,并通過 AOP 配置切入點來管理事務。那么它能否給我們帶來一些驚喜呢?來吧,大家。一起進入今天的課程…

課程回顧

首先我們回顧一下事務控制的實現(xiàn)要求:

1. 提供一個類,作為切面用于處理事務的開啟,提交和回滾。

2. 通過 xml 文件或者注解來配置 AOP,表述切入點和使用的切面類。

本小節(jié)帶著大家分別使用 xml 文件的方式,和注解的方式實現(xiàn) Spring 框架對于事務的控制。

2. 實例演示

2.1 思路介紹

Spring 的事務管理器類

Spring 框架本身已經(jīng)充分考慮了對事物的支持,所以我們完全不必像之前一樣自定義類來實現(xiàn)對事物的控制。Spring 已經(jīng)抽象了一整套的事務機制,而作為開發(fā)人員根本不必了解底層的事務 API,

一樣可以通過代碼管理數(shù)據(jù)庫的事務。頂層的事務管理器抽象就是 PlatformTransactionManager, 它為事務管理封裝了一組獨立于技術的方法。

而本示例就采用 Spring 提供的管理器實現(xiàn)類,來替換掉之前我們自己編寫的事務控制工具類。

2.2 工程搭建

1. 創(chuàng)建工程
圖片描述
2. 引入依賴

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
		<!-- Spring jdbc 使用的依賴-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
     	<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
   		 </dependency>
    </dependencies>

3. 準備代碼
實體類代碼

/**
 * 賬戶的實體類
 */
public class Account implements Serializable {
    //數(shù)據(jù)id
    private Integer id;
    //賬號編碼
    private String accountNum;
    //賬號金額
    private Float money;
}

持久層接口代碼

/**
 * 賬戶的持久層接口
 */
public interface IAccountDao {

    /**
     * 根據(jù)Id查詢賬戶
     * @param accountId
     * @return
     */
    Account findAccountById(Integer accountId);

    /**
     * 保存賬戶
     * @param account
     */
    void saveAccount(Account account);

    /**
     * 更新賬戶
     * @param account
     */
    void updateAccount(Account account);


}

持久層實現(xiàn)類代碼

/**
 * 賬戶的持久層實現(xiàn)類
 */
@Repository
public class AccountDaoImpl implements IAccountDao {
    //jdbc模板類屬性
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //根據(jù)id查找
    public Account findAccountById(Integer accountId) {
        List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }

    public void saveAccount(Account account) {
        jdbcTemplate.update("insert into account  values(?,?,?)",
                account.getId(),account.getAccountNum(),account.getMoney());
    }

    public void updateAccount(Account account) {
        jdbcTemplate.update("update account set accountnum=?,money=? where id=?",account.getAccountNum(),account.getMoney(),account.getId());
    }
}

業(yè)務層接口代碼

/**
 * @Auther: wyan
 */
public interface UserService {

    /**
     * 賬戶轉賬
     * @param fromId toId
     */
    public void transMoney(Integer fromId, Integer toId, Integer money);

}

業(yè)務層實現(xiàn)類代碼

/**
 * @Auther: wyan
 * @Description:
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private IAccountDao accountDao;

    public void transMoney(Integer fromId, Integer toId, Integer money) {
        Account fromAccount = accountDao.findAccountById(fromId);
        Account toAccount = accountDao.findAccountById(toId);
        //原始賬號減錢
        fromAccount.setMoney(fromAccount.getMoney()-money);
        accountDao.updateAccount(fromAccount);
        //拋出異常
        int i=1/0;
        //轉賬賬號加錢
        toAccount.setMoney(toAccount.getMoney()+money);
        accountDao.updateAccount(toAccount);
    }
}

Tips: 我們再給原始賬號減掉錢后,執(zhí)行保存。然后在這里會出現(xiàn)個異常,就是為了測試事務的特性,所以手動加了個除 0 的代碼。

4. 配置文件

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

    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置數(shù)據(jù)源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///transmoney"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!--包路徑掃描-->
    <context:component-scan base-package="com.offcn"></context:component-scan>
    <!--事務管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--事務的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="del*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!--切面的配置-->
    <aop:config>
        <aop:pointcut id="pt" expression="execution(* com.offcn.service.*.*(..))"/>
        <aop:advisor pointcut-ref="pt" advice-ref="txAdvice" />
    </aop:config>

</beans>

此處需要注意:

? context:component-scan:掃描的節(jié)點路徑為包含 service 和 dao 兩個子目錄的父級目錄;

? transactionManager: 此節(jié)點作用就是初始化 Spring 框架提供的事務管理器的實現(xiàn)類;

? tx:advice: 此節(jié)點的作用是配置切面的通知,因為之前我們的切面類是自定義的,這里使用的是 Spring 提供的事務管理器類作為切面,那么針對什么方法需要做增強呢,在此節(jié)點配置,可以看得出來:以 save、del、update 開頭的方法都會支持事務,而 find 開頭的方法,指定的是只讀。

? aop:config: 此節(jié)點就是 AOP 的相關配置節(jié)點了,將切入點和通知整合到一起,同以前的項目差別不大。這里可以看到:切入點規(guī)則是針對 service 下面的所有類所有方法任意參數(shù)做增強。通知使用的就是我們上面配置過的 tx:advice 節(jié)點。

5. 測試代碼

public class AccountServiceTest {

    public static void main(String[] args) {
        //1.獲取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.獲取業(yè)務對象
        UserService userService = ac.getBean(UserService.class);
        //3.從id為1的賬號轉成1000到2賬號
        userService.transMoney(1,2,1000);
        System.out.println("轉賬完成..");
    }
}

6. 測試結果:
圖片描述
ok, 大家,控制臺如愿以償打印了異常的堆棧信息,但是這個不是目的,哈哈哈。目的是在程序執(zhí)行發(fā)生異常的情況下,數(shù)據(jù)的數(shù)據(jù)不會錯亂。我們可以看見數(shù)據(jù)庫數(shù)據(jù)并沒有發(fā)生改變。

3. 總結

Spring 對于事務的控制,我們今天就到這里。通過本小節(jié),我們也能體會到,使用 Spring 對事務控制還是非常簡單的。無非以下三個注意事項:

  1. 配置 Spring 框架提供的事務管理器;
  2. 配置控制事務使用的通知;
  3. 配置切面將通知與切入點結合即可。

沒有比人更高的山… 沒有比腳更長的路… 繼續(xù)加油哦!