Spring入門(三)— AOP註解、jdbc模板、事務

来源:https://www.cnblogs.com/gdwkong/archive/2018/02/19/8453163.html
-Advertisement-
Play Games

本文主要介紹Spring中AOP註解,jdbc模板,事務的基本使用。 ...


一、AOP註解開發

  1. 導入jar包

    aop聯盟包、 aspectJ實現包 、 spring-aop-xxx.jar 、 spring-aspect-xxx.jar

  2. 導入約束

    aop約束

  3. 托管擴展類和被擴展類

  <!-- 要做AOP, 一定要托管擴展類和被擴展類 -->
   <bean id="us" class="com.pri.service.impl.UserServiceImpl"></bean>
   <bean id="logger" class="com.pri.util.Logger"></bean>   
也可以使用註解來托管這兩個類 。  @Component
  1. 在擴展出來的功能類身上和方法上打註解

@Aspect //這個註解,是和aop有關,用於表示該類是一個功能擴展類,專門用來做增強的。
public class Logger {
    @Before("execution(* com.pri.service.impl.*.*(..))")
    public void log(){
        System.out.println("輸出日誌了~~~!");
    }
}

二、 Jdbc模板

  • 為什麼spring也要提供jdbc模板呢?

spring是屬於service層的框架, 它所處的位置比較尷尬,並且它想讓自己更受程式員的喜愛。 除了能夠做好自己的核心 IOC & AOP , 它還對前後兩個框架都提供了支持。 spring其實對dao層的大部分技術有提供模板支持 。

1. jdbc模板的入門

public void testDemo(){
        
        //數據源,連資料庫。 連什麼類型的數據, 哪個庫, 賬號 & 密碼
        DriverManagerDataSource dataSource  =new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///stus");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
​
        //1. 創建jdbc模板
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        
        String sql = "insert into t_user values(null , ? , ? )";
        
        //2. 執行添加操作,其實它的用法和以前的queryrunner一樣。
        jdbcTemplate.update(sql , "66666","zhangsan");
}

2. crud操作

  • insert

String sql = "insert into t_user values (null , ? , ?)";
jdbcTemplate.update(sql, "heima24","6666");
  • delete 

 @Test
 public void testDelete(){
      //3. 執行添加操作
      String sql = "delete from t_user where uid = ?";
      jdbcTemplate.update(sql, 11);
 }
  • udpate

@Test
public void testUpdate(){
      //3. 執行添加操作
      String sql = "update t_user set password=? where uid=?";
      jdbcTemplate.update(sql, "888",11);
}
  • findCount

@Test
public void testFindCount(){
     //3. 執行添加操作
     String sql = "select count(*) from t_user";
     int count = jdbcTemplate.queryForObject(sql, Integer.class);
     System.out.println("count="+count);
}
  • findObject

@Test
public void testFindObject(){
       //3. 執行添加操作
      String sql = "select * from t_user where uid = ?";
      User user = jdbcTemplate.queryForObject(sql,new MyRowMapper()  , 10);
      System.out.println("user="+user);
}
  • findList

@Test
public void testFindList(){
     //3. 執行添加操作
     String sql = "select * from t_user ";
     List<User> user = jdbcTemplate.query(sql, new MyRowMapper());
     System.out.println("user="+user);
}

查詢要求我們手動封裝class MyRowMapper implements RowMapper<User>{

@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
        
        System.out.println("arg1=="+arg1);
        
        User user = new User();
        user.setUid(rs.getInt("uid"));
        user.setUsername(rs.getString("username"));
        user.setPassword(rs.getString("password"));  
        return user;
    }
}

3. jdbc模板的註入寫法

該小節演練的是三層結構的所有屬性註入寫法。(不寫action | servlet)

1. 分析

以下代碼其實是位於dao層的

  @Override
    public void save(User user) {
​
        // 數據源,連資料庫。 連什麼類型的數據, 哪個庫, 賬號 & 密碼
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///stus");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
​
        // 1. 創建jdbc模板
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
​
        String sql = "insert into t_user values(null , ? , ? )";
​
        // 2. 執行添加操作,其實它的用法和以前的queryrunner一樣。
        jdbcTemplate.update(sql, user.getPassword(), user.getUsername());
    }

這套代碼很多,而且它只是一個dao的操作代碼而已。 如果我們還有別的dao方法。也要執行資料庫操作,那麼必然也得寫出來這樣的代碼。 那麼就存在冗餘代碼了。

解決方案:

  1. 以前的解決方法:

    ​ 工具類 | 靜態代碼塊

    1. 現在學了spring了,我想用spring的手法來簡化dao的這一套代碼。

      ​分析以上代碼,其實它就是做了兩個工作。

      ​a. 創建了jdbc模板的對象,並且完成了屬性的賦值工作。

      ​b. 創建了dataSource 的對象,並且完成了屬性的賦值工作。

spring也可以完成這個工作, 創建對象,其實就是`IOC`的體現, 對屬性的賦值工作其實就是`DI`的體現
•~~~xml
<bean id="jdbctemplate" class="">
    <property name="dataSource" ref="dataSource">
      
 <bean id="dataSource" class="">   
    <property name="..." value="">
    <property name="..." value="">
    <property name="..." value="">
    <property name="..." value="">
•~~~

2. 基本實現

  • service

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
         this.userDao = userDao;
    }
​
    @Override
    public void save() {
        System.out.println("調用了UserServiceImpl的save方法~~!");
​      userDao.save();
    }
}
  • dao

public class UserDaoImpl implements UserDao {
   private JdbcTemplate jdbcTemplate;
   public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
   }
   @Override
   public void save() {
        System.out.println("調用了UserDaoImpl的save方法~~");
        //3. 執行添加操作
        String sql = "insert into t_user values (null , ? , ?)";
        jdbcTemplate.update(sql, "heima242","0000");
​
    }
}
  • xml

<bean id="us" class="com.pri.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
</bean><bean id="userDao" class="com.pri.dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
</bean>
 
<bean id="dataSource"    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///stus"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
</bean>

3. 整合c3p0連接池

  1. 導入jar包

       c3p0-0.9.5.2.jar   mchange-commons-java-0.2.12.jar

  1. 在xml中配置

沒有使用c3p0連接池的配置
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
  <property name="url" value="jdbc:mysql:///user"></property>
  <property name="username" value="root"></property>
  <property name="password" value="root"></property>
</bean> ​ 使用了c3p0的配置 <!-- 使用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:///user"></property>
  <property name="user" value="root"></property>
  <property name="password" value="root"></property>
</bean>

4. 使用jdbc.properties記錄資料庫連接信息

為了方便修改資料庫連接信息,通常在src下使用properties文件來記錄他們。主要是方便修改

  1. 在src下新建一個properties文件,內容如下 名:jdbc.properties

driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///user
user=root
password=root
  1. 在xml裡面導入jdbc.properties ,並且在dataSource裡面引用

a. 導入context約束 
b. 導入jdbc.properties
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 使用c3p0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
     <property name="driverClass" value="${driverClass}"></property>
     <property name="jdbcUrl" value="${jdbcUrl}"></property>
     <property name="user" value="${user}"></property>
     <property name="password" value="${password}"></property>
</bean>

三、 事務管理

1. 事務的回顧

  • 什麼事務,事務有什麼用?

事務是用於包裝一組操作的。當這一組操作裡面的所有步驟都執行成功,那麼這一組操作就算成功(事務的提交),如果有哪一個步驟執行失敗,那麼這一組操作就以失敗告終。(事務的回顧)

  • 事務的特性

原子性一致性隔離性持久性

  • 如果不考慮隔離級別,那麼事務併發會出現以下問題

  1. 讀的問題

    ​ 臟讀 : 讀到了另一個事務還沒有提交的數據

    ​ 不可重覆讀 : 讀到了另一個事務已經提交的數據 (針對的是update的數據)

    ​ 虛讀| 幻讀 : 讀到了另一個事務已經提交的數據(針對的是insert的數據)

    解決方案: 設置隔離級別

    ​ 讀未提交

    ​ 讀已提交 Oracle

    ​ 可重覆讀 MySql

    ​ 序列化|串列化

  2. 寫的問題

    ​ 丟失更新: 最後操作的事務,不管是提交還是回滾,都會讓前一個是的數據丟失掉。

    解決方案:

    ​ 悲觀鎖 : 還沒開始就認為一定會丟失更新。

    ​ 每一個事務在執行操作之前,先進行一次查詢。 並且查詢的語句裡面帶有關鍵字 for update

    ​ 樂觀鎖 : 認為不會出現丟失更新,

    ​ 要求程式員手動控制,給表額外添加一個欄位 如: version。

2. Spring對事務的管理辦法

  • 事務應該寫在哪一層? 為什麼spring也要插手管理事務?

事務應該寫在Service層。 因為service表示的業務,一組業務可能會執行多個到的方法。所以在Service層聲明事務更好一點。 而且spring正好是Service層的解決方案。

  • Spring針對事務的管理API

Spring 可以管理事務, 但是真正完成操作的技術,spring可不管。 dao層使用的技術可能有很多。 jdbchibernatemybatis . 但是這幾個框架,他們開啟事務的辦法,可能不一樣。 spring為了統一管理事務,聲明瞭一套規範出來,並且對底下的使用頻率比較到的技術,都給出了具體的實現。


管理事務的規範是 PlatformTransactionManager

