Spring+iBatis+JOTM实现JTA事务

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

JOTM是个开源的JTA事务管理组件,可以让程序脱离J2EE容器而获得分布式事务管理的能力。

 
测试过程如下:
 
一、环境
 
1、准备软件环境

 spring-framework-2.5.6.SEC01-with-dependencies.zip
 ibatis-2.3.4
 ow2-jotm-dist-2.1.4-bin.tar.gz
 MySQL-5.1
 JDK1.5
 
2、创建数据库环境,注意数据库引擎为InnoDB,只有这样才能支持事务。
 
CREATE  DATABASE  IF  NOT  EXISTS testdb_a     DEFAULT CHARACTER  SET utf8; 

USE testdb_a; 

DROP  TABLE  IF  EXISTS tab_a; 

CREATE  TABLE tab_a ( 
    id  bigint(20)  NOT  NULL
     name  varchar(60)  DEFAULT  NULL
    address  varchar(120)  DEFAULT  NULL
     PRIMARY  KEY (id) 
) ENGINE=InnoDB  DEFAULT CHARSET=utf8; 


CREATE  DATABASE  IF  NOT  EXISTS testdb_b     DEFAULT CHARACTER  SET utf8; 

USE testdb_b; 

DROP  TABLE  IF  EXISTS tab_b; 

CREATE  TABLE tab_b ( 
    id  bigint(20)  NOT  NULL
     name  varchar(60)  DEFAULT  NULL
    address  varchar(120)  DEFAULT  NULL
     PRIMARY  KEY (id) 
) ENGINE=InnoDB  DEFAULT CHARSET=utf8; 


二、建立项目testJOTM
 
1、建立项目后,准备依赖的类库,结构如下:
│    spring-aop.jar 
│    spring-beans.jar 
│    spring-context-support.jar 
│    spring-context.jar 
│    spring-core.jar 
│    spring-jdbc.jar 
│    spring-jms.jar 
│    spring-orm.jar 
│    spring-test.jar 
│    spring-tx.jar 
│    spring-web.jar 
│    spring-webmvc-portlet.jar 
│    spring-webmvc-struts.jar 
│    spring-webmvc.jar 
│    aspectjrt.jar 
│    aspectjweaver.jar 
│    cglib-nodep-2.1_3.jar 
│    asm-2.2.3.jar 
│    log4j-1.2.15.jar 
│    asm-commons-2.2.3.jar 
│    asm-util-2.2.3.jar 
│    aopalliance.jar 
│    mysql-connector-java-5.1.6-bin.jar 
│ 
├─ibatis 
│            ibatis-2.3.4.726.jar 
│            sql-map-2.dtd 
│            sql-map-config-2.dtd 
│ 
├─jotm 
│            license.txt 
│            xapool.jar 
│            jotm-core.jar 
│            jotm-standalone.jar 
│            jotm-jms.jar 
│            jotm-datasource.jar 
│            ow2-jta-1.1-spec.jar 
│            jotm-client.jar 
│ 
├─jakarta-commons 
│            commons-attributes-api.jar 
│            commons-attributes-compiler.jar 
│            commons-beanutils.jar 
│            commons-codec.jar 
│            commons-collections.jar 
│            commons-dbcp.jar 
│            commons-digester.jar 
│            commons-discovery.jar 
│            commons-fileupload.jar 
│            commons-httpclient.jar 
│            commons-io.jar 
│            commons-lang.jar 
│            commons-logging.jar 
│            commons-pool.jar 
│            commons-validator.jar 
│ 
├─junit 
│            junit-3.8.2.jar 
│            junit-4.4.jar 
│            license.txt 
│ 
└─log4j 
                log4j-1.2.15.jar
 
