Skip to content

Instantly share code, notes, and snippets.

@pocari
Last active August 29, 2015 14:20
Show Gist options
  • Save pocari/d66ac75d7df0a0495c78 to your computer and use it in GitHub Desktop.
Save pocari/d66ac75d7df0a0495c78 to your computer and use it in GitHub Desktop.
Spring+Wildflyで2phase commit ref: http://qiita.com/pocari/items/f083d7a6ecd86df0738d
package com.example.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
@Configuration
public class DatasourceConfig {
@Bean(name="ds1")
public DataSource ds1() {
DataSource dataSource = createJndiDataSourceBy("java:/jdbc/XAds1");
return dataSource;
}
@Bean(name="ds2")
public DataSource ds2() {
DataSource dataSource = createJndiDataSourceBy("java:/jdbc/XAds2");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(@Qualifier("ds1") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public JdbcTemplate jdbcTemplate2(@Qualifier("ds2") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
private DataSource createJndiDataSourceBy(String jndiName) {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(jndiName);
return dataSource;
}
}
${JBOSS_HOME}/modules
+- oracle
| +- jdbc
| +- main
| +- module.xml
| +- ojdbc6_g.jar
|
+- org
+- postgresql
+- main
  +- module.xml
+- postgresql-9.2-1003-jdbc4.jar
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="oracle.jdbc">
<resources>
<resource-root path="ojdbc6_g.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
SQL> desc ora_table
名前 NULL? 型
----------------------------------------- -------- ----------------------------
F NUMBER
SQL> select * from ora_table;
F
----------
-1
-2
-3
pgtest=> \d pg_table
テーブル "public.pg_table"
列 | 型 | 修飾語
----+---------+--------
f | numeric |
pgtest=> select * from pg_table;
f
---
1
2
3
(3 行)
SQL> select * from ora_table;
F
----------
-1
-2
-3
100
pgtest=> select * from pg_table;
f
---
1
2
3
(3 行)
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.postgresql">
<resources>
<resource-root path="postgresql-9.2-1003-jdbc4.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
SQL> select * from ora_table;
F
----------
-1
-2
-3
100
pgtest=> select * from pg_table;
f
---
1
2
3
(3 行)
SQL> select * from ora_table;
F
----------
-1
-2
-3
5
100
100
pgtest=> select * from pg_table;
f
----
1
2
3
20
(4 行)
>jboss-cli.bat
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /] connect
[standalone@localhost:9990 /]
[standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=oracle:add(driver-name=oracle,driver-module-name=oracle.jdbc,driver-xa-datasource-class-name=oracle.jdbc.xa.client.OracleXADataSource)
{"outcome" => "success"}
[standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=postgresql:add(driver-name=postgresql,driver-module-name=org.postgresql,driver-xa-datasource-class-name=org.postgresql.xa.PGXADataSource)
{"outcome" => "success"}
<subsystem xmlns="urn:jboss:domain:datasources:3.0">
<datasources>
<!-- ここ -->
</datasources>
</subsystem>
[standalone@localhost:9990 /] /subsystem=datasources/xa-data-source=XAds1:test-connection-in-pool
{
"outcome" => "success",
"result" => [true]
}
[standalone@localhost:9990 /] /subsystem=datasources/xa-data-source=XAds2:test-connection-in-pool
{
"outcome" => "success",
"result" => [true]
}
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.service.IndexService;
@Controller
@Transactional(rollbackFor=Exception.class) //Exceptionが発生したらロールバック
public class IndexController {
@Autowired
private IndexService indexService;
@RequestMapping("/")
@ResponseBody
public String index() throws Exception {
return indexService.doService();
}
}
package com.example.service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
@Service
public class IndexService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private JdbcTemplate jdbcTemplate2;
@Autowired
private NewTransactionService newTransactionService;
public String doService() throws Exception {
List<Map<String, Object>> result = jdbcTemplate.queryForList("select * from ora_table");
String val = result.stream().map(m -> m.get("f").toString()).collect(Collectors.joining(","));
jdbcTemplate.update("insert into ora_table (f) values (?)", 5);
jdbcTemplate2.update("insert into pg_table (f) values (?)", 20);
newTransactionService.doService();
int a = 1;
if (a == 1) {
//throw new Exception("exception occured"); //例外を発生しないように変更
}
List<Map<String, Object>> result2 = jdbcTemplate2.queryForList("select * from pg_table");
String val2 = result2.stream().map(m -> m.get("f").toString()).collect(Collectors.joining(","));
return String.format("Hello, World!! [%s], [%s]", val, val2);
// return String.format("Hello, World!! [%s]", val2);
}
}
package com.example.service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
@Service
public class IndexService {
@Autowired
private JdbcTemplate jdbcTemplate; //Oracleへのアクセス用
@Autowired
private JdbcTemplate jdbcTemplate2; //Postgresqlへのアクセス用
@Autowired
private NewTransactionService newTransactionService; //別トランザクションでOracleにinsertするサービス
public String doService() throws Exception {
List<Map<String, Object>> result = jdbcTemplate.queryForList("select * from ora_table");
String val = result.stream().map(m -> m.get("f").toString()).collect(Collectors.joining(","));
jdbcTemplate.update("insert into ora_table (f) values (?)", 5);
jdbcTemplate2.update("insert into pg_table (f) values (?)", 20);
newTransactionService.doService(); //下で例外が発生するがこのサービスの処理は別トランザクションなのでコミットされる。
int a = 1;
if (a == 1) {
throw new Exception("exception occured"); //ここでわざとExceptionを発生させて、5,20のinsertをロールバックする。
}
List<Map<String, Object>> result2 = jdbcTemplate2.queryForList("select * from pg_table");
String val2 = result2.stream().map(m -> m.get("f").toString()).collect(Collectors.joining(","));
return String.format("Hello, World!! [%s], [%s]", val, val2);
// return String.format("Hello, World!! [%s]", val2);
}
}
package com.example;
import javax.servlet.Filter;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ WebAppConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
return new Filter[] {createUTF8CharEncodingFilter()};
}
private static Filter createUTF8CharEncodingFilter() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
return filter;
}
}
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class NewTransactionService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(propagation=Propagation.REQUIRES_NEW) //このメッソドは特別に別トランザクションで実行するためREQUIRES_NEWで実行する
public void doService() {
jdbcTemplate.update("insert into ora_table (f) values (?)", 100);
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>MultipleDatasourceTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>utf-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
<xa-datasource jndi-name="java:/jdbc/XAds1" pool-name="XAds1">
<xa-datasource-property name="URL">
jdbc:oracle:thin:@localhost:1521:XE
</xa-datasource-property>
<xa-datasource-property name="User">
oratest
</xa-datasource-property>
<xa-datasource-property name="Password">
oratest
</xa-datasource-property>
<driver>oracle</driver>
<xa-pool>
<min-pool-size>10</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>true</prefill>
</xa-pool>
</xa-datasource>
<xa-datasource jndi-name="java:/jdbc/XAds2" pool-name="XAds2">
<xa-datasource-property name="DatabaseName">
pgtest
</xa-datasource-property>
<xa-datasource-property name="PortNumber">
5432
</xa-datasource-property>
<xa-datasource-property name="ServerName">
localhost
</xa-datasource-property>
<driver>postgresql</driver>
<xa-pool>
<min-pool-size>10</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>true</prefill>
</xa-pool>
<security>
<user-name>pgtest</user-name>
<password>pgtest</password>
</security>
</xa-datasource>
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
@Configuration
public class TransactionManagerConfig {
@Bean
public PlatformTransactionManager transactionManager() {
return new JtaTransactionManager();
}
}
package com.example;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.example")
public class WebAppConfig {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment