springboot結(jié)合mybatis操作事務(wù)配置的處理
前言:
目前大多數(shù)的項(xiàng)目都是通過spring或者springboot來開發(fā)的,并且項(xiàng)目里面操作數(shù)據(jù)庫常用的有mybatis\mybatis-plus等,在操作數(shù)據(jù)庫的時(shí)候,經(jīng)常會(huì)使用事務(wù)的處理,因?yàn)樵诓僮鲾?shù)據(jù)庫的時(shí)候,如果出現(xiàn)異常的話,所有的數(shù)據(jù)庫操作都能夠回滾操作,避免造成一些異常數(shù)據(jù)的問題。目前網(wǎng)絡(luò)上搜索的都是原始的配置方式,比如說使用xml進(jìn)行bean的配置,或者說直接在方法頭上面進(jìn)行添加注解的方式進(jìn)行調(diào)用的,本文主要介紹通過配置類進(jìn)行管理實(shí)務(wù)的方式,統(tǒng)一的管理、統(tǒng)一的處理方式。
事務(wù)的相關(guān)問題
1、什么是事務(wù)?
事務(wù)是指一組SQL語句的集合,集合中有多條SQL語句,可以是insert、update、select、delete,希望這些SQL語句執(zhí)行是一致的,作為一個(gè)整體執(zhí)行。要么都成功,要么都失敗。
2、事務(wù)的特點(diǎn)(ACID)
- 原子性(Atomicity):事務(wù)是一個(gè)原子操作,由一系列動(dòng)作組成。事務(wù)的原子性確保動(dòng)作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事務(wù)完成(不管成功還是失?。?,系統(tǒng)必須確保它所建模的業(yè)務(wù)處于一致的狀態(tài),而不會(huì)是部分完成部分失敗。在現(xiàn)實(shí)中的數(shù)據(jù)不應(yīng)該被破壞。
- 隔離性(Isolation):可能有許多事務(wù)會(huì)同時(shí)處理相同的數(shù)據(jù),因此每個(gè)事務(wù)都應(yīng)該與其他事務(wù)隔離開來,防止數(shù)據(jù)損壞。
- 持久性(Durability):一旦事務(wù)完成,無論發(fā)生什么系統(tǒng)錯(cuò)誤,它的結(jié)果都不應(yīng)該受到影響,這樣就能從任何系統(tǒng)崩潰中恢復(fù)過來。通常情況下,事務(wù)的結(jié)果被寫到持久化存儲(chǔ)器中。
3、什么時(shí)候想到使用事務(wù)?
(1)當(dāng)操作設(shè)計(jì)多個(gè)表,或者是多個(gè)SQL語句的insert、update、delete。需要保證這些語句都是成功才能完成功能,或者都失敗是符合要求的。(要么都成功,要么都失?。?/p>
(2)事務(wù)在java開發(fā)中如何運(yùn)用?
1、事務(wù)放在service類的業(yè)務(wù)方法中,因?yàn)闃I(yè)務(wù)方法會(huì)調(diào)用多個(gè)dao,執(zhí)行多條SQL語句
4、通常使用JDBC訪問數(shù)據(jù)庫,還是mybatis訪問數(shù)據(jù)庫,怎么處理事務(wù)?
(1)jdbc訪問數(shù)據(jù),處理事務(wù)。Connection conn;conn.commit();conn.rollback();
(2)mybatis訪問數(shù)據(jù)庫,處理事務(wù)。SqlSession.commit() ;SqlSession.rollback();
(3)hibernate訪問數(shù)據(jù)庫,處理事務(wù),Session.commit(); Session.rollback();
5、問題中事務(wù)處理的方式有什么不足?
(1)不同數(shù)據(jù)庫訪問技術(shù),處理事務(wù)的對象、方法不同。需要了解不同數(shù)據(jù)庫使用事務(wù)的原理。
(2)需要掌握多種數(shù)據(jù)庫事務(wù)的處理邏輯,什么時(shí)候提交事務(wù),什么時(shí)候回滾事務(wù)。
(3)處理事務(wù)的方法種類多。
總結(jié):就是多種數(shù)據(jù)庫訪問技術(shù),不同的事務(wù)處理的機(jī)制、對象、方法。較難掌握。
6、怎么解決不足?
spring提供了處理事務(wù)的統(tǒng)一模型,能夠使用統(tǒng)一的步驟、方式完成多種不同數(shù)據(jù)庫訪問技術(shù)的事務(wù)處理。使用spring的事務(wù)處理機(jī)制可以完成mybatis、hibernate訪問數(shù)據(jù)庫的事務(wù)處理。
7、處理事務(wù),需要怎么做,做什么?
spring處理事務(wù)的模型,使用的步驟都是固定的。把事務(wù)要使用的信息都提供給spring就可以了。
(1)事務(wù)內(nèi)部提交、回滾事務(wù)使用的是事務(wù)管理器對象,代替手動(dòng)commit、rollback。事務(wù)管理器是一個(gè)接口和其眾多的實(shí)現(xiàn)類。
接口:PlatformTransactionManager,定義了事務(wù)的重要方法 commit、rollback
實(shí)現(xiàn)類:spring把每一種數(shù)據(jù)庫訪問技術(shù)對應(yīng)的事務(wù)處理累都創(chuàng)建好了。
a、mybatis訪問數(shù)據(jù)庫—spring創(chuàng)建好的是DataSourceTransactionManager
b、hibernate訪問數(shù)據(jù)庫—spring創(chuàng)建好的是HibernateTransactionManager
怎么使用?
只需告訴spring使用哪種數(shù)據(jù)庫的訪問技術(shù)(框架),聲明數(shù)據(jù)庫訪問技術(shù)對應(yīng)的事務(wù)管理器的實(shí)現(xiàn)類,在spring的配置文件中使用<bean>聲明就可以了。例如使用mybatis訪問數(shù)據(jù)庫:
<bean id = "xxx" class = "...DataSourceTransactionManager"/>
(2)業(yè)務(wù)方法需要什么樣的事務(wù)?說明需要事務(wù)的類型。
8、事務(wù)的隔離級別
有 5 個(gè)值,其中一個(gè)是默認(rèn)。這些常量均是以ISOLATION_開頭,即形如:ISOLATION_XXX。
1、DEFAULT:采用DB默認(rèn)的事務(wù)隔離級別。MySQL的默認(rèn)隔離級別:REPEATABLE_READ(可重復(fù)讀);Oracle默認(rèn)的隔離級別:READ_COMMITTED(讀已提交)
2、READ_UNCOMMITTED:讀未提交,未解決任何并發(fā)問題。
3、READ_COMMITTED:讀已提交。解決度臟數(shù)據(jù),存在不可重復(fù)讀與幻讀。
4、REPEATABLE_READ:可重復(fù)度。解決臟讀、不可重復(fù)讀,存在幻讀。
5、SERIALIZABLE:串行化。不存在并發(fā)問題。
9、事務(wù)的超時(shí)時(shí)間
表示一個(gè)方法最長的執(zhí)行時(shí)間,如果方法執(zhí)行時(shí)超過了這個(gè)時(shí)間,事務(wù)就回滾。單位是秒,整數(shù)值,默認(rèn)是:-1(表示沒有限制最長時(shí)間)。
10、事務(wù)的傳播行為
控制業(yè)務(wù)方法是不是有事務(wù)的,是什么樣的事務(wù)的。共有 7 個(gè)傳播行為。(標(biāo)紅常用需掌握)
(1)PROPAGATION_REQUIRED:指定的方法必須在事務(wù)內(nèi)執(zhí)行。若當(dāng)前存在事務(wù),就加入當(dāng)前事務(wù)中;若當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新事務(wù)。這種創(chuàng)博行為時(shí)最常見的選擇,也是spring默認(rèn)的事務(wù)傳播行為。
(2)PROPAGATION_REQUIRES_NEW:總是新建一個(gè)事務(wù),若當(dāng)前存在事務(wù),就將當(dāng)前事務(wù)掛起,知道新事物執(zhí)行完畢。
(3)PROPAGATION_SUPPORTS:指定方法支持當(dāng)前事務(wù),但若當(dāng)前沒有事務(wù),也可以以非事務(wù)的方式執(zhí)行。
(4)PROPAGATION_MANDATORY
(5)PROPAGATION_NESTED
(6)PROPAGATION_NEVER
(7)PROPAGATION_NOT_SUPPORTED
spring boot中配置事務(wù)以及使用:
1、進(jìn)行配置類的處理
#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*
第一個(gè)配置:該方法主要是為了在操作的時(shí)候,掃描包的路徑,不是所有的方法都是走事務(wù)處理的。
第二個(gè)配置:配置處理的時(shí)間大小36秒
第三個(gè)配置:為了限制規(guī)則,比如說方法的名稱必須是什么開頭的,只有這些方法名稱開頭的才會(huì)走事務(wù)的處理
第四個(gè)配置:讀取的規(guī)則的方法名稱開頭的命名
第五個(gè)配置:事務(wù)的處理規(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("關(guān)閉連接失敗", 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í)際代碼里面調(diào)用實(shí)踐:
第一種:添加異常方法,直接調(diào)用接口,就可以看到相關(guān)的效果,只不過需要在數(shù)據(jù)庫變更的后面,添加相關(guān)的異常拋出,讓整個(gè)方法異常,然后看一下這個(gè)數(shù)據(jù)庫的記錄沒有變化,已經(jīng) 回滾了;
第二種:去除異常方法,讓整個(gè)方法正常執(zhí)行下去,通過 數(shù)據(jù)庫查詢一下記錄,看一下數(shù)據(jù)是更新是成功落庫的;
總結(jié):
目前網(wǎng)絡(luò)上面搜索到的都是直接使用的注解進(jìn)行事務(wù)的處理,而不是根據(jù)配置文件進(jìn)行配置規(guī)則、以及事務(wù)的統(tǒng)一管理處理,比如說方法名稱進(jìn)行切面的處理,那些方法是會(huì)進(jìn)行mybatis(數(shù)據(jù)庫的更新處理會(huì)走事務(wù)處理),比如說,目前的很多大型公司,或者說需要保持事務(wù)一致性的公司都會(huì)用到,整個(gè)的調(diào)用鏈比較長,如果中途出現(xiàn)了問題,會(huì)進(jìn)行事務(wù)的回滾處理,避免了很多的問題(數(shù)據(jù)庫里面存在垃圾數(shù)據(jù)的問題);
到此這篇關(guān)于springboot結(jié)合mybatis操作事務(wù)配置的處理的文章就介紹到這了,更多相關(guān)springboot mybatis事務(wù)配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring定時(shí)任務(wù)實(shí)現(xiàn)與配置(二)
這篇文章主要為大家詳細(xì)介紹了Spring定時(shí)任務(wù)的實(shí)現(xiàn)與配置第二篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Java中BigDecimal類與int、Integer使用總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中BigDecimal類與int、Integer使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Java實(shí)現(xiàn)狀態(tài)模式的示例代碼
狀態(tài)模式是一種行為型設(shè)計(jì)模式,允許對象根據(jù)其內(nèi)部狀態(tài)改變行為,本文主要介紹了Java實(shí)現(xiàn)狀態(tài)模式的示例代碼,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02SpringBoot項(xiàng)目集成依賴Mybatis步驟
在本篇文章中小編給大家分享了關(guān)于SpringBoot項(xiàng)目如何集成依賴Mybatis的相關(guān)知識點(diǎn)內(nèi)容,有興趣的朋友們學(xué)習(xí)下。2019-06-06關(guān)于Java數(shù)組查詢的相關(guān)問題及實(shí)例
這篇文章主要介紹了關(guān)于Java數(shù)組查詢的相關(guān)問題及實(shí)例,需要的朋友可以參考下。2017-08-08