2、根据表建立entity和SQLMap
public  class TabA  implements Serializable { 
         private Long id; 
         private String name; 
         private String address; 
         //省略getter/setter
 
public  class TabB  implements Serializable { 
         private Long id; 
         private String name; 
         private String address; 
         //省略getter/setter

TabA.xml
<? xml  version ="1.0"  encoding ="UTF-8"  ?> 
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" > 

<!--  表名:tab_a --> 
< sqlMap  namespace ="tab_a" > 
         < typeAlias  alias ="TabA"  type ="com.lavasoft.stu.jtom.entity.TabA" /> 
         < resultMap  id ="result_base"  class ="TabA" > 
                 < result  property ="id"  column ="id" /> 
                 < result  property ="name"  column ="name" /> 
                 < result  property ="address"  column ="address" /> 
         </ resultMap > 
        <!--  添加 --> 
         < insert  id ="insert"  parameterClass ="TabA" > 
                insert into tab_a( 
                id, 
                name, 
                address 
                ) values ( 
                #id#, 
                #name#, 
                #address# 
                ) 
                 < selectKey  keyProperty ="id"  resultClass ="long" > 
                        select LAST_INSERT_ID() 
                 </ selectKey > 
         </ insert > 
        <!--  更新 --> 
         < update  id ="update"  parameterClass ="TabA" > 
                update tab_a set 
                id = #id#, 
                name = #name#, 
                address = #address# 
                where id = #id# 
         </ update > 
        <!--  删除 --> 
         < delete  id ="deleteById"  parameterClass ="long" > 
                delete from tab_a 
                where id = #value# 
         </ delete > 
        <!--  根据ID获取 --> 
         < select  id ="findById"  parameterClass ="long"  resultMap ="tab_a.result_base" > 
                select * 
                from tab_a 
                where id = #value# 
         </ select > 
</ sqlMap >
 
TabB.xml
<? xml  version ="1.0"  encoding ="UTF-8"  ?> 
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" > 

<!--  表名:tab_b --> 
< sqlMap  namespace ="tab_b" > 
         < typeAlias  alias ="TabB"  type ="com.lavasoft.stu.jtom.entity.TabB" /> 
         < resultMap  id ="result_base"  class ="TabB" > 
                 < result  property ="id"  column ="id" /> 
                 < result  property ="name"  column ="name" /> 
                 < result  property ="address"  column ="address" /> 
         </ resultMap > 
        <!--  添加 --> 
         < insert  id ="insert"  parameterClass ="TabB" > 
                insert into tab_b( 
                id, 
                name, 
                address 
                ) values ( 
                #id#, 
                #name#, 
                #address# 
                ) 
                 < selectKey  keyProperty ="id"  resultClass ="long" > 
                        select LAST_INSERT_ID() 
                 </ selectKey > 
         </ insert > 
        <!--  更新 --> 
         < update  id ="update"  parameterClass ="TabB" > 
                update tab_b set 
                id = #id#, 
                name = #name#, 
                address = #address# 
                where id = #id# 
         </ update > 
        <!--  删除 --> 
         < delete  id ="deleteById"  parameterClass ="long" > 
                delete from tab_b 
                where id = #value# 
         </ delete > 
        <!--  根据ID获取 --> 
         < select  id ="findById"  parameterClass ="long"  resultMap ="tab_b.result_base" > 
                select * 
                from tab_b 
                where id = #value# 
         </ select > 
</ sqlMap >
 
/** 
* TabADAO 

* @author leizhimin 2009-6-25 12:39:19 
*/
 
public  interface TabADAO { 

         /** 
         * 保存一个TabA对象 
         * 
         * @param tabA TabA对象 
         * @return 返回保存后的对象 
         */
 
        TabA saveTabA(TabA tabA); 

         /** 
         * 更新一个TabA 
         * 
         * @param tabA TabA对象 
         * @return 返回更新后的对象 
         */
 
        TabA updateTabA(TabA tabA); 

         /** 
         * 删除指定标识的一个TabA 
         * 
         * @param id TabA标识 
         */
 
         void deleteTabAById(Long id); 

         /** 
         * 获取指定标识的TabA 
         * 
         * @param id TabA标识 
         * @return 所查询到的TabA 
         */
 
        TabA findTabAById(Long id); 
}
 
/** 
* TabADAO 

* @author leizhimin 2009-6-25 12:43:55 
*/
 
public  class TabADAOImpl  extends SqlMapClientDaoSupport  implements TabADAO { 

