`
Feiing
  • 浏览: 239258 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Spring 事务简化配置

阅读更多
在 spring 中,  事务管理一般是通过声明一个 txProxyTemplate,  然后业务 bean 中 parent = "txProxyTemplate",  这样做未免显得有些繁琐,  并且如果业务 bean 还需要其他拦截器,  配置也不太方便,  下面贴出我的配置, 用 DefaultAdvisorAutoProxyCreator 实现自动代理

<beans>
	<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
    <bean id="transactionManager"
          class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          <property name="sessionFactory">
              <ref bean="sessionFactory"/>
          </property>
    </bean>	
	
	<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    	<property name="transactionManager" ref="transactionManager"/>
		<property name="transactionAttributeSource">
		  <value>
			com.skyon.user.manager.UserManager.*=PROPAGATION_REQUIRED
			#Add new defines here ->
		  </value>
		</property>
	</bean>
	
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
		<property name="interceptorNames">
			<list>
				<value>transactionInterceptor</value>
				<!--
				增加新的 Interceptor
				-->
			</list>
		</property>
	</bean>

	<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
	  <property name="transactionInterceptor" ref="transactionInterceptor"/>
	</bean>
		
</beans>



这里利用 DefaultAdvisorAutoProxyCreator 实现了对容器中所有 bean 的自动代理,  增加一个需要事务的业务 bean 时只要在 transactionInterceptor 增加一行即可,  增加别的 interceptor 也非常方便,
极大减少了配置量
分享到:
评论
44 楼 flyeagle 2007-03-29  
   这个贴没人给跟一下吗?请大家指点一下
43 楼 flyeagle 2007-03-29  
  看来这个贴是没有人回复了,这个问题到底是怎么产生的呢?
42 楼 flyeagle 2007-03-29  
  我使用hongliang给出的配置方法出现了问题,请大家指点一下:
   配置如下:
 

	<bean id="userSortDao"
		class="com.hengji.dao.impl.UserSortDaoImpl">
		<property name="sqlMapClient">
			<ref bean="sqlMapClient" />
		</property>
	</bean>
	<bean id="userSort[b]Service[/b]"
		class="com.hengji.service.impl.UserSortServiceImpl">
		<property name="userSortDao">
			<ref bean="userSortDao" />
		</property>
	</bean>
<bean id="transactionInterceptor"
		class="org.springframework.transaction.interceptor.TransactionInterceptor">
		<property name="transactionManager" ref="transactionManager" />
		<property name="transactionAttributes">
			<props>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
			</props>
		</property>
	</bean>
	<bean
		class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<value>*Service</value><!-- <value>*Service,*Manager</value> -->
		</property>
		<property name="interceptorNames">
			<list>
				<value>transactionInterceptor</value>
				<!--   
					此处增加新的Interceptor  
				-->
			</list>
		</property>
	</bean>

	<bean
		class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
		<property name="transactionInterceptor"
			ref="transactionInterceptor" />
	</bean>

  在不加入事务时,插入和查询没问题,在加入上面事务后,可以插入,但是在检索时出现如下问题:
The error occurred while applying a result map.  
--- Check the UserSort.resultUserSort.  
--- The error happened while setting a property on the result object.  
--- Cause: [b]java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Can't [/b]start a cloned connection while in manual transaction mode.
	at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:185)
	at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForList(GeneralStatement.java:123)
	at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:615)
	at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:589)
	at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:118)


这是为什么呢?
41 楼 小疯子 2007-02-26  
hermitte 写道
    <aop:config>
        
        <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Manager.*(..))" order="2"/>
    </aop:config>
   
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

上面是appfuse里的,我觉得比LZ的要简洁点
下面的service也好配置

<bean id="roleManager" class="org.appfuse.service.impl.RoleManagerImpl">
        <property name="roleDao" ref="roleDao"/>
    </bean>
这样就可以了



呵呵...都快一年了,版本都不一样了吧!
40 楼 piaochunzhi 2007-02-26  
我不懂 SPRING 感觉 配置文件真让人头疼 ,看了都疼!
39 楼 hermitte 2007-02-03  
    <aop:config>
        
        <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Manager.*(..))" order="2"/>
    </aop:config>
   
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

上面是appfuse里的,我觉得比LZ的要简洁点
下面的service也好配置

<bean id="roleManager" class="org.appfuse.service.impl.RoleManagerImpl">
        <property name="roleDao" ref="roleDao"/>
    </bean>
这样就可以了

38 楼 blackstreet 2007-02-02  
org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor

这个起到什么用处
37 楼 wuyingsong 2007-02-01  
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">   
                <property name="beanNames"> 
                    <value>*Service,*Manager</value> 
                </property> 
                <property name="interceptorNames">   
                        <list>   
                                <value>transactionInterceptor</value>   
                                <!--  
                                此处增加新的Interceptor 
                                -->   
                        </list>   
                </property>   
        </bean>   
其实你只是这儿<value>*Service,*Manager</value> 用了通配符而已
36 楼 loaer 2007-01-31  
<div class='code_title'>xml 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-xml'>
    <li class='alt'><span><span class='tag'>&lt;</span><span class='tag-name'>bean</span><span>  </span></span></li>
    <li class=''><span>        </span><span class='attribute'>class</span><span>=</span><span class='attribute-value'>"org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"</span><span class='tag'>&gt;</span><span>  </span></li>
    <li class='alt'><span>        </span><span class='tag'>&lt;</span><span class='tag-name'>property</span><span> </span><span class='attribute'>name</span><span>=</span><span class='attribute-value'>"transactionInterceptor"</span><span>  </span></li>
    <li class=''><span>            </span><span class='attribute'>ref</span><span>=</span><span class='attribute-value'>"transactionInterceptor"</span><span> </span><span class='tag'>/&gt;</span><span>  </span></li>
    <li class='alt'><span>    </span><span class='tag'>&lt;/</span><span class='tag-name'>bean</span><span class='tag'>&gt;</span><span>  </span></li>
</ol>
</div>
<br/>
是多余的吧?
35 楼 loaer 2007-01-31  
<bean
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor"
ref="transactionInterceptor" />
</bean>

是多余的吧?
34 楼 loaer 2007-01-31  
<!-- 
     增加新的 Interceptor 
--> 

请问这个是用来干什么的?
33 楼 Leapiny 2007-01-25  
Feiing 写道
呵呵, 想不到大家反响这么激烈, 我说一下自己的想法
3. 说到事务控制, 其实我的项目是放在 Action 做的, 可能要被鄙视了, 我们用 xwork Interceptor 实现, 再加上 webwork
   <default-interceptor-ref name="defaultStack" /> 的功能, 基本上完全不用再管事务, 当然策略只能是 PROPAGATION_REQUIRED 了


不是有意挖坟,确实有问题想交流。

为了尽量使接口简洁点,尝试把事务放在action中 (webwork),但是对action外面包一层事务处理后,action就不能用了,现在想到的也是自己做个拦截器,所有的方法都是 PROPAGATION_REQUIRED ,总觉得不太好,不知道有没有人有在action中处理事务的经验给介绍下。
32 楼 差沙 2006-04-07  
autowire="byName"会自动根据你的属性的名字帮你注入你要的bean,要不就要手动写明。
31 楼 liuyifan.com 2006-04-07  
autowire="byName" 不是必需的吧
30 楼 cnsdl 2006-04-04  
如果想PROPAGATION_REQUIRED,readOnly,写了接口也不方便,支持feiing
29 楼 hongliang 2006-03-30  
差沙 写道
hongliang 写道

啊!!!这个我还真的没有注意到,因为我所有的Service层都是*Service,我从来不用*Manager的。。。怪不得我的没问题,


关键是你的事务管理对象的名字是*Manager呀,怎么会没有问题出现呢?难道是我的人品问题??


我上面给的代码写的是*Service,*Manager,是为叻迎合大家的口味 我自己不用*Manager,只有*Service 
28 楼 差沙 2006-03-30  
hongliang 写道

啊!!!这个我还真的没有注意到,因为我所有的Service层都是*Service,我从来不用*Manager的。。。怪不得我的没问题,


关键是你的事务管理对象的名字是*Manager呀,怎么会没有问题出现呢?难道是我的人品问题??
27 楼 hongliang 2006-03-30  
差沙 写道
受hongliang启发,我现在就用这个方法,但是发现一个Bug。里面代理匹配的名字有*Manager,就是想匹配所有的ManagerObject。但是好像没有注意到,这样配置会把transactionManager也匹配上,然后定义的是find以外的方法都是要事务的。也就说transactionManager执行getTransaction的时候还会要事务,然后就是死循环,造成溢出。。

我解决的办法就是transactionManager改称transactionManagerHibernate。这么做的时候一定要注意名字的问题。别一不小心,把一个不相关的东东给弄进来的。。。

对了,加Acegi的时候有很多*Manager,打算想一个比较好名字匹配。。


啊!!!这个我还真的没有注意到,因为我所有的Service层都是*Service,我从来不用*Manager的。。。怪不得我的没问题,
26 楼 差沙 2006-03-30  
hongliang 写道
完整版来叻!!
下面的是Feiing给出的更好的方案,我有一些修改:

<beans> 
        <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA); --> 
    <bean id="transactionManager"           class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
          <property name="sessionFactory"> 
              <ref bean="sessionFactory"/> 
          </property> 
    </bean>        
        
        <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> 
            <property name="transactionManager" ref="transactionManager"/> 
            <property name="transactionAttributes">
                <props>
                    <prop key="*">PROPAGATION_REQUIRED</prop>
                    <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                </props>
            </property>
        </bean> 
        
        <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
                <property name="beanNames">
                    <value>*Service,*Manager</value>
                </property>
                <property name="interceptorNames"> 
                        <list> 
                                <value>transactionInterceptor</value> 
                                <!-- 
                                此处增加新的Interceptor
                                --> 
                        </list> 
                </property> 
        </bean> 

        <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> 
          <property name="transactionInterceptor" ref="transactionInterceptor"/> 
        </bean> 


        <bean id="userManager" class="some.package.UserManagerImpl" autoWire="byName"/>
                
</beans> 


以后每次的增量是这一段:
        <bean id="userManager" class="some.package.UserManagerImpl" autoWire="byName"/>


跟配置普通bean的方法一样,非常简洁、直观。对现有的Service接口也无须任何修改

我把Feiing的transactionAttributesSource改成叻transactionAttributes,并且将DefaultAdvisorAutoProxyCreator改成了BeanNameAutoProxyCreator,我觉得毕竟不是context下的每个bean都需要事务,只要在Service层做AOP就可以叻。

和Robbin一致认为,Feiing的做法非常可取,因为它分离叻XML配置文件关注点


受hongliang启发,我现在就用这个方法,但是发现一个Bug。里面代理匹配的名字有*Manager,就是想匹配所有的ManagerObject。但是好像没有注意到,这样配置会把transactionManager也匹配上,然后定义的是find以外的方法都是要事务的。也就说transactionManager执行getTransaction的时候还会要事务,然后就是死循环,造成溢出。。

我解决的办法就是transactionManager改称transactionManagerHibernate。这么做的时候一定要注意名字的问题。别一不小心,把一个不相关的东东给弄进来的。。。

对了,加Acegi的时候有很多*Manager,打算想一个比较好名字匹配。。
25 楼 sunandrain 2006-03-27  
这样配置,在单独测试usermanager时,没有问题.
但当放到tomcat中,通过action调用usermanager时却出现异常,用以前的那种配法没有出现问题.
Exception:
2006-03-27 12:35:21,377 ERROR [com.opensymphony.webwork.dispatcher.DispatcherUtils] - Could not execute action
java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method);
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39);
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25);
	at java.lang.reflect.Method.invoke(Method.java:585);
	at com.opensymphony.xwork.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:353);
	at com.opensymphony.xwork.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:208);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:182);
	at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:32);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:180);
	at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:32);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:180);
	at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:32);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:180);
	at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:32);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:180);
	at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:32);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:180);
	at com.opensymphony.xwork.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:94);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:180);
	at com.opensymphony.xwork.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:94);
	at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:180);
	at com.opensymphony.xwork.DefaultActionProxy.execute(DefaultActionProxy.java:119);
	at com.opensymphony.webwork.dispatcher.DispatcherUtils.serviceAction(DispatcherUtils.java:183);
	at com.opensymphony.webwork.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:182);
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202);
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173);
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213);
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178);
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126);
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105);
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107);
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148);
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869);
	at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:667);
	at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527);
	at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80);
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684);
	at java.lang.Thread.run(Thread.java:595);
Caused by: java.lang.StackOverflowError
	at java.lang.System.identityHashCode(Native Method);
	at java.util.IdentityHashMap.hash(IdentityHashMap.java:283);
	at java.util.IdentityHashMap.get(IdentityHashMap.java:313);
	at org.springframework.aop.framework.HashMapCachingAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(HashMapCachingAdvisorChainFactory.java:44);
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:154);
	at $Proxy1.getTransaction(Unknown Source);
	at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:217);
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:89);
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:144);
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:174);
	at $Proxy1.getTransaction(Unknown Source);
......

相关推荐

    spring事务配置的五种方式

    ### Spring事务配置的五种方式详解 #### 一、引言 在企业级应用开发中,事务处理是非常重要的一部分,特别是在涉及多个数据库操作时。Spring框架提供了强大的事务管理功能,支持编程式和声明式两种事务处理方式。...

    Spring 事务代理配置

    最后,需要将事务拦截器应用到具体的目标类上,通常是在`aop:config`标签下配置切入点和增强,或者通过`@Transactional`注解来简化配置。 ```xml (* com.example.service.*.*(..))"/&gt; ``` 或者使用`@...

    Spring事务管理开发必备jar包

    本资源包提供了进行Spring事务管理开发所需的所有关键库,包括框架基础、核心组件、AOP(面向切面编程)支持、日志处理、编译工具以及与数据库交互的相关jar包。下面将对这些知识点进行详细解释: 1. **Spring框架*...

    spring事务案例分析.zip

    7. **案例分析**:"SPRING事务管理案例分析.docx"很可能包含了具体的项目实例,详细讲解了如何在Spring项目中配置和使用事务管理,以及如何解决实践中遇到的问题。而"studyspring"可能是源代码目录,包含了实现这些...

    spring 事务传播 demo

    在Java后端开发中,Spring的事务管理机制大大简化了事务控制,使得开发者可以更专注于业务逻辑,而不用关心底层事务的管理。通过声明式事务管理,我们只需在方法上添加@Transactional注解,而无需编写手动的try-...

    spring声明事务的配置

    此外,Spring Boot简化了Spring应用的启动和配置,包括事务管理,使得在现代项目中使用声明式事务更加便捷。 总的来说,Spring声明式事务管理提供了一种强大且灵活的方式来控制事务的边界,使得事务管理与业务逻辑...

    Spring事务管理配置

    在深入探讨Spring事务管理配置之前,我们先简要回顾一下Spring框架的核心概念。Spring是一个开源的Java平台,它提供了一套全面的编程和配置模型,旨在简化企业级应用的开发。其中,事务管理是Spring框架中的一个重要...

    实验 spring 声明事务

    Spring 提供了声明式事务管理,允许开发者在不编写事务管理代码的情况下实现事务控制,极大地简化了事务处理。 实验环境主要包括 Eclipse 或 MyEclipse 开发工具,以及 Spring 4.0 及以上版本,JDK 1.7 及以上版本...

    Spring事务五种不同的代理配置

    第一种方式需要手动配置事务规则,而第二、三种方式通过注解简化了配置,第四种方式适用于不依赖接口的情况,第五种方式则提供了最大的灵活性。在实际开发中,我们通常会选择基于注解的声明式事务管理,因为它既简洁...

    Spring事务配置的五种方式

    这种方式的优点是可以简化配置文件,但是缺点是需要了解 AOP 的机制和实现。 第三种方式:使用代理工厂 这种方式使用了 Spring 的代理工厂机制,可以将事务管理器注入到 Bean 中。这种方式的优点是可以灵活地控制...

    Spring基于XML方式配置事务

    结合上述配置,Spring会自动管理事务的开始、提交、回滚等操作,大大简化了事务管理的代码。在实际项目中,根据业务需求,我们可以灵活调整这些配置,以实现高效、安全的事务处理。 在提供的压缩包文件`Spring-JDBC...

    spring 事务基于注解模式

    Spring事务管理分为编程式和声明式两种。编程式事务管理通过编程的方式(如使用`TransactionTemplate`或直接调用`PlatformTransactionManager`)来控制事务的开始、提交、回滚等操作。而声明式事务管理则是在配置...

    Spring事务优缺点及使用详解.docx

    Spring事务管理提供了统一的事务处理模型,使得开发者无需关注具体数据库访问技术的事务细节,简化了事务控制代码,提高了代码的可读性和可维护性。无论是使用注解还是AOP配置,都能有效地管理和协调事务,确保应用...

    Spring事务详解

    本文将深入探讨Spring事务管理的概念、类型、配置方式以及在实际开发中的应用。 首先,我们要理解什么是事务。事务是数据库操作的基本单元,它确保一组数据库操作要么全部成功,要么全部失败。事务有四大特性,即...

    Spring的事务管理小案例

    在本文中,我们将深入探讨Spring框架中的事务管理。Spring是一个广泛应用的Java企业级应用开发框架,它提供...如果你想要深入了解,可以参考提供的博客链接或其他相关资料,进一步学习Spring事务管理的细节和最佳实践。

    spring声明式事务配置

    根据提供的信息,我们可以深入探讨Spring框架中的声明式事务配置及其多种实现方式。声明式事务管理是一种简化事务管理的方式,它允许开发人员通过配置而非编程来指定事务边界,从而减少了代码的复杂性并提高了可维护...

    Spring 事务配置详解(多种配置方法)

    Spring 2.5引入了注解事务管理,可以直接在Service层的方法上添加@Transactional注解,简化配置。例如: ```java @Service public class UserService { @Transactional public void addUser(User user) { // ...

    spring事务管理5种方法

    本篇文章将深入探讨Spring事务管理的五种方法,旨在帮助开发者更好地理解和运用这一核心特性。 首先,我们来了解什么是事务。在数据库操作中,事务是一组逻辑操作,这些操作要么全部成功,要么全部失败,确保数据的...

Global site tag (gtag.js) - Google Analytics