包名的配置問題
execution(* com.keeep.isrvbase.service.*.*(..))
//表示匹配com.keeep.isrvbase.service包下的所有方法
execution(* com.keeep.isrvbase.service..*.*(..))
//表示匹配com.savage.server包及其子包下的所有方法
Spring 事務(wù)的隔離性
事務(wù)隔離級(jí)別:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
讀取未提交數(shù)據(jù)(會(huì)出現(xiàn)臟讀, 不可重復(fù)讀) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
讀取已提交數(shù)據(jù)(會(huì)出現(xiàn)不可重復(fù)讀和幻讀)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重復(fù)讀(會(huì)出現(xiàn)幻讀)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化
MYSQL: 默認(rèn)為REPEATABLE_READ級(jí)別
SQLSERVER: 默認(rèn)為READ_COMMITTED
臟讀 : 一個(gè)事務(wù)讀取到另一事務(wù)未提交的更新數(shù)據(jù)
不可重復(fù)讀 : 在同一事務(wù)中, 多次讀取同一數(shù)據(jù)返回的結(jié)果有所不同, 換句話說,后續(xù)讀取可以讀到另一事務(wù)已提交的更新數(shù)據(jù).
相反, "可重復(fù)讀"在同一事務(wù)中多次讀取數(shù)據(jù)時(shí), 能夠保證所讀數(shù)據(jù)一樣, 也就是后續(xù)讀取不能讀到另一事務(wù)已提交的更新數(shù)據(jù)
幻讀 : 一個(gè)事務(wù)讀到另一個(gè)事務(wù)已提交的insert數(shù)據(jù)
Spring事務(wù)的傳播行為
事物傳播行為介紹:
@Transactional(propagation=Propagation.REQUIRED)
如果有事務(wù), 那么加入事務(wù), 沒有的話新建一個(gè)(默認(rèn)情況下)
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不為這個(gè)方法開啟事務(wù)
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事務(wù),都創(chuàng)建一個(gè)新的事務(wù),原來的掛起,新的執(zhí)行完畢,繼續(xù)執(zhí)行老的事務(wù)
@Transactional(propagation=Propagation.MANDATORY)
必須在一個(gè)已有的事務(wù)中執(zhí)行,否則拋出異常
@Transactional(propagation=Propagation.NEVER)
必須在一個(gè)沒有的事務(wù)中執(zhí)行,否則拋出異常(與Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean調(diào)用這個(gè)方法,在其他bean中聲明事務(wù),那就用事務(wù).如果其他bean沒有聲明事務(wù),那就不用事務(wù).
事務(wù)配置
package com.keeep.isrvbase.pojo;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Table;
/**
* 測(cè)試用例
* @author congco
*/
@Setter
@Getter
@Table(name="tb_base_transaction_test")
public class TransactionTest {
private Long id;
private String name;
}
applicationContext-transaction.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 定義事務(wù)管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 定義事務(wù)策略 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--所有以query開頭的方法都是只讀的 -->
<tx:method name="query*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="select*" read-only="true"/>
<!--其他方法使用默認(rèn)事務(wù)策略 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--pointcut元素定義一個(gè)切入點(diǎn)组力,execution中的第一個(gè)星號(hào) 用以匹配方法的返回類型翔悠,
這里星號(hào)表明匹配所有返回類型。
1)execution(* *(..))
//表示匹配所有方法
2)execution(public * com.keeep.isrvbase.service.*(..))
//表示匹配 com.keeep.isrvbase.service中所有的公有方法
3)execution(* com.keeep.isrvbase.service..*.*(..))
//表示匹配 com.keeep.isrvbase.service包及其子包下的所有方法
-->
<aop:pointcut id="myPointcut" expression="execution(* com.keeep.isrvbase.service..*.*(..))"/>
<!--將定義好的事務(wù)處理策略應(yīng)用到上述的切入點(diǎn) -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
</aop:config>
</beans>
mapper
package com.keeep.isrvbase.mapper;
import com.github.abel533.mapper.Mapper;
import com.keeep.isrvbase.pojo.TransactionTest;
/**
* @author congco
*/
public interface TransactionTestMapper extends Mapper<TransactionTest> {
}
service
package com.keeep.isrvbase.service;
import com.keeep.isrvbase.mapper.TransactionTestMapper;
import com.keeep.isrvbase.pojo.TransactionTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* created on 2020/4/10 上午11:58
*
* @author congco
*/
@Service
public class AnotherTransService {
@Autowired
private TransactionTestMapper mapper;
public String testTrans() {
try {
TransactionTest test = new TransactionTest();
test.setName("cong");
this.mapper.insertSelective(test);
} catch (Exception e) {
e.printStackTrace();
}
return "over";
}
}
//
package com.keeep.isrvbase.service.test;
import com.keeep.isrvbase.service.AnotherTransService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
/**
* @author congco
* @date 19-5-27 下午7:25
*/
@Service
public class TransactionTestService {
@Autowired
public AnotherTransService anotherTransService;
public String queryName() {
return "Hello Congco";
}
public String saveName() {
try {
System.out.println("開始事務(wù)");
this.anotherTransService.testTrans();
int i =1/0;
this.anotherTransService.testTrans();
} catch (Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
System.out.println("roll back");
return "ok";
}
}
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version> 3.2.4.RELEASE </version>
<scope>provided</scope>
</dependency>
單元測(cè)試
package com.keeep.isrvbase.test;
import com.keeep.isrvbase.service.test.TransactionTestService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* created on 2020/4/10 上午11:21
*
* @author congco
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/app*.xml")
public class TransactionTestServiceTest {
@Autowired
private TransactionTestService service;
@Test
public void queryName() {
String name = this.service.queryName();
System.out.println(name);
}
@Test
public void saveName() {
this.service.saveName();
}
}
結(jié)果
數(shù)據(jù)庫(kù)表沒有插入新的數(shù)據(jù)