1. 程式人生 > 遊戲 >E3 2021:《They Always Run》演示 爽快橫版動作

E3 2021:《They Always Run》演示 爽快橫版動作

事務基礎

事務的概念

  • 事務指資料庫中多個操作合併在一起形成的操作序列
  • 由多個操作組成的一個邏輯單元,組成這個邏輯單元的多個操作要麼都成功要麼都失敗

事務的特性

  • 原子性(Atomicity)

    • 指事務是一個不可分割的整體,其中的操作要麼全執行或全不執行
  • 一致性(Consistency)

    • 事務前後資料的完整性必須保持一致
  • 隔離性(Isolation)

    • 事務的隔離性是多個使用者併發訪問資料庫時,
    • 資料庫為每一個使用者開啟的事務,不能被其他事務的操作資料所幹擾,
    • 多個併發事務之間要相互隔離
  • 永續性(Durability)

    • 永續性是指一個事務一旦被提交,它對資料庫中資料的改變就是永久性的,
    • 接下來即使資料庫發生故障也不應該對其有任何影響

名詞解釋

  • 髒讀
    • 允許讀取未提交的資訊
    • 解決方案:表級讀鎖
  • 不可重複讀
    • 讀取過程中單個數據發生了變化
    • 解決方案:行級寫鎖
  • 幻讀
    • 讀取過程中資料條目發生了變化
    • 解決方案:表級寫鎖

隔離級別

  • Read uncommitted
    • 存在:髒讀、不可重複讀、幻讀
  • Read committed
    • 存在:不可重複讀、幻讀
    • 解決:髒讀
  • Repeatable read
    • 存在:幻讀
    • 解決:髒讀、不可重複讀
  • Serializable
    • 解決:髒讀、不可重複讀、幻讀

程式設計式事務控制

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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

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

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="accountService" class="com.asaawan.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.asaawan.domain"/>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.asaawan.dao"/>
    </bean>

    <!-- aop 控制事務 -->

    <!-- 為 TxAdvice 注入資料來源 -->
    <bean id="txAdvice" class="com.asaawan.aop.TxAdvice">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 為 transfer 方法新增事務控制 -->
    <aop:config>
        <aop:pointcut id="pt" expression="execution(* *..transfer(..))"/>
        <aop:aspect ref="txAdvice">
            <aop:around method="transactionManager" pointcut-ref="pt"/>
        </aop:aspect>
    </aop:config>
</beans>

TxAdvice 配置

public class TxAdvice {

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Object transactionManager(ProceedingJoinPoint pjp) throws Throwable {
        // 開啟事務 
        // 建立事務管理器併為事務管理器設定與資料層相同的資料來源
        PlatformTransactionManager ptm = new DataSourceTransactionManager(dataSource);
        // 建立事務定義物件
        TransactionDefinition td = new DefaultTransactionDefinition();
        // 建立事務狀態物件,用於控制事務執行
        TransactionStatus ts = ptm.getTransaction(td);
		// 執行切入點方法
        Object ret = pjp.proceed(pjp.getArgs());
        // 提交事務
        ptm.commit(ts);
        // 返回資料
        return ret;
    }
}

宣告式事務控制

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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

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

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.asaawan.domain"/>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.asaawan.dao"/>
    </bean>

    <bean id="accountService" class="com.asaawan.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!-- tx 控制事務 -->

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--定義事務管理的通知類-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!--定義控制的事務-->
        <tx:attributes>
            <tx:method
                name="transfer"
                read-only="false"
                timeout="-1"
                isolation="DEFAULT"
                no-rollback-for=""
                rollback-for=""
                propagation="REQUIRED"
                />
            <!--<tx:method name="transfer" read-only="false"/>-->
            <!--name="transfer"		待新增事務的方法名錶達式(支援*號萬用字元),例如get*
			read-only="false"		設定事務的讀寫屬性,true為只讀,false為只寫
			timeout="-1"			設定事務超時時長,單位秒
			isolation="DEFAULT" 	設定事務的隔離級別,該隔離級設定是基於Spring的設定,非資料庫端
			no-rollback-for=""  	設定事務中不回滾的異常,多個異常間使用 ',' 分割
			rollback-for=""			設定事務中必回滾的異常,多個異常間使用 ',' 分割
			propagation="REQUIRED" 	設定事務的傳播行為-->
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="pt" expression="execution(* com.asaawan.service.*Service.*(..))"/>
        <aop:pointcut id="pt2" expression="execution(* com.asaawan.dao.*.b(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt2"/>
    </aop:config>
</beans>

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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

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

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.asaawan.domain"/>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.asaawan.dao"/>
    </bean>

    <bean id="accountService" class="com.asaawan.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

	<!-- tx 事務控制註解版 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
	<!-- 開啟事務註解驅動 -->
    <tx:annotation-driven transaction-manager="txManager"/>
</beans>

AccountService 配置

//對當前介面的所有方法新增事務
//新增事務一般在 *Service 新增
@Transactional(isolation = Isolation.DEFAULT)
public interface AccountService {

    /**
     * 轉賬操作
     * @param outName     出賬使用者名稱
     * @param inName      入賬使用者名稱
     * @param money       轉賬金額
     */
    
    //對當前方法新增事務,該配置將替換介面的配置
    @Transactional(
        readOnly = false,
        timeout = -1,
        isolation = Isolation.DEFAULT,
        rollbackFor = {},   //java.lang.ArithmeticException.class, IOException.class
        noRollbackFor = {},
        propagation = Propagation.REQUIRED
        )
    public void transfer(String outName, String inName, Double money);
}

宣告式事務控制純註解

TxManagerConfig 註解

public class TxManagerConfig {
    @Bean
    public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

SpringConfiguration 註解

@Configuration
@ComponentScan("com.asaawan")
@PropertySource(value = {"classpath:jdbc.properties"},ignoreResourceNotFound = true)
@Import({JdbcConfiguration.class, MyBatisConfiguration.class})
@EnableTransactionManagement
public class SpringConfiguration {
}

aop:advice 與 aop:advisor

aop:advice

  • 配置的通知類可以是普通 java 物件,不實現介面,也不使用繼承關係

aop:advisor

  • 配置的通知類必須實現通知介面
  • MethodBeforeAdvice
  • AfterReturningAdvice
  • ThrowsAdvice
  • ...

事務的傳播行為

概念

  • 指的就是當一個事務方法被另一個事務方法呼叫時,這個事務方法應該如何進行

常見取值