         /** 
         * 保存一个TabA对象 
         * 
         * @param tabA TabA对象 
         * @return 返回保存后的对象 
         */
 
         public TabA saveTabA(TabA tabA) { 
                Long id = (Long) getSqlMapClientTemplate().insert( "tab_a.insert", tabA); 
                tabA.setId(id); 
                 return tabA; 
        } 

         /** 
         * 更新一个TabA 
         * 
         * @param tabA TabA对象 
         * @return 返回更新后的对象 
         */
 
         public TabA updateTabA(TabA tabA) { 
                getSqlMapClientTemplate().update( "tab_a.update", tabA); 
                 return tabA; 
        } 

         /** 
         * 删除指定标识的一个TabA 
         * 
         * @param id TabA标识 
         */
 
         public  void deleteTabAById(Long id) { 
                getSqlMapClientTemplate().delete( "tab_a.deleteById",id); 
        } 

         /** 
         * 获取指定标识的TabA 
         * 
         * @param id TabA标识 
         * @return 所查询到的TabA 
         */
 
         public TabA findTabAById(Long id) { 
                 return (TabA) getSqlMapClientTemplate().queryForObject( "tab_a.findById",id); 
        } 
}
 
B的DAO和A类似,就不写了。
 
/** 
* 测试JOTM的Service 

* @author leizhimin 2009-6-25 12:53:55 
*/
 
public  interface StuJotmService { 
         /** 
         * 同时保存TabA、TabB 
         * 
         * @param a TabA对象 
         * @param b TabB对象 
         */
 
         void saveAB(TabA a, TabB b); 

         /** 
         * 同时更新TabA、TabB 
         * 
         * @param a TabA对象 
         * @param b TabB对象 
         */
 
         void updateAB(TabA a, TabB b); 

         /** 
         * 删除指定id的TabA、TabB记录 
         * 
         * @param id 指定id 
         */
 
         void deleteABif(Long id); 
}
 
/** 
* Created by IntelliJ IDEA. 

* @author leizhimin 2009-6-25 12:58:48 
*/
 
//@Transactional 
public  class StuJotmServiceImpl  implements StuJotmService { 
         private TabADAO tabADAO; 
         private TabBDAO tabBDAO; 

         /** 
         * 同时保存TabA、TabB 
         * 
         * @param a TabA对象 
         * @param b TabB对象 
         */
 
//        @Transactional(readOnly=false) 
         public  void saveAB(TabA a, TabB b) { 
                tabADAO.saveTabA(a); 
                tabBDAO.saveTabB(b); 
        } 

         /** 
         * 同时更新TabA、TabB 
         * 
         * @param a TabA对象 
         * @param b TabB对象 
         */
 
//        @Transactional(readOnly=false) 
         public  void updateAB(TabA a, TabB b) { 
                tabADAO.updateTabA(a); 
                tabBDAO.updateTabB(b); 
        } 

         /** 
         * 删除指定id的TabA、TabB记录 
         * 
         * @param id 指定id 
         */
 
//        @Transactional(readOnly=false) 
         public  void deleteABif(Long id) { 
                tabADAO.deleteTabAById(id); 
                tabBDAO.deleteTabBById(id); 
        } 

         public  void setTabADAO(TabADAO tabADAO) { 
                 this.tabADAO = tabADAO; 
        } 

         public  void setTabBDAO(TabBDAO tabBDAO) { 
                 this.tabBDAO = tabBDAO; 
        } 
}
 
/** 
* Spring上下文工具 

* @author leizhimin 2008-8-13 14:42:58 
*/
 

public  class ApplicationContextUtil { 
         private  static ApplicationContext applicationContext; 

