首頁 > 軟體

Java Spring的兩種事務你知道嗎

2022-03-15 19:00:28

1. Spring中的事務控制方式

Spring的事務控制可以分為程式設計式事務控制和宣告式事務控制。

程式設計式

開發者直接把事務的程式碼和業務程式碼耦合到一起,在實際開發中不用。

宣告式

開發者採用設定的方式來實現的事務控制,業務程式碼與事務程式碼實現解耦合,使用的AOP思想。

2.程式設計式事務控制相關物件

2.1PlatformTransactionManager

PlatformTransactionManager介面,是spring的事務管理器介面,裡面提供了我們常用的操作事務的方法。

2.2TransactionDefinition

TransactionDefinition介面提供事務的定義資訊(事務隔離級別、事務傳播行為等等)

(1)事務隔離級別

設定隔離級別,可以解決事務並行產生的問題,如髒讀、不可重複讀和虛讀(幻讀)。

注意:使用資料庫預設級別,如果資料庫是mysql,則預設是可重複讀,oracle是讀已提交。

ISOLATION_DEFAULT 使用資料庫預設級別

ISOLATION_READ_UNCOMMITTED 讀未提交

ISOLATION_READ_COMMITTED 讀已提交(可解決髒讀問題)

ISOLATION_REPEATABLE_READ 可重複讀 (可解決髒讀、不可重複讀)

ISOLATION_SERIALIZABLE 序列化

可解決:

(2)事務傳播行為

事務傳播行為指的就是當一個業務方法【被】另一個業務方法呼叫時,應該如何進行事務控制。

重點:

  • read-only(是否唯讀):建議查詢時設定為唯讀
  • timeout(超時時間):預設值是-1,沒有超時限制。如果有,以秒為單位進行設定

2.3 TransactionStatus

TransactionStatus 介面提供的是事務具體的執行狀態。

可以簡單的理解三者的關係:事務管理器通過讀取事務定義引數進行事務管理,然後會產生一系列的事務狀態。

Spring中的事務控制主要就是通過這三個API實現的

PlatformTransactionManager 負責事務的管理,它是個介面,其子類負責具體工作

TransactionDefinition 定義了事務的一些相關引數

TransactionStatus 代表事務執行的一個實時狀態

理解三者的關係:事務管理器通過讀取事務定義引數進行事務管理,然後會產生一系列的事務狀態

3.基於XML的宣告式事務控制【重點】

在Spring組態檔中宣告式的處理事務來代替程式碼式的處理事務。底層採用AOP思想來實現。

宣告式事務控制明確事項:

核心業務程式碼(目標物件) (切入點是誰?)

事務增強程式碼(Spring已提供事務管理器))(通知是誰?)

切面設定(切面如何設定?)(切面 = 切入點 + 通知)

3.1快速入門

使用spring宣告式事務控制轉賬業務。

步驟:

1.引入tx名稱空間

2.事務管理器通知設定

3.事務管理器AOP設定

4.測試事務控制轉賬業務程式碼 

(1)引入tx名稱空間

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

(2)事務管理器通知設定

  <!--事務管理器物件-->
    <!--<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>--> 
// 通知增強
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
       //定義事務的一些屬性 * 表示當前任意名稱的方法都走預設設定
     <!--
            name: 切點方法名稱
            isolation:事務的隔離級別
            propagation:事務的傳播行為
            read-only:是否唯讀
            timeout:超時時間
        -->
        <tx:attributes>
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="-1"/>
            //CRUD常用設定
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

(3)事務管理器AOP設定 

當使用spring宣告式管理事務,要使用aop:advisor來進行aop的設定!

//aop設定:設定切面   
<aop:config>  
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>
    </aop:config>-->

事務引數的設定詳解:

<tx:method name=“transfer” isolation=“REPEATABLE_READ” propagation=“REQUIRED”timeout="-1" read-only=“false”/>

  • name:切點方法名稱
  • isolation:事務的隔離級別
  • propogation:事務的傳播行為
  • timeout:超時時間
  • read-only:是否唯讀

4.基於註解的宣告式事務控制(重點)

步驟:

  • 修改service層,增加事務註解
  • 修改spring核心組態檔,開啟事務註解支援

4.1 修改service層,增加事務註解

@Service
public class AccountServiceImpl implements AccountService {
  @Autowired
  private AccountDao accountDao;
    @Transactional(propagation = Propagation.REQUIRED, isolation =
Isolation.REPEATABLE_READ, timeout = -1, readOnly = false)
  @Override
  public void transfer(String outUser, String inUser, Double money) {
    accountDao.out(outUser, money);
    int i = 1 / 0;
    accountDao.in(inUser, money);
 }
}

4.2修改spring核心組態檔,開啟事務註解支援

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w2.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">
  <!--省略之前datsSource、jdbcTemplate、元件掃描設定-->
  <!--事務管理器-->
  <bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
  </bean>
  <!--事務的註解支援-->
  <tx:annotation-driven/>
</beans

4.3純註解方式

核心設定類:

@Configuration  // 宣告該類為核心設定類
@ComponentScan("com.lagou")  // 包掃描
@Import(DataSourceConfig.class) //匯入其他設定類
@EnableTransactionManagement //事務的註解驅動
public class SpringConfig {
    @Bean
    public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }
    @Bean
    public PlatformTransactionManager getPlatformTransactionManager(@Autowired DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
        return dataSourceTransactionManager;
    }
}

資料來源設定類:

@PropertySource("classpath:jdbc.properties") //引入properties檔案
public class DataSourceConfig {
    @Value("${jdbc.driverClassName}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean //會把當前方法的返回值物件放進IOC容器中
    public DataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
}

知識小結:

  • 平臺事務管理器設定(xml、註解方式)
  • 事務通知的設定(@Transactional註解設定)
  • 事務註解驅動的設定 <tx:annotation-driven/>、@EnableTransactionManagement

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!      


IT145.com E-mail:sddin#qq.com