SalesforceのバッチモードではCSVファイル以外にデータベースと連動する機能がある。
データベース接続およびSQL定義はdatabase-conf.xmlで定義する。
本記事ではHSQLDBを利用してSalesforceと連動を実施する。
前提条件
- Java 11以上
- DataLoder Version 58.0.4
- HSQLDB 2.1.210
セキュリティトークンの取得
データローダバッチの構成
C:\DataLoaderProcess
├─config.properties ⇒ データローダ環境設定ファイル
├─my.properties ⇒ 独自の環境設定ファイル
│─extractAccountDbToSf.bat ⇒ データベースからデータを取得してSalesforceへUpsertする
│─extractAccountSfToDb.bat ⇒ Salesforceからデータを取得してデータベースへInsertする
│─extractAccountDbToSfMap.sdl ⇒ DataLoaderマッピングファイル(Database⇒Salesforce)
│─extractAccountSfToDbMap.sd ⇒ DataLoaderマッピングファイル(Salesforce⇒Database)
│─dataloader.key ⇒ 暗号鍵
│─dataloader-58.0.4.jar ⇒ データローダJAR
│─spring-context-5.3.27.jar ⇒ spring-context
│─spring-core-5.3.27.jar ⇒ spring-core
│─h2-2.1.210.jar ⇒ HSQLDBライブラリ
│─h2v2.mv.db ⇒ HSQLDBデータベースファイル
│─h2v2.trace.db ⇒ HSQLDBデータベースファイル
├─process.bat ⇒ バッチ起動ファイル(ProcessId指定)
├─process-conf.xml ⇒ データローダの実行設定ファイル
└─log4j2.properties ⇒ ログ出力用の設定ファイル
必要なJarファイルの取得する
DataLoader jarファイルの取得
本記事にはJava 11をサポートする最後のバージョンであるV58.0.4を利用する
取得先:https://github.com/forcedotcom/dataloader/releases/tag/v58.0.4
欲しいのは[dataloader-58.0.4.jar]ファイルのみなので任意のフォルダにコピーしておく
この記事では[C:\DataLoaderProcess]にコピーした。
Spring-Core,Spring-Context jarファイルの取得
mavenサイトからダウンロードする。
spring-core-5.3.27.jar
spring-context-5.3.27.jar
H2 Database Engine jarファイルの取得
※あなたが経験あるJavaプログラマーであれば、何で細かいマイナバージョンまで指定しているか理解してくれるはずです。
暗号化されたパスワードの生成
データベースを用意する
C:\DataLoaderProcess\h2v2.mv.dbファイルを作成し、以下のテーブルを作成する
CREATE TABLE PUBLIC.ACCOUNT_TABLE (
ID CHARACTER(18),
NAME CHARACTER(255),
NUMBER_OF_EMPLOYEES INTEGER,
INDUSTRY CHARACTER(40),
ANNUAL_REVENUE DOUBLE PRECISION,
CREATED_DATE CHARACTER(25)
);
設定ファイルを作成する
config.properties
# Data LodaerLoader Config
# https://help.salesforce.com/apex/HTViewHelpDoc?id=loader_params.htm
# 接続先情報
# sandboxの場合:https://test.salesforce.com
sfdc.endpoint=https://login.salesforce.com
sfdc.username=<ログインユーザ名>
sfdc.password=<コマンドで生成した暗号化パスワード>
process.encryptionKeyFile=./dataLoader.key
my.properties
# 独自の環境設定
outputdirectory=C:/DataLoaderProcess
log4j2.properties
name = Salesforce Data Loader
monitorInterval = 5
property.basePath = ${sys:java.io.tmpdir}
# RollingFileAppender name, pattern, path and rollover policy
appender.rolling.type = RollingFile
appender.rolling.name = fileAppender
appender.rolling.fileName= ./log/sdl.log
appender.rolling.filePattern= ./log/sdl-%d{yyyy-MM-dd}.log
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d %-5p [%t] %C{2} %M (%F:%L) - %m%n
appender.rolling.policies.type = Policies
# CONSOLE Appender
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d %-5p [%t] %C{2} %M (%F:%L) - %m%n
# RollingFileAppender rotation policy
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size = 100KB
# Configure root logger
rootLogger.level = info
rootLogger.appenderRef.rolling.ref = fileAppender
rootLogger.appenderRef.stdout.ref = STDOUT
database-conf.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tool
http://www.springframework.org/schema/tool/spring-tool.xsd">
<!-- 独自の環境設定をロード -->
<context:property-placeholder location="classpath:my.properties"/>
<!-- データソースの設定(必ずdbcp2を使用する必要がある) -->
<bean id="dbDataSource"
class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close"
scope="prototype">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:./h2v2"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
<!-- データベースから取得するBean定義 -->
<bean id="queryAccountTable"
class="com.salesforce.dataloader.dao.database.DatabaseConfig"
scope="singleton">
<property name="sqlConfig" ref="queryAccountTableSql"/>
<property name="dataSource" ref="dbDataSource"/>
</bean>
<!-- データベースへ登録するBean定義 -->
<bean id="insertAccountTable"
class="com.salesforce.dataloader.dao.database.DatabaseConfig"
scope="singleton">
<property name="sqlConfig" ref="insertAccountTableSql"/>
<property name="dataSource" ref="dbDataSource"/>
</bean>
<!-- SELECT SQL -->
<bean id="queryAccountTableSql"
class="com.salesforce.dataloader.dao.database.SqlConfig"
scope="singleton">
<property name="sqlString">
<value>
SELECT ID, NAME, NUMBER_OF_EMPLOYEES, INDUSTRY, ANNUAL_REVENUE
FROM ACCOUNT_TABLE
WHERE created_date > @process.lastRunDate@
</value>
</property>
<property name="columnNames">
<list>
<value>id</value>
<value>name</value>
<value>number_of_employees</value>
<value>industry</value>
<value>annual_revenue</value>
</list>
</property>
<property name="sqlParams">
<map>
<entry key="process.lastRunDate" value="java.sql.Timestamp"/>
</map>
</property>
</bean>
<!-- INSERT SQL -->
<bean id="insertAccountTableSql"
class="com.salesforce.dataloader.dao.database.SqlConfig"
scope="singleton">
<property name="sqlString">
<value>
INSERT INTO ACCOUNT_TABLE (
ID, NAME, NUMBER_OF_EMPLOYEES, INDUSTRY, ANNUAL_REVENUE, CREATED_DATE)
VALUES (@id@, @name@, @number_of_employees@, @industry@, @annual_revenue@, @created_date@)
</value>
</property>
<property name="sqlParams">
<map>
<entry key="id" value="java.lang.String" />
<entry key="name" value="java.lang.String" />
<entry key="number_of_employees" value="java.lang.Long" />
<entry key="industry" value="java.lang.Double" />
<entry key="annual_revenue" value="java.lang.String" />
<entry key="created_date" value="java.lang.String" />
</map>
</property>
</bean>
</beans>
process-conf.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tool
http://www.springframework.org/schema/tool/spring-tool.xsd">
<!-- 独自の環境設定をロード -->
<context:property-placeholder location="classpath:my.properties"/>
<!-- Salesforce⇒Database出力ジョブを定義 -->
<bean id="extractAccountSfToDb"
class="com.salesforce.dataloader.process.ProcessRunner"
scope="prototype">
<description>extractAccountSfToDbジョブは、Salesforceから取引先情報を取得し、データベースへ保存します。</description>
<property name="name" value="extractAccountSfToDb"/>
<property name="configOverrideMap">
<map>
<entry key="sfdc.extractionSOQL" value="Select Id, Name, NumberOfEmployees, Industry, AnnualRevenue, CreatedDate FROM Account LIMIT 10" />
<entry key="process.outputSuccess" value="${outputdirectory}/extractAccountDbSuccess.csv"/>
<entry key="process.outputError" value="${outputdirectory}/extractAccountDbError.csv"/>
<entry key="sfdc.debugMessagesFile" value="${outputdirectory}/extractAccountSfToDbSoapTrace.log"/>
<entry key="sfdc.extractionRequestSize" value="1000"/>
<entry key="sfdc.entity" value="Account"/>
<entry key="process.operation" value="extract"/>
<entry key="process.mappingFile" value="${outputdirectory}/extractAccountSfToDbMap.sdl"/>
<entry key="dataAccess.type" value="databaseWrite"/>
<entry key="dataAccess.name" value="insertAccountTable"/>
<entry key="dataAccess.writeBatchSize" value="750"/>
</map>
</property>
</bean>
<!-- Database⇒Salesforce入力ジョブを定義 -->
<bean id="extractAccountDbToSf"
class="com.salesforce.dataloader.process.ProcessRunner"
scope="prototype">
<description>extractAccountDbToSfジョブは、データベースから取引先情報を取得し、SalesforceへUpsertします。</description>
<property name="name" value="extractAccountDbToSf"/>
<property name="configOverrideMap">
<map>
<entry key="sfdc.debugMessages" value="false"/>
<entry key="sfdc.debugMessagesFile" value="${outputdirectory}/extractAccountSfToDbSoapTrace.log"/>
<entry key="sfdc.externalIdField" value="Id"/>
<entry key="sfdc.entity" value="Account"/>
<entry key="process.operation" value="upsert"/>
<entry key="process.mappingFile" value="${outputdirectory}/extractAccountDbToSfMap.sdl"/>
<entry key="dataAccess.name" value="queryAccountTable"/>
<entry key="dataAccess.type" value="databaseRead"/>
<entry key="process.initialLastRunDate" value="2005-12-01T00:00:00.000-0800"/>
</map>
</property>
</bean>
</beans>
process.bat
@echo off
SET MIN_JAVA_VERSION=11
echo Data Loader requires Java JRE %MIN_JAVA_VERSION% or later. Checking if it is installed...
java -version 1>nul 2>nul || (
echo Did not find java command.
EXIT -1
)
java -cp ".\dataloader-58.0.4.jar;.\spring-core-5.3.27.jar;.\spring-context-5.3.27.jar;.\h2-2.1.210.jar;." com.salesforce.dataloader.process.DataLoaderRunner .\ %1 run.mode=batch
EXIT /b %ERRORLEVEL%
extractAccountDbToSf.bat
CALL process.bat extractAccountDbToSf
extractAccountSfToDb.bat
CALL process.bat extractAccountSfToDb
バッチファイルの実行
データベースにはデータが何もないのでまず、Salesforceからデータを取得してデータベースへ登録してみる。
extractAccountSfToDb.batファイルを実行して起動
次はデータベースへ登録された取引先情報をSalesforceへUpsertする。
データは同じなので最終更新日が更新されたことは確認できる