项目中分为了2个数据库 Activiti 数据库和 业务数据库 下面直接上代码
- pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<activiti-dependencies.version>7.1.0.M4</activiti-dependencies.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<skipTests>true</skipTests>
</properties>
<!-- 引入Activiti相关依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>${activiti-dependencies.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
- application.yml
spring:
datasource:
druid:
master:
# 业务数据库
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/manage_test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=CTT&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false
username: root
password: root@123
activiti:
# Activiti 数据库
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/activiti_test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=CTT&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&nullCatalogMeansCurrent=true
# url换为jdbc-url 解决jdbcUrl is required with driverClassName错误
jdbc-url: ${spring.datasource.druid.activiti.url}
username: root
password: root@123
# 连接池配置
# 初始化大小,最小,最大
initial-size: 10
min-idle: 10
max-active: 20
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
# max-evictable-idle-time-millis: 600000
max-open-prepared-statements: 60000
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
#最大等待超时时间
max-wait: 60000
test-on-borrow: false
test-on-return: false
test-while-idle: true
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
validation-query: SELECT 1 FROM DUAL
validation-query-timeout: 60000
query-timeout: 60000
transaction-threshold-millis: 60000
remove-abandoned-timeout-millis: 30000
# 配置监控统计拦截的filters,采用log4j2作为日志实现
filters: stat,wall,log4j2
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
use-global-data-source-stat: true
# 监控配置 WebStatFilter配置
web-stat-filter:
enabled: true
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
principal-cookie-name: admin
principal-session-name: admin
profile-enable: true
session-stat-enable: false
session-stat-max-count: 1000
url-pattern: '/*'
stat-view-servlet:
# IP 白名单
allow: 127.0.0.1
# IP黑名单(共同存在时,deny优先于allow)
deny: 192.168.0.10
enabled: true
# 控制台用户名和密码
login-password: admin
login-username: admin
reset-enable: false
url-pattern: '/druid/*'
# 配置日志输出
filter:
slf4j:
enabled: true
statement-create-after-log-enabled: false
statement-close-after-log-enabled: false
result-set-open-after-log-enabled: false
stat:
#慢查询
log-slow-sql: true
#慢查询时长,默认3秒
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
# jta atomikos 配置
jta:
atomikos:
datasource:
min-pool-size: 10
max-pool-size: 20
borrow-connection-timeout: 60
connectionfactory:
min-pool-size: 10
max-pool-size: 20
borrow-connection-timeout: 60
jpa:
open-in-view: true
database: MYSQL
generate-ddl: true
show-sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
hibernate:
ddl-auto: update
# update:表示自动根据model对象来更新表结构,启动 hibernate 时会自动检查数据库,如果缺少表则自动建表;缺少列则自动添加列;
# create: 启动hibernate时,自动删除原来的表,新建所有的表,所以每次启动后的以前数据都会丢失。
# create-drop:应用停下来的时候,自动会把表和数据删掉、
# none: 什么也不做;
# validate:会验证类里的属性和表字段是否一致,不一致,则会报错;
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy # 策略会有大小写区别 在进行领域映射时,首字母小写,大写字母变为下划线加小写 自动根据实体类重新生成表时(实体类即使配置了@Table 如果大小写不匹配也会生成表) 表名和字段都为小写
properties:
hibernate:
format_sql: true
activiti:
# 数据源指定
database-schema: ACTIVITI
# 建表规则: 服务启动时检查数据库表,不存在则创建
database-schema-update: true
# 表示哪种情况下使用历史表,这里配置为all表示全部记录历史,方便绘制流程图; 记录历史等级 可配置的历史级别有none, acitivity, audit, full
history-level: full
# 表示使用历史表,如果不配置,则工程启动后可以检查数据库
db-history-used: true
# spring jpa使用
jpa-enabled: true
# 暂时不检查
check-process-definitions: false
- 业务数据库 数据源配置
/***
* 文件名称: JpaRepositoriesConfig.java
* 文件描述: 默认数据源 主库持久化配置
* 公 司:
* 内容摘要:
* 其他说明: @EnableTransactionManagement 开启注解事物
* @EnableJpaRepositories 开启JPA存储库扫描
* @EntityScan 配置 实体类所在的路径 解决: Not a managed type:
* 完成日期:
* 修改记录:
* @version 1.0
* @author
*/
@Configuration
@DependsOn("transactionManager")
@EntityScan(basePackages = {"test.base.entity"})
@EnableJpaRepositories(basePackages = {"test.base.repository.jpa"},
entityManagerFactoryRef = "masterEntityManager", transactionManagerRef = "transactionManager")
public class JpaRepositoriesConfig {
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
@Bean("masterDruidDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
public DruidDataSource masterDruidDataSource() {
return new DruidDataSource();
}
/**
* 默认数据库
* @return
*/
@Primary
@Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
public DataSource masterDataSource() throws SQLException {
DruidDataSource dataSourceProperties = masterDruidDataSource();
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(dataSourceProperties.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setUser(dataSourceProperties.getUsername());
mysqlXaDataSource.setPassword(dataSourceProperties.getPassword());
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("masterDataSource");
xaDataSource.setBorrowConnectionTimeout(60);
xaDataSource.setMaxIdleTime(60);
xaDataSource.setMaxPoolSize(dataSourceProperties.getMaxActive());
xaDataSource.setMinPoolSize(dataSourceProperties.getMinIdle());
return xaDataSource;
}
/**
* 默认数据源事物配置
* @return
* @throws Throwable
*/
@Primary
@Bean(name = "masterEntityManager")
@DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean masterEntityManager() throws Throwable {
HashMap<String, Object> properties = new HashMap<String, Object>();
// 标注transaction是JTA和JTA平台是AtomikosJtaPlatform.class.getName()
properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
properties.put("javax.persistence.transactionType", "JTA");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(masterDataSource());
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("pers.liujunyi.cloud.photo.entity", "pers.liujunyi.cloud.security.entity");
entityManager.setPersistenceUnitName("masterPersistenceUnit");
// 设置jpa属性 使用 hibernateProperties.determineHibernateProperties(properties, new HibernateSettings()) 解决不按照配置的JPA 命令策略生成表的问题
entityManager.setJpaPropertyMap(hibernateProperties.determineHibernateProperties(properties, new
HibernateSettings()));
return entityManager;
}
}
- Activiti 数据库 数据源配置
/***
* 文件名称: ActivitiConfig.java
* 文件描述: Activiti 据源配置
* 公 司:
* 内容摘要:
* 其他说明:
* @EnableTransactionManagement 开启注解事物
* @EnableJpaRepositories 开启JPA存储库扫描
* 完成日期:
* 修改记录:
* @version 1.0
* @author
*/
@Configuration
@DependsOn("transactionManager")
@EntityScan(basePackages = {"test.activiti.entity"})
@EnableJpaRepositories(basePackages = {"test..activiti.repository"},
entityManagerFactoryRef = "activitiEntityManager", transactionManagerRef = "transactionManager")
public class ActivitiDataSourceConfig extends AbstractProcessEngineAutoConfiguration {
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Bean("activitiDruidDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.activiti")
public DruidDataSource activitiDruidDataSource() {
return new DruidDataSource();
}
/**
* Activiti 数据源
* @return
*/
@Bean(name = "activitiDataSource", initMethod = "init", destroyMethod = "close")
public DataSource activitiDataSource() throws SQLException {
DruidDataSource dataSourceProperties = activitiDruidDataSource();
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(dataSourceProperties.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setUser(dataSourceProperties.getUsername());
mysqlXaDataSource.setPassword(dataSourceProperties.getPassword());
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("activitiDataSource");
xaDataSource.setBorrowConnectionTimeout(60);
xaDataSource.setMaxIdleTime(60);
xaDataSource.setMaxPoolSize(dataSourceProperties.getMaxActive());
xaDataSource.setMinPoolSize(dataSourceProperties.getMinIdle());
return xaDataSource;
}
/**
*
* @return
* @throws Throwable
*/
@Bean(name = "activitiEntityManager")
@DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean masterEntityManager() throws IOException, SQLException {
HashMap<String, Object> properties = new HashMap<>();
// 标注transaction是JTA和JTA平台是AtomikosJtaPlatform.class.getName()
properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
properties.put("javax.persistence.transactionType", "JTA");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(activitiDataSource());
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("pers.liujunyi.cloud.activiti.entity");
entityManager.setPersistenceUnitName("activitiPersistenceUnit");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
/**
* 注入数据源和事务管理器
* 这段代码很重要,如果没有这段代码无法初始化 activitiDataSource
* @param transactionManager
* @param springAsyncExecutor
* @param activitiProperties
* @param processDefinitionResourceFinder
* @param processEngineConfigurationConfigurer
* @param processEngineConfigurators
* @param userGroupManager
* @return
* @throws IOException
*/
@Bean
public SpringProcessEngineConfiguration springProcessEngineConfiguration(
PlatformTransactionManager transactionManager,
SpringAsyncExecutor springAsyncExecutor,
ActivitiProperties activitiProperties,
ProcessDefinitionResourceFinder processDefinitionResourceFinder,
@Autowired(required = false) DefaultActivityBehaviorFactoryMappingConfigurer processEngineConfigurationConfigurer,
@Autowired(required = false) List<ProcessEngineConfigurator> processEngineConfigurators,
UserGroupManager userGroupManager) throws IOException, SQLException {
SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
processEngineConfiguration.setConfigurators(processEngineConfigurators);
configureProcessDefinitionResources(processDefinitionResourceFinder, processEngineConfiguration);
processEngineConfiguration.setDataSource(activitiDataSource());
processEngineConfiguration.setTransactionManager(transactionManager);
if (springAsyncExecutor != null) {
processEngineConfiguration.setAsyncExecutor(springAsyncExecutor);
}
processEngineConfiguration.setDeploymentName(activitiProperties.getDeploymentName());
processEngineConfiguration.setDatabaseSchema(activitiProperties.getDatabaseSchema());
processEngineConfiguration.setDatabaseSchemaUpdate(activitiProperties.getDatabaseSchemaUpdate());
processEngineConfiguration.setDbHistoryUsed(activitiProperties.isDbHistoryUsed());
processEngineConfiguration.setAsyncExecutorActivate(activitiProperties.isAsyncExecutorActivate());
if (!activitiProperties.isAsyncExecutorActivate()) {
ValidatorSet springBootStarterValidatorSet = new ValidatorSet("activiti-spring-boot-starter");
springBootStarterValidatorSet.addValidator(new AsyncPropertyValidator());
if (processEngineConfiguration.getProcessValidator() == null) {
ProcessValidatorImpl processValidator = new ProcessValidatorImpl();
processValidator.addValidatorSet(springBootStarterValidatorSet);
processEngineConfiguration.setProcessValidator(processValidator);
} else {
processEngineConfiguration.getProcessValidator().getValidatorSets().add(springBootStarterValidatorSet);
}
}
processEngineConfiguration.setMailServerHost(activitiProperties.getMailServerHost());
processEngineConfiguration.setMailServerPort(activitiProperties.getMailServerPort());
processEngineConfiguration.setMailServerUsername(activitiProperties.getMailServerUserName());
processEngineConfiguration.setMailServerPassword(activitiProperties.getMailServerPassword());
processEngineConfiguration.setMailServerDefaultFrom(activitiProperties.getMailServerDefaultFrom());
processEngineConfiguration.setMailServerUseSSL(activitiProperties.isMailServerUseSsl());
processEngineConfiguration.setMailServerUseTLS(activitiProperties.isMailServerUseTls());
if (userGroupManager != null) {
processEngineConfiguration.setUserGroupManager(userGroupManager);
}
processEngineConfiguration.setHistoryLevel(activitiProperties.getHistoryLevel());
processEngineConfiguration.setCopyVariablesToLocalForTasks(activitiProperties.isCopyVariablesToLocalForTasks());
processEngineConfiguration.setSerializePOJOsInVariablesToJson(activitiProperties.isSerializePOJOsInVariablesToJson());
processEngineConfiguration.setJavaClassFieldForJackson(activitiProperties.getJavaClassFieldForJackson());
if (activitiProperties.getCustomMybatisMappers() != null) {
processEngineConfiguration.setCustomMybatisMappers(
getCustomMybatisMapperClasses(activitiProperties.getCustomMybatisMappers()));
}
if (activitiProperties.getCustomMybatisXMLMappers() != null) {
processEngineConfiguration.setCustomMybatisXMLMappers(
new HashSet<>(activitiProperties.getCustomMybatisXMLMappers()));
}
if (activitiProperties.getCustomMybatisXMLMappers() != null) {
processEngineConfiguration.setCustomMybatisXMLMappers(
new HashSet<>(activitiProperties.getCustomMybatisXMLMappers()));
}
if (activitiProperties.isUseStrongUuids()) {
processEngineConfiguration.setIdGenerator(new StrongUuidGenerator());
}
if (activitiProperties.getDeploymentMode() != null) {
processEngineConfiguration.setDeploymentMode(activitiProperties.getDeploymentMode());
}
processEngineConfiguration.setActivityBehaviorFactory(new DefaultActivityBehaviorFactory());
if (processEngineConfigurationConfigurer != null) {
processEngineConfigurationConfigurer.configure(processEngineConfiguration);
}
return processEngineConfiguration;
}
private void configureProcessDefinitionResources(
ProcessDefinitionResourceFinder processDefinitionResourceFinder,
SpringProcessEngineConfiguration conf) throws IOException {
List<Resource> procDefResources = processDefinitionResourceFinder
.discoverProcessDefinitionResources();
if (!procDefResources.isEmpty()) {
conf.setDeploymentResources(procDefResources.toArray(new Resource[0]));
}
}
}
- atomikos的jta
public class AtomikosJtaPlatform extends AbstractJtaPlatform {
private static final long serialVersionUID = 8601225157421131143L;
static TransactionManager transactionManager;
static UserTransaction transaction;
@Override
protected TransactionManager locateTransactionManager() {
return transactionManager;
}
@Override
protected UserTransaction locateUserTransaction() {
return transaction;
}
}
- 数据源事物管理配置
@Configuration
@ComponentScan
@EnableTransactionManagement(proxyTargetClass = true)
public class DataSourceTransactionManagerConfig {
/**
* 事物超时时间 (秒)
*/
@Value("${spring.datasource.druid.transaction-threshold-millis}")
private Integer transactionTimeOut;
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
/**
* 设置JPA特性
* @return
*/
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
//显示sql
hibernateJpaVendorAdapter.setShowSql(true);
//自动生成/更新表
hibernateJpaVendorAdapter.setGenerateDdl(true);
//设置数据库类型
hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
return hibernateJpaVendorAdapter;
}
@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(60000);
return userTransactionImp;
}
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
userTransactionManager.setTransactionTimeout(60000);
AtomikosJtaPlatform.transactionManager = userTransactionManager;
return userTransactionManager;
}
@Bean(name = "transactionManager")
@DependsOn({"userTransaction", "atomikosTransactionManager"})
public PlatformTransactionManager transactionManager() throws Throwable {
UserTransaction userTransaction = userTransaction();
AtomikosJtaPlatform.transaction = userTransaction;
TransactionManager atomikosTransactionManager = atomikosTransactionManager();
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}
}
-
启动项目 Activiti 数据库 自动生成 25张表
如果启动项目没有自动生成数据库表 请检查数据库连接地址配置中是否有nullCatalogMeansCurrent=true 配置