jdbc | mybatis : DataSourceTransactionManager
hibernate : HibernateTransactionManager

spring對dao層使用什麼技術,它不管,它統一規定,要操作事務,必須使用管理員!!!

3. spring對事務支持的寫法

提供了三種寫法 編程式事務聲明式事務(xml & 註解)

1. 編程式事務

純靠寫代碼來完成事務配置

@Test
public void test(){  
    //事務的管理員是用來管理事務的,包含了打開事務、 提交事務、 回滾事務
    final DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql:///stus");
    dataSource.setUsername("root");
    dataSource.setPassword("root");

    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource);
        
    //1. 創建事務的模板對象。
    TransactionTemplate transactionTemplate = new TransactionTemplate();
    transactionTemplate.setTransactionManager(transactionManager);
        
    //事務事務的模板對象
    transactionTemplate.execute( new TransactionCallback<Object>() {
    //在事務裡面執行這個方法。
    @Override
    public Object doInTransaction(TransactionStatus arg0) {
        //添加操作
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
                
        String sql = "insert into  t_user values ( null , ? , ?)";
        jdbcTemplate.update(sql, "123","王五");
        int a = 1 / 0 ;
        jdbcTemplate.update(sql, "6666","趙六");
          return null;
       }
    });
   
}

2. 聲明式事務(xml)

xml方式配置事務,其實就是使用AOP的思想,在方法執行前,開啟事務,方法執行後,提交事務(回滾事務)

<!-- 以下屬於事務的配置 如果要用事務了,那麼事務的管理員是誰啊。 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
     <tx:advice id="advice01" transaction-manager="transactionManager">
        <tx:attributes>  <!-- 對前面的表達式找到的那一堆方法,進行過濾配置,表示誰才能用事務管理, 如果是* ,表示前面找到的那一堆都用事務管理 -->
            <tx:method name="save*"/>
            <tx:method name="update*"/>
            <tx:method name="delete*"/>
        </tx:attributes>
     </tx:advice>
     
     <!-- 
         以上配置,到目前為止,只是說明瞭,如果要開啟事務,管理員是誰。 但是缺少了一個東西。
         就是哪一個方法到底要用事務呀? -->
     
     <aop:config>
        <aop:pointcut expression="execution(* com.pri.service.impl.*.*(..))" id="aa"/>
        
        <aop:advisor advice-ref="advice01" pointcut-ref="aa"/>
     </aop:config>

3. 聲明式事務(註解)

使用註解的方式來開啟事務

  • xml配置        

1. 在xml中 聲明註解事務的管理員
​
   <!-- 以下屬於事務的配置 如果要用事務了,那麼事務的管理員是誰啊。 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 指定註解事務使用的管理員是誰 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
  • 代碼配置

2. 在業務邏輯類上或者方法上打註解
​  類上的註解,表示類中的所有方法都用事務, 如果在方法上打註解,表示只有這個方法才會用事務
@Transactional
public class UserServiceImpl implements UserService {

}
​
public class UserServiceImpl implements UserService {
    @Transactional
    @Override
    public void save() {}
} 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • timeChunk函數讓創建節點的工作分批進行,比如一秒鐘創建1000個節點,改為每個200ms創建10個節點。具體timeChunk函數封裝如下 應用實例見https://92node.com/article/js-fen-shi.html ...
  • 上一篇聊了聊構建分散式系統所面臨的困難,這篇將著重討論構建容錯分散式系統的演算法與協議。構建容錯系統的最佳方法是使用通用抽象,允許應用程式忽略分散式系統中的一些問題。本篇我們先聊一聊線性一致性,以及與線性一致性有關的技術,後續需要瞭解的分散式協調服務,如:ZooKeeper等,都是基於分散式系統的線性 ...
  • 本文簡要地示範瞭如何使用java CardLayout對程式進行佈局。 ...
  • Problem Link: http://codeforces.com/problemset/problem/888/F Problem Statement: There are n points marked on the plane. The points are situated in suc ...
  • 針對本文,博主最近在寫《成神之路系列文章》 ,分章分節介紹所有知識點。歡迎關註。 一、基礎篇 1.1 JVM 1.1.1. Java記憶體模型,Java記憶體管理,Java堆和棧,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http://ifeve.com/ ...
  • 前言 本文配套代碼:https://github.com/TTGuoying/ThreadPool 先看看幾個概念: 我們為什麼要使用線程池呢? 簡單來說就是線程本身存在開銷,我們利用多線程來進行任務處理,單線程也不能濫用,無止禁的開新線程會給系統產生大量消耗,而線程本來就是可重用的資源,不需要每次 ...
  • 本文主要介紹Sprint整合Struts和Hibernate的基本使用。 ...
  • 本文主要對SSH框架中的註解方式與XML配置方式進行簡單對比。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...