         static { 
                 if (applicationContext ==  null
                        applicationContext = rebuildApplicationContext(); 
        } 

         /** 
         * 重新构建Spring应用上下文环境 
         * 
         * @return ApplicationContext 
         */
 
         public  static ApplicationContext rebuildApplicationContext() { 
                 return  new ClassPathXmlApplicationContext( "/ApplicationContext.xml"); 
        } 

         /** 
         * 获取Spring应用上下文环境 
         * 
         * @return 
         */
 
         public  static ApplicationContext getApplicationContext() { 
                 return applicationContext; 
        } 

         /** 
         * 简单的上下文环境测试 
         */
 
         public  static  void main(String[] args) { 
                rebuildApplicationContext(); 
                 if (applicationContext ==  null) { 
                        System.out.println( "ApplicationContext is null"); 
                }  else { 
                        System.out.println( "ApplicationContext is not null!"); 
                } 
        } 
}
 
三、做JTOM、Spring、iBatis、Log4j等配置
 
JOTM配置:carol.properties
#JNDI调用协议 
carol.protocols=jrmp 
#不使用CAROL JNDI封装器        
carol.start.jndi=false 
#不启动命名服务器 
carol.start.ns=false 
 
Spring配置: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:jee ="http://www.springframework.org/schema/jee" 
              xmlns:aop ="http://www.springframework.org/schema/aop" 
              xmlns:tx ="http://www.springframework.org/schema/tx" 
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
                     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd 
                     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd 
                     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd" > 

        <!-- 指定Spring配置中用到的属性文件--> 
         < bean  id ="propertyConfig" 
                     class ="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" > 
                 < property  name ="locations" > 
                         < list > 
                                 < value >classpath:jdbc.properties </ value > 
                         </ list > 
                 </ property > 
         </ bean > 
        <!--  JOTM实例 --> 
         < bean  id ="jotm"  class ="org.springframework.transaction.jta.JotmFactoryBean" /> 
        <!--  JTA事务管理器 --> 
         < bean  id ="myJtaManager" 
                     class ="org.springframework.transaction.jta.JtaTransactionManager" > 
                 < property  name ="userTransaction" > 
                         < ref  local ="jotm" /> 
                 </ property > 
         </ bean > 
        <!--  数据源A --> 
         < bean  id ="dataSourceA"  class ="org.enhydra.jdbc.pool.StandardXAPoolDataSource"  destroy-method ="shutdown" > 
                 < property  name ="dataSource" > 
                         < bean  class ="org.enhydra.jdbc.standard.StandardXADataSource"  destroy-method ="shutdown" > 
                                 < property  name ="transactionManager"  ref ="jotm" /> 
                                 < property  name ="driverName"  value ="${jdbc.driver}" /> 
                                 < property  name ="url"  value ="${jdbc.url}" /> 
                         </ bean > 
                 </ property > 
                 < property  name ="user"  value ="${jdbc.username}" /> 
                 < property  name ="password"  value ="${jdbc.password}" /> 
         </ bean > 
        <!--  数据源B --> 
         < bean  id ="dataSourceB"  class ="org.enhydra.jdbc.pool.StandardXAPoolDataSource"  destroy-method ="shutdown" > 
                 < property  name ="dataSource" > 
                         < bean  class ="org.enhydra.jdbc.standard.StandardXADataSource"  destroy-method ="shutdown" > 
                                 < property  name ="transactionManager"  ref ="jotm" /> 
                                 < property  name ="driverName"  value ="${jdbc2.driver}" /> 
                                 < property  name ="url"  value ="${jdbc2.url}" /> 
                         </ bean > 
                 </ property > 
                 < property  name ="user"  value ="${jdbc2.username}" /> 
                 < property  name ="password"  value ="${jdbc.password}" /> 
         </ bean > 
        <!--  事务切面配置 --> 
         < aop:config > 
                 < aop:pointcut  id ="serviceOperation" 
                                             expression ="execution(* *..servi1ce*..*(..))" /> 
                 < aop:advisor  pointcut-ref ="serviceOperation" 
                                          advice-ref ="txAdvice" /> 
         </ aop:config > 
        <!--  通知配置 --> 
         < tx:advice  id ="txAdvice"  transaction-manager ="myJtaManager" > 
                 < tx:attributes > 
                         < tx:method  name ="delete*"  rollback-for ="Exception" /> 
                         < tx:method  name ="save*"  rollback-for ="Exception" /> 
                         < tx:method  name ="update*"  rollback-for ="Exception" /> 
                         < tx:method  name ="*"  read-only ="true"  rollback-for ="Exception" /> 
                 </ tx:attributes > 
         </ tx:advice > 

