spring JTA多数据源事务管理详细教程
用框架的话只要配置好对个数据源,和工厂,公用一个JtaTransactionManager事物管理器,一个事物中有多个不同数据库操作不同数据源的时候会自动启用两阶段提交
,在加入事物标签的地方遇到任何异常就会自动回滚。
DataSourceTransactionManager是mybaits的事物管理器
HibernateTransactionManager是hibernate的事物管理器
JtaTransactionManager是分布式的事物管理器
这里的示例忘了在service加事物注解
刚好项目要用到多数据源,在网上查找了很多资料,花了几天的时间对spring、jta 、atomikos、hibernate进行多数据源事务管理的配置。
没有花时间弄maven,lib的地址:https://pan.baidu.com/s/1skdIC3N
也可以直接放在tomcat中运行,不过要用ws调用,因为没有做界面,ws入口在controller包里
下面是jta配置文件:
001 |
< context:annotation-config /> |
002 |
<!-- 使用注解的包路径 --> |
003 |
< context:component-scan base-package = "com.rongli.service,com.rongli.dao,com.rongli.controller" /> |
004 |
<!-- 支持 @Transactional 标记 --> |
005 |
< tx:annotation-driven transaction-manager = "springJTATransactionManager" proxy-target-class = "true" /> |
006 |
<!-- 导入cxf配置文件 --> |
007 |
< import resource = "ws.cxf.xml" /> |
008 |
|
009 |
<!-- 加载properties配置文件 --> |
010 |
< bean id = "propertyConfigurer" |
011 |
class = "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" > |
012 |
< property name = "locations" > |
013 |
< list > |
014 |
< value >classpath:jta.jdbc.properties</ value > |
015 |
</ list > |
016 |
</ property > |
017 |
</ bean > |
018 |
|
019 |
<!--公有数据库连接池 --> |
020 |
< bean id = "abstractXADataSource" class = "com.atomikos.jdbc.AtomikosDataSourceBean" |
021 |
init-method = "init" destroy-method = "close" abstract = "true" > |
022 |
< property name = "xaDataSourceClassName" |
023 |
value = "com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" /> |
024 |
< property name = "poolSize" value = "10" /> |
025 |
< property name = "minPoolSize" value = "10" /> |
026 |
< property name = "maxPoolSize" value = "30" /> |
027 |
<!--获取连接失败重新获等待最大时间,在这个时间内如果有可用连接,将返回--> |
028 |
< property name = "borrowConnectionTimeout" value = "60" /> |
029 |
<!--最大获取数据时间,如果不设置这个值,Atomikos使用默认的5分钟, |
030 |
那么在处理大批量数据读取的时候,一旦超过5分钟,就会抛出类似 Resultset is close 的错误.--> |
031 |
< property name = "reapTimeout" value = "20000" /> |
032 |
<!-- 最大空闲时间 --> |
033 |
< property name = "maxIdleTime" value = "60" /> |
034 |
<!--连接回收时间--> |
035 |
< property name = "maintenanceInterval" value = "60" /> |
036 |
<!--java数据库连接池,最大可等待获取datasouce的时间--> |
037 |
< property name = "loginTimeout" value = "60" /> |
038 |
< property name = "testQuery" > |
039 |
< value >select 1</ value > |
040 |
</ property > |
041 |
</ bean > |
042 |
|
043 |
<!-- 客户数据库 --> |
044 |
< bean id = "rlc_cus" parent = "abstractXADataSource" > |
045 |
< property name = "uniqueResourceName" value = "mysql/rlc_cus" /> |
046 |
< property name = "xaProperties" > |
047 |
< props > |
048 |
< prop key = "URL" >${jdbc.rlc_cus.properties}</ prop > |
049 |
< prop key = "user" >${jdbc.rlc.user}</ prop > |
050 |
< prop key = "password" >${jdbc.rlc.password}</ prop > |
051 |
< prop key = "pinGlobalTxToPhysicalConnection" >true</ prop > |
052 |
</ props > |
053 |
</ property > |
054 |
</ bean > |
055 |
|
056 |
<!-- 系统数据库 --> |
057 |
< bean id = "rlc_sys" parent = "abstractXADataSource" > |
058 |
< property name = "uniqueResourceName" value = "mysql/rlc_sys" /> |
059 |
< property name = "xaProperties" > |
060 |
< props > |
061 |
< prop key = "URL" >${jdbc.rlc_sys.properties}</ prop > |
062 |
< prop key = "user" >${jdbc.rlc.user}</ prop > |
063 |
< prop key = "password" >${jdbc.rlc.password}</ prop > |
064 |
< prop key = "pinGlobalTxToPhysicalConnection" >true</ prop > |
065 |
</ props > |
066 |
</ property > |
067 |
</ bean > |
068 |
|
069 |
<!-- 公有SessionFactory配置 --> |
070 |
< bean id = "baseSessionFactory" |
071 |
class = "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" |
072 |
abstract = "true" > |
073 |
< property name = "hibernateProperties" > |
074 |
< props > |
075 |
< prop key = "hibernate.dialect" >${hibernate.dialect}</ prop > |
076 |
< prop key = "hibernate.show_sql" >${hibernate.format_sql}</ prop > |
077 |
< prop key = "hibernate.format_sql" >${hibernate.show_sql}</ prop > |
078 |
< prop key = "javax.persistence.validation.mode" >none</ prop > |
079 |
</ props > |
080 |
</ property > |
081 |
<!-- 自动扫描注解方式配置的hibernate类文件 --> |
082 |
< property name = "packagesToScan" value = "com.rongli.bean" ></ property > |
083 |
</ bean > |
084 |
|
085 |
<!-- sessionFactory配置--> |
086 |
<!-- customer sessionFactory --> |
087 |
< bean id = "cusSessionFactory" parent = "baseSessionFactory" > |
088 |
< property name = "dataSource" ref = "rlc_cus" /> |
089 |
</ bean > |
090 |
<!-- system sessionFactory --> |
091 |
< bean id = "sysSessionFactory" parent = "baseSessionFactory" > |
092 |
< property name = "dataSource" ref = "rlc_sys" /> |
093 |
</ bean > |
094 |
095 |
<!-- atomikos事务管理器 --> |
096 |
< bean id = "atomikosTransactionManager" |
097 |
class = "com.atomikos.icatch.jta.UserTransactionManager" |
098 |
init-method = "init" destroy-method = "close" > |
099 |
<!-- 调用终止时,强制关闭 --> |
100 |
< property name = "forceShutdown" > |
101 |
< value >true</ value > |
102 |
</ property > |
103 |
</ bean > |
104 |
< bean id = "atomikosUserTransaction" |
105 |
class = "com.atomikos.icatch.jta.UserTransactionImp" > |
106 |
< property name = "transactionTimeout" > |
107 |
< value >2000</ value > |
108 |
</ property > |
109 |
</ bean > |
110 |
111 |
<!-- spring 事务管理器 --> |
112 |
< bean id = "springJTATransactionManager" |
113 |
class = "org.springframework.transaction.jta.JtaTransactionManager" > |
114 |
< property name = "transactionManager" > |
115 |
< ref bean = "atomikosTransactionManager" /> |
116 |
</ property > |
117 |
< property name = "userTransaction" > |
118 |
< ref bean = "atomikosUserTransaction" /> |
119 |
</ property > |
120 |
</ bean > |
121 |
|
122 |
<!-- 用于测试,发布到服务器上时删除 --> |
123 |
< bean id = "systemServiceImpl" |
124 |
class = "com.rongli.service.impl.SystemServiceImpl" > |
125 |
</ bean > |
运行截图:
原2个数据库中都没有数据,图如下:
具体代码:
代码运行成功截图:
代码故意抛出异常:
代码运行失败:
失败后2个数据库中没有插入(事务回滚了):
参考:
http://blog.csdn.net/super_scan/article/details/39400719