springboot結合mybatis操作事務配置的處理
前言:
目前大多數(shù)的項目都是通過spring或者springboot來開發(fā)的,并且項目里面操作數(shù)據(jù)庫常用的有mybatis\mybatis-plus等,在操作數(shù)據(jù)庫的時候,經常會使用事務的處理,因為在操作數(shù)據(jù)庫的時候,如果出現(xiàn)異常的話,所有的數(shù)據(jù)庫操作都能夠回滾操作,避免造成一些異常數(shù)據(jù)的問題。目前網絡上搜索的都是原始的配置方式,比如說使用xml進行bean的配置,或者說直接在方法頭上面進行添加注解的方式進行調用的,本文主要介紹通過配置類進行管理實務的方式,統(tǒng)一的管理、統(tǒng)一的處理方式。
事務的相關問題
1、什么是事務?
事務是指一組SQL語句的集合,集合中有多條SQL語句,可以是insert、update、select、delete,希望這些SQL語句執(zhí)行是一致的,作為一個整體執(zhí)行。要么都成功,要么都失敗。
2、事務的特點(ACID)
- 原子性(Atomicity):事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事務完成(不管成功還是失?。?,系統(tǒng)必須確保它所建模的業(yè)務處于一致的狀態(tài),而不會是部分完成部分失敗。在現(xiàn)實中的數(shù)據(jù)不應該被破壞。
- 隔離性(Isolation):可能有許多事務會同時處理相同的數(shù)據(jù),因此每個事務都應該與其他事務隔離開來,防止數(shù)據(jù)損壞。
- 持久性(Durability):一旦事務完成,無論發(fā)生什么系統(tǒng)錯誤,它的結果都不應該受到影響,這樣就能從任何系統(tǒng)崩潰中恢復過來。通常情況下,事務的結果被寫到持久化存儲器中。
3、什么時候想到使用事務?
(1)當操作設計多個表,或者是多個SQL語句的insert、update、delete。需要保證這些語句都是成功才能完成功能,或者都失敗是符合要求的。(要么都成功,要么都失敗)
(2)事務在java開發(fā)中如何運用?
1、事務放在service類的業(yè)務方法中,因為業(yè)務方法會調用多個dao,執(zhí)行多條SQL語句
4、通常使用JDBC訪問數(shù)據(jù)庫,還是mybatis訪問數(shù)據(jù)庫,怎么處理事務?
(1)jdbc訪問數(shù)據(jù),處理事務。Connection conn;conn.commit();conn.rollback();
(2)mybatis訪問數(shù)據(jù)庫,處理事務。SqlSession.commit() ;SqlSession.rollback();
(3)hibernate訪問數(shù)據(jù)庫,處理事務,Session.commit(); Session.rollback();
5、問題中事務處理的方式有什么不足?
(1)不同數(shù)據(jù)庫訪問技術,處理事務的對象、方法不同。需要了解不同數(shù)據(jù)庫使用事務的原理。
(2)需要掌握多種數(shù)據(jù)庫事務的處理邏輯,什么時候提交事務,什么時候回滾事務。
(3)處理事務的方法種類多。
總結:就是多種數(shù)據(jù)庫訪問技術,不同的事務處理的機制、對象、方法。較難掌握。
6、怎么解決不足?
spring提供了處理事務的統(tǒng)一模型,能夠使用統(tǒng)一的步驟、方式完成多種不同數(shù)據(jù)庫訪問技術的事務處理。使用spring的事務處理機制可以完成mybatis、hibernate訪問數(shù)據(jù)庫的事務處理。
7、處理事務,需要怎么做,做什么?
spring處理事務的模型,使用的步驟都是固定的。把事務要使用的信息都提供給spring就可以了。
(1)事務內部提交、回滾事務使用的是事務管理器對象,代替手動commit、rollback。事務管理器是一個接口和其眾多的實現(xiàn)類。
接口:PlatformTransactionManager,定義了事務的重要方法 commit、rollback
實現(xiàn)類:spring把每一種數(shù)據(jù)庫訪問技術對應的事務處理累都創(chuàng)建好了。
a、mybatis訪問數(shù)據(jù)庫—spring創(chuàng)建好的是DataSourceTransactionManager
b、hibernate訪問數(shù)據(jù)庫—spring創(chuàng)建好的是HibernateTransactionManager
怎么使用?
只需告訴spring使用哪種數(shù)據(jù)庫的訪問技術(框架),聲明數(shù)據(jù)庫訪問技術對應的事務管理器的實現(xiàn)類,在spring的配置文件中使用<bean>聲明就可以了。例如使用mybatis訪問數(shù)據(jù)庫:
<bean id = "xxx" class = "...DataSourceTransactionManager"/>
(2)業(yè)務方法需要什么樣的事務?說明需要事務的類型。
8、事務的隔離級別
有 5 個值,其中一個是默認。這些常量均是以ISOLATION_開頭,即形如:ISOLATION_XXX。
1、DEFAULT:采用DB默認的事務隔離級別。MySQL的默認隔離級別:REPEATABLE_READ(可重復讀);Oracle默認的隔離級別:READ_COMMITTED(讀已提交)
2、READ_UNCOMMITTED:讀未提交,未解決任何并發(fā)問題。
3、READ_COMMITTED:讀已提交。解決度臟數(shù)據(jù),存在不可重復讀與幻讀。
4、REPEATABLE_READ:可重復度。解決臟讀、不可重復讀,存在幻讀。
5、SERIALIZABLE:串行化。不存在并發(fā)問題。
9、事務的超時時間
表示一個方法最長的執(zhí)行時間,如果方法執(zhí)行時超過了這個時間,事務就回滾。單位是秒,整數(shù)值,默認是:-1(表示沒有限制最長時間)。
10、事務的傳播行為
控制業(yè)務方法是不是有事務的,是什么樣的事務的。共有 7 個傳播行為。(標紅常用需掌握)
(1)PROPAGATION_REQUIRED:指定的方法必須在事務內執(zhí)行。若當前存在事務,就加入當前事務中;若當前沒有事務,則創(chuàng)建一個新事務。這種創(chuàng)博行為時最常見的選擇,也是spring默認的事務傳播行為。
(2)PROPAGATION_REQUIRES_NEW:總是新建一個事務,若當前存在事務,就將當前事務掛起,知道新事物執(zhí)行完畢。
(3)PROPAGATION_SUPPORTS:指定方法支持當前事務,但若當前沒有事務,也可以以非事務的方式執(zhí)行。
(4)PROPAGATION_MANDATORY
(5)PROPAGATION_NESTED
(6)PROPAGATION_NEVER
(7)PROPAGATION_NOT_SUPPORTED
spring boot中配置事務以及使用:
1、進行配置類的處理
#transaction setting############################################### spring.transaction.aop.aop-pointcut-expression=execution(* com...*ServiceImpl.*(..)) spring.transaction.aop.tx-method-timeout=3600 spring.transaction.aop.require-rule=insert*,update*,delete*,do* spring.transaction.aop.read-only-rule=query* spring.transaction.aop.indep-transaction-rule=indep*
第一個配置:該方法主要是為了在操作的時候,掃描包的路徑,不是所有的方法都是走事務處理的。
第二個配置:配置處理的時間大小36秒
第三個配置:為了限制規(guī)則,比如說方法的名稱必須是什么開頭的,只有這些方法名稱開頭的才會走事務的處理
第四個配置:讀取的規(guī)則的方法名稱開頭的命名
第五個配置:事務的處理規(guī)則
2、創(chuàng)建數(shù)據(jù)資源配置類:
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
@Configuration
public class SpringBootDatasourceConfig {
private Logger LOGGER = LoggerFactory.getLogger(SpringBootDatasourceConfig.class);
@Value("${spring.transaction.aop.tx-method-timeout}")
private int TX_METHOD_TIMEOUT = 60;
@Value("${spring.transaction.aop.aop-pointcut-expression}")
private String AOP_POINTCUT_EXPRESSION;
@Value("#{'${spring.transaction.aop.require-rule}'.split(',')}")
private List<String> requireRuleList;
@Value("#{'${spring.transaction.aop.read-only-rule}'.split(',')}")
private List<String> readOnlyRuleList;
@Value("#{'${spring.transaction.aop.indep-transaction-rule}'.split(',')}")
private List<String> indepTransactionRuleList;
@Value("${mybatis.mapper-locations}")
private String MYBATIS_MAPPER_LOCATIONS;
@Value("${mybatis.config-location}")
private String MYBATIS_CONFIG_LOCATION;
@Value("${mybatis.jdbc.dialect.type}")
private String MYBATIS_JDBC_DIALECT_TYPE;
public SpringBootDatasourceConfig() {
}
@Primary
@Bean({"db1DataSourceProperties"})
@ConfigurationProperties(
prefix = "spring.datasource.db1"
)
public DataSourceProperties dataSourceProperties() {
DataSourceProperties dataSourceProperties = new DataSourceProperties();
return dataSourceProperties;
}
@Primary
@Bean({"db1DataSource"})
@ConfigurationProperties(
prefix = "spring.datasource.db1.tomcat"
)
public DataSource db1DataSource(@Qualifier("db1DataSourceProperties") DataSourceProperties dataSourceProperties) {
DataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().build();
return dataSource;
}
@Primary
@Bean(
name = {"db1SqlSessionFactory"}
)
public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource datasource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(datasource);
bean.setMapperLocations((new PathMatchingResourcePatternResolver()).getResources(this.MYBATIS_MAPPER_LOCATIONS));
bean.setConfigLocation((new PathMatchingResourcePatternResolver()).getResource(this.MYBATIS_CONFIG_LOCATION));
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
properties.setProperty("dialect", this.MYBATIS_JDBC_DIALECT_TYPE);
pageInterceptor.setProperties(properties);
Interceptor[] plugins = new Interceptor[]{pageInterceptor};
bean.setPlugins(plugins);
return bean.getObject();
}
@Bean({"sqlSessionTemplate"})
public SqlSessionTemplate db1SqlsessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sessionfactory) {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sessionfactory);
if (sqlSessionTemplate != null) {
Connection connection = null;
try {
connection = sqlSessionTemplate.getConnection();
} catch (Exception var13) {
this.LOGGER.error("SqlSessionTemplate初始化連接池失敗", var13);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException var12) {
this.LOGGER.error("關閉連接失敗", var12);
}
}
}
}
return sqlSessionTemplate;
}
@Bean({"txmanager"})
public DataSourceTransactionManager txManager(@Qualifier("db1DataSource") DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
@Bean({"txAdvice"})
public TransactionInterceptor txAdvice(@Qualifier("txmanager") DataSourceTransactionManager dataSourceTransactionManager) {
RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute();
readOnlyRule.setReadOnly(true);
readOnlyRule.setPropagationBehavior(4);
RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute();
requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(RuntimeException.class)));
requireRule.setPropagationBehavior(0);
requireRule.setIsolationLevel(2);
requireRule.setTimeout(this.TX_METHOD_TIMEOUT);
RuleBasedTransactionAttribute indepTransactionRule = new RuleBasedTransactionAttribute();
indepTransactionRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(RuntimeException.class)));
indepTransactionRule.setPropagationBehavior(3);
indepTransactionRule.setIsolationLevel(2);
indepTransactionRule.setTimeout(this.TX_METHOD_TIMEOUT);
Map<String, TransactionAttribute> txMap = new HashMap();
int i;
String indepTransacdtionAopRule;
for(i = 0; i < this.requireRuleList.size(); ++i) {
indepTransacdtionAopRule = (String)this.requireRuleList.get(i);
txMap.put(indepTransacdtionAopRule.trim(), requireRule);
}
for(i = 0; i < this.readOnlyRuleList.size(); ++i) {
indepTransacdtionAopRule = (String)this.readOnlyRuleList.get(i);
txMap.put(indepTransacdtionAopRule.trim(), readOnlyRule);
}
for(i = 0; i < this.indepTransactionRuleList.size(); ++i) {
indepTransacdtionAopRule = (String)this.indepTransactionRuleList.get(i);
txMap.put(indepTransacdtionAopRule.trim(), indepTransactionRule);
}
NameMatchTransactionAttributeSource nameMatchTransactionAttributeSource = new NameMatchTransactionAttributeSource();
nameMatchTransactionAttributeSource.setNameMap(txMap);
TransactionInterceptor txAdvice = new TransactionInterceptor(dataSourceTransactionManager, nameMatchTransactionAttributeSource);
return txAdvice;
}
@Bean
public Advisor txAdviceAdvisor(@Qualifier("txAdvice") TransactionInterceptor transactionInterceptor) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(this.AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, transactionInterceptor);
}
}3、實際代碼里面調用實踐:
第一種:添加異常方法,直接調用接口,就可以看到相關的效果,只不過需要在數(shù)據(jù)庫變更的后面,添加相關的異常拋出,讓整個方法異常,然后看一下這個數(shù)據(jù)庫的記錄沒有變化,已經 回滾了;
第二種:去除異常方法,讓整個方法正常執(zhí)行下去,通過 數(shù)據(jù)庫查詢一下記錄,看一下數(shù)據(jù)是更新是成功落庫的;
總結:
目前網絡上面搜索到的都是直接使用的注解進行事務的處理,而不是根據(jù)配置文件進行配置規(guī)則、以及事務的統(tǒng)一管理處理,比如說方法名稱進行切面的處理,那些方法是會進行mybatis(數(shù)據(jù)庫的更新處理會走事務處理),比如說,目前的很多大型公司,或者說需要保持事務一致性的公司都會用到,整個的調用鏈比較長,如果中途出現(xiàn)了問題,會進行事務的回滾處理,避免了很多的問題(數(shù)據(jù)庫里面存在垃圾數(shù)據(jù)的問題);
到此這篇關于springboot結合mybatis操作事務配置的處理的文章就介紹到這了,更多相關springboot mybatis事務配置內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Presto自定義函數(shù)@SqlNullable引發(fā)問題詳解
這篇文章主要為大家介紹了Presto自定義函數(shù)@SqlNullable引發(fā)問題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
java多態(tài)實現(xiàn)電子寵物系統(tǒng)
這篇文章主要為大家詳細介紹了java多態(tài)實現(xiàn)電子寵物系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
解決SpringBoot整合MybatisPlus分模塊管理遇到的bug
這篇文章主要介紹了解決SpringBoot整合MybatisPlus分模塊管理遇到的bug,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Spring Security實現(xiàn)動態(tài)路由權限控制方式
這篇文章主要介紹了Spring Security實現(xiàn)動態(tài)路由權限控制方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08