        <!-- 根据dataSourceA和sql-map-config_A.xml创建一个SqlMapClientA--> 
         < bean  id ="sqlMapClientA" 
                     class ="org.springframework.orm.ibatis.SqlMapClientFactoryBean" > 
                 < property  name ="dataSource" > 
                         < ref  local ="dataSourceA" /> 
                 </ property > 
                 < property  name ="configLocation" > 
                         < value >sql-map-config_A.xml </ value > 
                 </ property > 
         </ bean > 
        <!-- 根据dataSourceB和sql-map-config_B.xml创建一个SqlMapClientB--> 
         < bean  id ="sqlMapClientB" 
                     class ="org.springframework.orm.ibatis.SqlMapClientFactoryBean" > 
                 < property  name ="dataSource" > 
                         < ref  local ="dataSourceB" /> 
                 </ property > 
                 < property  name ="configLocation" > 
                         < value >sql-map-config_B.xml </ value > 
                 </ property > 
         </ bean > 
        <!-- 根据sqlMapClientA创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateA--> 
         < bean  id ="sqlMapClientTemplateA" 
                     class ="org.springframework.orm.ibatis.SqlMapClientTemplate" > 
                 < property  name ="sqlMapClient"  ref ="sqlMapClientA" /> 
         </ bean > 
        <!-- 根据sqlMapClientB创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateB--> 
         < bean  id ="sqlMapClientTemplateB" 
                     class ="org.springframework.orm.ibatis.SqlMapClientTemplate" > 
                 < property  name ="sqlMapClient"  ref ="sqlMapClientB" /> 
         </ bean > 

        <!--  配置DAO,并注入所使用的sqlMapClientTemplate实例 --> 
         < bean  id ="tabADAO"  class ="com.lavasoft.stu.jtom.dao.impl.TabADAOImpl" > 
                 < property  name ="sqlMapClientTemplate"  ref ="sqlMapClientTemplateA" /> 
         </ bean > 
         < bean  id ="tabBDAO"  class ="com.lavasoft.stu.jtom.dao.impl.TabBDAOImpl" > 
                 < property  name ="sqlMapClientTemplate"  ref ="sqlMapClientTemplateB" /> 
         </ bean > 

        <!--  Service配置,注入DAO --> 
         < bean  id ="stuJotmService"  class ="com.lavasoft.stu.jtom.service.StuJotmServiceImpl" > 
                 < property  name ="tabADAO"  ref ="tabADAO" /> 
                 < property  name ="tabBDAO"  ref ="tabBDAO" /> 
         </ bean > 
</ beans >
 
数据库配置:jdbc.properties
jdbc.database=cms_release 
jdbc.driver=com.mysql.jdbc.Driver 
jdbc.url=jdbc:mysql://192.168.0.2:3306/testdb_a?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull 
jdbc.username=root 
jdbc.password=leizhimin 

jdbc2.database=cms_release 
jdbc2.driver=com.mysql.jdbc.Driver 
jdbc2.url=jdbc:mysql://192.168.0.1:3306/testdb_b?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull 
jdbc2.username=root 
jdbc2.password=leizhimin 
 
iBatis的SQLMap配置:
sql-map-config_A.xml
<? xml  version ="1.0"  encoding ="UTF-8" ?> 
<!DOCTYPE sqlMapConfig 
                PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" 
                "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> 

< sqlMapConfig > 
         < settings  cacheModelsEnabled ="true"  enhancementEnabled ="true" 
                             lazyLoadingEnabled ="true"  errorTracingEnabled ="true" 
                             useStatementNamespaces ="true" /> 

