1、jdbc操作分布式事务
分布式事务是指事务的参与者、支持事务的服务器、资源管理器以及事务管理器分别位于分布系统的不同节点之上,在两个或多个网络计算机资源上访问并且更新数据,将两个或多个网络计算机的数据进行的多次操作作为一个整体进行处理。如不同银行账户之间的转账。
对于在项目中接触到JTA,大部分的原因是因为在项目中需要操作多个数据库,同时,可以保证操作的原子性,保证对多个数据库的操作一致性。
在正式的项目中应该用springMVC(struts)+spring+hibernate(jpa)+jta,目前,先用spring+jta来完成基本的测试框架。下面我们看看代码
applicationContext-jta.xml
<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
4 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans
6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7 http://www.springframework.org/schema/context
8 http://www.springframework.org/schema/context/spring-context-2.5.xsd
9 http://www.springframework.org/schema/aop 10 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 11 http://www.springframework.org/schema/tx 12 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
13
14 <!-- jotm 本地实例 -->
15 <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
16
17
18 <!-- JTA事务管理器 -->
19 <bean id="txManager"
20 class="org.springframework.transaction.jta.JtaTransactionManager">
21 <property name="userTransaction" ref="jotm"></property>
22 </bean>
23
24 <!-- XAPool配置,内部包含了一个XA数据源,对应sshdb数据库 -->
25 <bean id="db1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
26 destroy-method="shutdown">
27 <property name="dataSource">
28 <!-- 内部XA数据源 -->
29 <bean class="org.enhydra.jdbc.standard.StandardXADataSource"
30 destroy-method="shutdown">
31 <property name="transactionManager" ref="jotm" />
32 <property name="driverName" value="com.mysql.jdbc.Driver" />
33 <property name="url"
34 value="jdbc:mysql://192.168.1.28:3306/sshdb?useUnicode=true&characterEncoding=UTF-8" />
35 </bean>
36 </property>
37 <property name="user" value="root" />
38 <property name="password" value="123456" />
39 </bean>
40
41 <!-- 另一个XAPool配置,内部包含另一个XA数据源,对应babasport数据库 -->
42 <bean id="db2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
43 destroy-method="shutdown">
44 <property name="dataSource">
45 <bean class="org.enhydra.jdbc.standard.StandardXADataSource"
46 destroy-method="shutdown">
47 <property name="transactionManager" ref="jotm" />
48 <property name="driverName" value="com.mysql.jdbc.Driver" />
49 <property name="url"
50 value="jdbc:mysql://192.168.1.28:3306/babasport?useUnicode=true&characterEncoding=UTF-8" />
51 </bean>
52 </property>
53 <property name="user" value="root" />
54 <property name="password" value="123456" />
55 </bean>
56
57 <!-- 配置访问sshdb数据源的Spring JDBC模板 -->
58 <bean id="sshdbTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
59 <property name="dataSource" ref="db1"></property>
60 </bean>
61
62 <!-- 配置访问babasport数据源的Spring JDBC模板 -->
63 <bean id="babasportTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
64 <property name="dataSource" ref="db2"></property>
65 </bean>
66 </beans></pre>
小注一下:spring-tx-3.2.4.jar里面竟然没有org.springframework.transaction.jta.JotmFactoryBean类,如果你可以选择spring-tx-2.5.6.jar,或者自己建立一下这个类。
接下来,看下dao层测试的代码
1 @Resource(name = "txManager")
2 private JtaTransactionManager txManager;
9
10 protected JdbcTemplate babasport_jdbcTemplate;
11
12 /**
13 * sshdb sql jdbcTemplate
14 */
15 protected JdbcTemplate ssh_jdbcTemplate;
16
17 /**
18 * babasport sql jdbcTemplate
19 *
20 * @return
21 */
22 public JdbcTemplate getBabasport_jdbcTemplate() {
23 return babasport_jdbcTemplate;
24 }
25
26 public JdbcTemplate getSsh_jdbcTemplate() {
27 return ssh_jdbcTemplate;
28 }
29
30 @Resource(name = "babasportTemplate")
31 public void setBabasport_jdbcTemplate(JdbcTemplate babasport_jdbcTemplate) {
32 this.babasport_jdbcTemplate = babasport_jdbcTemplate;
33 }
34
35 @Resource(name = "sshdbTemplate")
36 public void setSsh_jdbcTemplate(JdbcTemplate ssh_jdbcTemplate) {
37 this.ssh_jdbcTemplate = ssh_jdbcTemplate;
38 }
39
40 /**
41 * 同时修改两个数据库的表中内容
42 *
43 * @throws RollbackException
44 */
45 public void updateMultiple() {
46
47 if (null == this.txManager) {
48 System.out.println("txManager为空");
49 return;
50 }
51
52 UserTransaction userTx = this.txManager.getUserTransaction();
53 if (null == userTx) {
54 System.out.println("userTx为空");
55 return;
56 }
57
58 try {
59
60 userTx.begin();
61
62 this.ssh_jdbcTemplate
63 .execute("update wyuser set password='wangyong1' where id=8");
64
65
66 this.babasport_jdbcTemplate
67 .execute("update brand set name='wangyong28' where code='14ac8d5b-d19c-40e9-97ea-d82dfbcd84c6'");
68
69 userTx.commit();
70 } catch (Exception e) {
71 System.out.println("捕获到异常,进行回滚" + e.getMessage());
72 e.printStackTrace();
73 try {
74 userTx.rollback();
75 } catch (IllegalStateException e1) {
76 System.out.println("IllegalStateException:" + e1.getMessage());
77 } catch (SecurityException e1) {
78 System.out.println("SecurityException:" + e1.getMessage());
79 } catch (SystemException e1) {
80 System.out.println("SystemException:" + e1.getMessage());
81 }
82 // System.out.println("sql语句操作失败");
83 }
84 }
如果,将后一条update语句故意写错,就会发现会执行rollback,同时,对上面一个语句的操作也不会生效。基本的简单框架就是这样。
2、spring+mybatis
1、数据源
#car数据源
spring.datasource.car.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.car.driverClassName=com.mysql.jdbc.Driver
spring.datasource.car.url=jdbc:mysql://ip:3306/db_car?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.car.username=root
spring.datasource.car.password=123456
spring.datasource.car.initialSize=5
spring.datasource.car.minIdle=5
spring.datasource.car.maxActive=20
spring.datasource.car.maxWait=60000
# test 数据源
spring.datasource.test.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.test.driverClassName=com.mysql.jdbc.Driver
spring.datasource.test.url=jdbc:mysql://ip:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.test.username=root
spring.datasource.test.password=123456
spring.datasource.test.initialSize=5
spring.datasource.test.minIdle=5
spring.datasource.test.maxActive=20
spring.datasource.test.maxWait=60000
2、多数据源配置
这里只配置 car数据源的,test数据源的和这个一样,复制一份。
/**
* Created by Administrator on 2017/3/26/026.
* 数据源配置
*/
@Configuration
@MapperScan(basePackages = {"com.xxx.mapper.car*"}, sqlSessionTemplateRef = "sqlSessionTemplateCar") // 扫描dao或mapper接口
public class DataSourceCarConfig {
@Primary
@Bean(name = "dataSourceCar")
public DataSource dataSourceCar(DataSourceCarProperties dataSourceCarProperties){
DruidXADataSource dataSource = new DruidXADataSource();
BeanUtils.copyProperties(dataSourceCarProperties,dataSource);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(dataSource);
xaDataSource.setUniqueResourceName("dataSourceCar");
return xaDataSource;
}
@Bean(name = "sqlSessionFactoryCar")
public SqlSessionFactory sqlSessionFactoryCar(@Qualifier("dataSourceCar") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setTypeAliasesPackage("com.lcj.web.entity.car");
//bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/car/*Mapper.xml"));
return bean.getObject();
}
@Bean(name = "sqlSessionTemplateCar")
public SqlSessionTemplate sqlSessionTemplateCar(
@Qualifier("sqlSessionFactoryCar") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@Component //自动注入
@ConfigurationProperties(prefix = "spring.datasource.car")
@Data
public class DataSourceCarProperties {
private String type;
private String driverClassName;
private String url;
private String username;
private String password;
private int initialSize;
private int minIdle;
private int maxActive;
private int maxWait;
private int timeBetweenEvictionRunsMillis;
private int minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxPoolPreparedStatementPerConnectionSize;
private String filters;
private String connectionProperties;
}
3、分布式事务管理器配置
@Configuration
@EnableTransactionManagement
public class XATransactionManagerConfig {
@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(10000);
return userTransactionImp;
}
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
return userTransactionManager;
}
@Bean(name = "transactionManager")
@DependsOn({ "userTransaction", "atomikosTransactionManager" })
public PlatformTransactionManager transactionManager() throws Throwable {
return new JtaTransactionManager(userTransaction(),atomikosTransactionManager());
}
4、接口调用
controller 方法
@GetMapping
public void index(){
// 构造数据
MessagePackageNo messagePackageNo = new MessagePackageNo();
messagePackageNo.setNo(99);
messagePackageNo.setCreateTime(new Date());
User user = new User();
user.setAge(25);
user.setName("lcj");
user.setCreateTime(new Date());
indexService.save(messagePackageNo,user);
}
indexService.save 方法,包含两个不同数据库的调用
@Service
public class IndexService {
@Autowired
private MessagePackageNoService messagePackageNoService;
@Autowired
private UserService userService;
/**
* 保存数据
*
* @param messagePackageNo
* @param user
*/
@Transactional
public void save(MessagePackageNo messagePackageNo, User user) {
messagePackageNoService.insert(messagePackageNo);
userService.insert(user);
//int i = 4 / 0; // 除0异常,测试事务
}
}
基本的demo框架就是这样了,后续上传源码。
网友评论