         < sqlMap  resource ="com/lavasoft/stu/jtom/entity/sqlmap/TabA.xml" /> 

</ sqlMapConfig >
 
sql-map-config_B.xml
<? xml  version ="1.0"  encoding ="UTF-8" ?> 
<!DOCTYPE sqlMapConfig 
                PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" 
                "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> 

< sqlMapConfig > 
         < settings  cacheModelsEnabled ="true"  enhancementEnabled ="true" 
                             lazyLoadingEnabled ="true"  errorTracingEnabled ="true" 
                             useStatementNamespaces ="true" /> 

         < sqlMap  resource ="com/lavasoft/stu/jtom/entity/sqlmap/TabB.xml" /> 

</ sqlMapConfig >
 
日志的配置:log4j.properties
log4j.rootLogger=INFO,CONSOLE,LOGFILE 

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 
log4j.appender.Threshold=INFO 
log4j.appender.CONSOLE.Target=System.out 
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss } - %-5p %c        %x - %m%n 

log4j.appender.LOGFILE=org.apache.log4j.RollingFileAppender 
log4j.appender.LOGFILE.File=contestlog.log 
log4j.appender.LOGFILE.MaxFileSize=500KB 
log4j.appender.LOGFILE.MaxBackupIndex=10 
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout 
log4j.appender.LOGFILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss } -    %-p %c     %x - %m%n 

log4j.logger.com.ibatis=INFO 
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=INFO 
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=INFO 
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=INFO 
log4j.logger.java.sql.Connection=debug 
log4j.logger.java.sql.Statement=INFO,CONSOLE 
log4j.logger.java.sql.PreparedStatement=INFO,CONSOLE 
 
四、测试
 
public  class Test { 
         private  static ApplicationContext ctx = ApplicationContextUtil.getApplicationContext(); 
         private  static StuJotmService ser = (StuJotmService) ctx.getBean( "stuJotmService"); 

         public  static  void test_() { 
                TabA a =  new TabA(); 
                a.setId(1L); 
                a.setName( "aaa"); 
                a.setAddress( "address a"); 
                TabB b =  new TabB(); 
                b.setId(1L); 
                b.setName( "bbb"); 
                b.setAddress( "address b"); 
                ser.saveAB(a, b); 
        } 

         public  static  void main(String[] args) { 
                test_(); 
        } 
}
 
然后将主键其中一个改掉进行测试,让另外一个主键重复,发现a、b数据库均不能成功写入,经过多次测试,验证jtom真正实现了分布式事务的管理。
 
终于粘贴完了,周末愉快~!


本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/170085,如需转载请自行联系原作者
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
16天前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
40 2
Spring高手之路26——全方位掌握事务监听器
|
4月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
5月前
|
Java 关系型数据库 MySQL
Spring 事务失效场景总结
Spring 事务失效场景总结
68 4
|
18天前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
1月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
51 1
Spring高手之路24——事务类型及传播行为实战指南
|
22天前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
1月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
47 3
|
3月前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
|
3月前
|
Java 测试技术 数据库
Spring事务传播机制(最全示例)
在使用Spring框架进行开发时,`service`层的方法通常带有事务。本文详细探讨了Spring事务在多个方法间的传播机制,主要包括7种传播类型:`REQUIRED`、`SUPPORTS`、`MANDATORY`、`REQUIRES_NEW`、`NOT_SUPPORTED`、`NEVER` 和 `NESTED`。通过示例代码和数据库插入测试,逐一展示了每种类型的运作方式。例如,`REQUIRED`表示如果当前存在事务则加入该事务,否则创建新事务;`SUPPORTS`表示如果当前存在事务则加入,否则以非事务方式执行;`MANDATORY`表示必须在现有事务中运行,否则抛出异常;
178 4
Spring事务传播机制(最全示例)
|
2月前
|
Java 关系型数据库 MySQL
Spring事务失效,我总结了这7个主要原因
本文详细探讨了Spring事务在日常开发中常见的七个失效原因,包括数据库不支持事务、类不受Spring管理、事务方法非public、异常被捕获、`rollbackFor`属性配置错误、方法内部调用事务方法及事务传播属性使用不当。通过具体示例和源码分析,帮助开发者更好地理解和应用Spring事务机制,避免线上事故。适合所有使用Spring进行业务开发的工程师参考。
39 2