优化数据库维护

This commit is contained in:
zhou-hao
2017-12-19 22:24:04 +08:00
parent b81564920e
commit 903ecf7b36
13 changed files with 374 additions and 113 deletions

View File

@@ -12,5 +12,5 @@ import java.util.Map;
* @author zhouhao
*/
public interface DatabaseManagerService extends SqlExecutor,TransactionSqlExecutor {
Map<ObjectMetadata.ObjectType, List<? extends ObjectMetadata>> getMetas(String datasourceId);
Map<ObjectMetadata.ObjectType, List<? extends ObjectMetadata>> getMetas();
}

View File

@@ -0,0 +1,21 @@
package org.hswebframework.web.database.manager.sql;
import lombok.Data;
import org.hswebframework.web.database.manager.SqlInfo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Data
public class TransactionInfo implements Serializable {
private String id;
private List<SqlInfo> sqlHistory=new ArrayList<>();
private Date createTime;
private Date lastExecuteTime;
}

View File

@@ -3,6 +3,7 @@ package org.hswebframework.web.database.manager.sql;
import org.hswebframework.web.database.manager.SqlExecuteRequest;
import org.hswebframework.web.database.manager.SqlExecuteResult;
import org.hswebframework.web.datasource.DynamicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
@@ -36,6 +37,19 @@ public interface TransactionSqlExecutor {
*/
void rollback(String transactionId);
/**
* @return 获取全部事务
*/
List<TransactionInfo> allTransaction();
/**
* 执行
*
* @param transactionId
* @param request
* @return
* @throws Exception
*/
List<SqlExecuteResult> execute(String transactionId, SqlExecuteRequest request) throws Exception;
}

View File

@@ -1,93 +0,0 @@
package org.hswebframework.web.datasource.manager.simple;
import org.hswebframework.ezorm.rdb.executor.SqlExecutor;
import org.hswebframework.ezorm.rdb.meta.parser.OracleTableMetaParser;
import org.hswebframework.web.database.manager.DatabaseManagerService;
import org.hswebframework.web.database.manager.meta.ObjectMetadata;
import org.hswebframework.web.database.manager.meta.table.parser.MetaDataParserRegister;
import org.hswebframework.web.database.manager.meta.table.parser.MetaDataParserSupplier;
import org.hswebframework.web.database.manager.meta.table.parser.TableMetaDataParser;
import org.hswebframework.web.database.manager.meta.table.parser.support.H2TableMetaDataParser;
import org.hswebframework.web.database.manager.meta.table.parser.support.MysqlTableMetaDataParser;
import org.hswebframework.web.database.manager.meta.table.parser.support.SqlServerTableMetaDataParser;
import org.hswebframework.web.datasource.DatabaseType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnMissingBean(DatabaseManagerService.class)
public class DatabaseManagerAutoConfiguration {
@Bean
public DatabaseManagerService databaseManagerService() {
return new SimpleDatabaseManagerService();
}
@Configuration
public static class TableMetaDataParserAutoConfiguration {
@Autowired
private SqlExecutor sqlExecutor;
@Autowired
private MetaDataParserRegister metaDataParserRegister;
@Bean
@ConditionalOnClass(name = "org.h2.Driver")
public H2TableMetaDataParser h2TableMetaDataParser() {
return new H2TableMetaDataParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name = "com.mysql.jdbc.Driver")
public MysqlTableMetaDataParser mysqlTableMetaDataParser() {
return new MysqlTableMetaDataParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name = "oracle.jdbc.driver.OracleDriver")
public OracleTableMetaParser oracleTableMetaParser() {
return new OracleTableMetaParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name ="com.microsoft.sqlserver.jdbc.SQLServerDriver")
public SqlServerTableMetaDataParser sqlServerTableMetaDataParser(){
return new SqlServerTableMetaDataParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name ="net.sourceforge.jtds.jdbc.Driver")
public SqlServerTableMetaDataParser jstdSqlServerTableMetaDataParser(){
return new SqlServerTableMetaDataParser(sqlExecutor);
}
@Bean
public BeanPostProcessor tableMetaDataAutoParserRegister() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return o;
}
@Override
@SuppressWarnings("unchecked")
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
if (o instanceof MetaDataParserSupplier) {
MetaDataParserSupplier<? extends TableMetaDataParser> supplier = ((MetaDataParserSupplier) o);
for (DatabaseType databaseType : DatabaseType.values()) {
if (supplier.isSupport(databaseType)) {
metaDataParserRegister.registerMetaDataParser(databaseType, ObjectMetadata.ObjectType.TABLE, supplier.get());
}
}
}
return o;
}
};
}
}
}

View File

@@ -152,6 +152,7 @@ public class DefaultLocalTransactionExecutor implements TransactionExecutor {
protected void doExecute() {
Execution execution;
while ((execution = executionQueue.poll()) != null) {
Execution finalE = execution;
running = true;
logger.debug("start execute sql {}", transactionId);
try {
@@ -159,6 +160,11 @@ public class DefaultLocalTransactionExecutor implements TransactionExecutor {
.stream()
.map(sqlInfo -> {
try {
if (finalE.datasourceId != null) {
DataSourceHolder.switcher().use(finalE.datasourceId);
} else {
DataSourceHolder.switcher().useDefault();
}
//执行sql
return sqlRequestExecutor.apply(sqlExecutor, sqlInfo);
} catch (SQLException e) {
@@ -188,6 +194,8 @@ public class DefaultLocalTransactionExecutor implements TransactionExecutor {
//异常信息
Exception[] exceptions = new Exception[1];
Execution execution = new Execution();
execution.datasourceId=DataSourceHolder.switcher().currentDataSourceId();
execution.request = request;
execution.callback = sqlExecuteResults -> {
results.addAll(sqlExecuteResults);
@@ -215,6 +223,9 @@ public class DefaultLocalTransactionExecutor implements TransactionExecutor {
}
protected class Execution {
protected String datasourceId;
protected SqlExecuteRequest request;
protected Consumer<List<SqlExecuteResult>> callback;

View File

@@ -8,9 +8,11 @@ import org.hswebframework.web.database.manager.SqlExecuteResult;
import org.hswebframework.web.database.manager.meta.ObjectMetadata;
import org.hswebframework.web.database.manager.meta.table.parser.MetaDataParser;
import org.hswebframework.web.database.manager.meta.table.parser.MetaDataParserRegister;
import org.hswebframework.web.database.manager.sql.TransactionInfo;
import org.hswebframework.web.datasource.DataSourceHolder;
import org.hswebframework.web.datasource.DatabaseType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.PostConstruct;
@@ -22,27 +24,32 @@ import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
*
* @author zhouhao
*/
@Slf4j
public class SimpleDatabaseManagerService implements DatabaseManagerService,MetaDataParserRegister {
public class SimpleDatabaseManagerService implements DatabaseManagerService, MetaDataParserRegister {
private Map<String, TransactionExecutor> transactionExecutorMap = new ConcurrentHashMap<>();
private Map<String, TransactionInfo> transactionInfoMap = new ConcurrentHashMap<>();
private ExecutorService executorService;
private SqlExecutor sqlExecutor;
private TransactionTemplate transactionTemplate;
private Map<DatabaseType,Map<ObjectMetadata.ObjectType,MetaDataParser<? extends ObjectMetadata>>> parserRepo=new HashMap<>();
private Map<DatabaseType, Map<ObjectMetadata.ObjectType, MetaDataParser<? extends ObjectMetadata>>> parserRepo = new HashMap<>();
@Override
public List<TransactionInfo> allTransaction() {
return new ArrayList<>(transactionInfoMap.values());
}
@PostConstruct
public void init() {
if (executorService == null) {
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2);
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
}
}
@@ -67,6 +74,10 @@ public class SimpleDatabaseManagerService implements DatabaseManagerService,Meta
DefaultLocalTransactionExecutor executor = new DefaultLocalTransactionExecutor(sqlExecutor, id, datasourceId, transactionTemplate);
transactionExecutorMap.put(id, executor);
executorService.submit(executor);
TransactionInfo info = new TransactionInfo();
info.setId(id);
info.setCreateTime(new Date());
transactionInfoMap.put(id, info);
return id;
}
@@ -77,26 +88,39 @@ public class SimpleDatabaseManagerService implements DatabaseManagerService,Meta
@Override
public void commit(String transactionId) {
TransactionExecutor executor = transactionExecutorMap.get(transactionId);
if (executor != null) {
executor.commit();
try {
TransactionExecutor executor = transactionExecutorMap.get(transactionId);
if (executor != null) {
executor.commit();
}
} finally {
transactionExecutorMap.remove(transactionId);
transactionInfoMap.remove(transactionId);
}
transactionExecutorMap.remove(transactionId);
}
@Override
public void rollback(String transactionId) {
TransactionExecutor executor = transactionExecutorMap.get(transactionId);
if (executor != null) {
executor.rollback();
try {
TransactionExecutor executor = transactionExecutorMap.get(transactionId);
if (executor != null) {
executor.rollback();
}
} finally {
transactionExecutorMap.remove(transactionId);
transactionInfoMap.remove(transactionId);
}
transactionExecutorMap.remove(transactionId);
}
@Override
public List<SqlExecuteResult> execute(String transactionId, SqlExecuteRequest request) throws Exception {
TransactionExecutor executor = transactionExecutorMap.get(transactionId);
if (executor != null) {
TransactionInfo info = transactionInfoMap.get(transactionId);
if (null != info) {
info.setLastExecuteTime(new Date());
info.getSqlHistory().addAll(request.getSql());
}
return executor.execute(request);
}
return null;
@@ -108,16 +132,16 @@ public class SimpleDatabaseManagerService implements DatabaseManagerService,Meta
}
@Override
public Map<ObjectMetadata.ObjectType, List<? extends ObjectMetadata>> getMetas(String datasourceId) {
public Map<ObjectMetadata.ObjectType, List<? extends ObjectMetadata>> getMetas() {
return parserRepo
.computeIfAbsent(DataSourceHolder.dataSource(datasourceId).getType(),t->new HashMap<>())
.computeIfAbsent(DataSourceHolder.currentDatabaseType(), t -> new HashMap<>())
.entrySet()
.parallelStream()
.collect(Collectors.toMap(Map.Entry::getKey, entry->{
.collect(Collectors.toMap(Map.Entry::getKey, entry -> {
try {
return entry.getValue().parseAll();
} catch (SQLException e) {
log.error("parse meta {} error",entry.getKey(),e);
log.error("parse meta {} error", entry.getKey(), e);
return new ArrayList<>();
}
}));
@@ -125,7 +149,7 @@ public class SimpleDatabaseManagerService implements DatabaseManagerService,Meta
@Override
public <M extends ObjectMetadata> void registerMetaDataParser(DatabaseType databaseType, ObjectMetadata.ObjectType objectType, MetaDataParser<M> parser) {
parserRepo.computeIfAbsent(databaseType,t->new HashMap<>())
.put(objectType,parser);
parserRepo.computeIfAbsent(databaseType, t -> new HashMap<>())
.put(objectType, parser);
}
}

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>hsweb-system-database-manager</artifactId>
<groupId>org.hswebframework.web</groupId>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hsweb-system-database-manager-starter</artifactId>
<dependencies>
<dependency>
<groupId>org.hswebframework.web</groupId>
<artifactId>hsweb-system-database-manager-simple</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.hswebframework.web</groupId>
<artifactId>hsweb-system-database-manager-web</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,26 @@
package org.hswebframework.web.database.mamager;
import org.hswebframework.web.database.manager.DatabaseManagerService;
import org.hswebframework.web.datasource.manager.simple.SimpleDatabaseManagerService;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan({"org.hswebframework.web.database.manager.web"
, "org.hswebframework.web.datasource.manager.simple"})
@ImportAutoConfiguration(TableMetaDataParserAutoConfiguration.class)
@AutoConfigureBefore(TableMetaDataParserAutoConfiguration.class)
public class DataBaseManagerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(DatabaseManagerService.class)
public SimpleDatabaseManagerService simpleDatabaseManagerService() {
return new SimpleDatabaseManagerService();
}
}

View File

@@ -0,0 +1,82 @@
package org.hswebframework.web.database.mamager;
import org.hswebframework.ezorm.rdb.executor.SqlExecutor;
import org.hswebframework.ezorm.rdb.meta.parser.OracleTableMetaParser;
import org.hswebframework.web.database.manager.meta.ObjectMetadata;
import org.hswebframework.web.database.manager.meta.table.parser.MetaDataParserRegister;
import org.hswebframework.web.database.manager.meta.table.parser.MetaDataParserSupplier;
import org.hswebframework.web.database.manager.meta.table.parser.TableMetaDataParser;
import org.hswebframework.web.database.manager.meta.table.parser.support.H2TableMetaDataParser;
import org.hswebframework.web.database.manager.meta.table.parser.support.MysqlTableMetaDataParser;
import org.hswebframework.web.database.manager.meta.table.parser.support.SqlServerTableMetaDataParser;
import org.hswebframework.web.datasource.DatabaseType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TableMetaDataParserAutoConfiguration {
@Autowired
private SqlExecutor sqlExecutor;
@Autowired
private MetaDataParserRegister metaDataParserRegister;
@Bean
@ConditionalOnClass(name = "org.h2.Driver")
public H2TableMetaDataParser h2TableMetaDataParser() {
return new H2TableMetaDataParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name = "com.mysql.jdbc.Driver")
public MysqlTableMetaDataParser mysqlTableMetaDataParser() {
return new MysqlTableMetaDataParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name = "oracle.jdbc.driver.OracleDriver")
public OracleTableMetaParser oracleTableMetaParser() {
return new OracleTableMetaParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name = "com.microsoft.sqlserver.jdbc.SQLServerDriver")
public SqlServerTableMetaDataParser sqlServerTableMetaDataParser() {
return new SqlServerTableMetaDataParser(sqlExecutor);
}
@Bean
@ConditionalOnClass(name = "net.sourceforge.jtds.jdbc.Driver")
public SqlServerTableMetaDataParser jstdSqlServerTableMetaDataParser() {
return new SqlServerTableMetaDataParser(sqlExecutor);
}
@Bean
public BeanPostProcessor tableMetaDataAutoParserRegister() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return o;
}
@Override
@SuppressWarnings("unchecked")
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
if (o instanceof MetaDataParserSupplier) {
MetaDataParserSupplier<? extends TableMetaDataParser> supplier = ((MetaDataParserSupplier) o);
for (DatabaseType databaseType : DatabaseType.values()) {
if (supplier.isSupport(databaseType)) {
metaDataParserRegister.registerMetaDataParser(databaseType, ObjectMetadata.ObjectType.TABLE, supplier.get());
}
}
}
return o;
}
};
}
}

View File

@@ -1,3 +1,3 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.hswebframework.web.datasource.manager.simple.DatabaseManagerAutoConfiguration
org.hswebframework.web.database.mamager.DataBaseManagerAutoConfiguration

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>hsweb-system-database-manager</artifactId>
<groupId>org.hswebframework.web</groupId>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hsweb-system-database-manager-web</artifactId>
<dependencies>
<dependency>
<groupId>org.hswebframework.web</groupId>
<artifactId>hsweb-system-database-manager-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.hswebframework.web</groupId>
<artifactId>hsweb-commons-controller</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,121 @@
package org.hswebframework.web.database.manager.web;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.hswebframework.web.Sqls;
import org.hswebframework.web.authorization.Permission;
import org.hswebframework.web.authorization.annotation.Authorize;
import org.hswebframework.web.controller.message.ResponseMessage;
import org.hswebframework.web.database.manager.DatabaseManagerService;
import org.hswebframework.web.database.manager.SqlExecuteRequest;
import org.hswebframework.web.database.manager.SqlExecuteResult;
import org.hswebframework.web.database.manager.SqlInfo;
import org.hswebframework.web.database.manager.meta.ObjectMetadata;
import org.hswebframework.web.database.manager.sql.TransactionInfo;
import org.hswebframework.web.datasource.DataSourceHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/database/manager")
@Api(value = "开发人员工具-数据库维护", description = "数据库维护")
@Authorize(permission = "database-manager",description = "数据库维护")
public class DataBaseManagerController {
@Autowired
private DatabaseManagerService databaseManagerService;
@GetMapping("/metas")
@Authorize(action = Permission.ACTION_QUERY)
@ApiOperation("获取数据库元数据")
public ResponseMessage<Map<ObjectMetadata.ObjectType, List<? extends ObjectMetadata>>> parseAllObject() throws Exception {
return parseAllObject(null);
}
@GetMapping("/metas/{datasourceId}")
@Authorize(action = Permission.ACTION_QUERY)
@ApiOperation("获取指定数据源的元数据")
public ResponseMessage<Map<ObjectMetadata.ObjectType, List<? extends ObjectMetadata>>> parseAllObject(@PathVariable String datasourceId) throws Exception {
DataSourceHolder.switcher().use(datasourceId);
return ResponseMessage.ok(databaseManagerService.getMetas());
}
@PostMapping("/execute/{datasourceId}")
@Authorize(action = "execute", description = "执行SQL")
@ApiOperation("指定数据源执行SQL")
public ResponseMessage<List<SqlExecuteResult>> execute(
@PathVariable String datasourceId
, @RequestBody String sqlLines) throws Exception {
DataSourceHolder.switcher().use(datasourceId);
return ResponseMessage.ok(databaseManagerService
.execute(SqlExecuteRequest.builder()
.sql(parseSql(sqlLines))
.build()));
}
@PostMapping("/execute")
@ApiOperation("执行SQL")
@Authorize(action = "execute", description = "执行SQL")
public ResponseMessage<List<SqlExecuteResult>> execute(@RequestBody String sqlLines) throws Exception {
return ResponseMessage.ok(databaseManagerService
.execute(SqlExecuteRequest.builder()
.sql(parseSql(sqlLines))
.build()));
}
@PostMapping("/transactional/execute/{transactionalId}")
@Authorize(action = "execute", description = "执行SQL")
@ApiOperation("开启事务执行SQL")
public ResponseMessage<List<SqlExecuteResult>> executeTransactional(@PathVariable String transactionalId, @RequestBody String sqlLines) throws Exception {
return ResponseMessage.ok(databaseManagerService
.execute(transactionalId,SqlExecuteRequest.builder()
.sql(parseSql(sqlLines))
.build()));
}
@GetMapping("/transactional/new")
@Authorize(action = "execute", description = "执行SQL")
@ApiOperation("新建事务")
public ResponseMessage<String> newTransaction() throws Exception {
return ResponseMessage.ok(databaseManagerService.newTransaction());
}
@GetMapping("/transactional")
@Authorize(action = "execute", description = "执行SQL")
@ApiOperation("获取全部事务信息")
public ResponseMessage<List<TransactionInfo>> allTransaction() throws Exception {
return ResponseMessage.ok(databaseManagerService.allTransaction());
}
@PostMapping("/transactional/{id}/commit")
@Authorize(action = "execute", description = "执行SQL")
@ApiOperation("提交事务")
public ResponseMessage<String> commitTransaction(@PathVariable String id) throws Exception {
databaseManagerService.commit(id);
return ResponseMessage.ok();
}
@PostMapping("/transactional/{id}/rollback")
@Authorize(action = "execute", description = "执行SQL")
@ApiOperation("回滚事务")
public ResponseMessage<String> rollbackTransaction(@PathVariable String id) throws Exception {
databaseManagerService.rollback(id);
return ResponseMessage.ok();
}
private List<SqlInfo> parseSql(String sqlText) {
List<String> sqlList = Sqls.parse(sqlText);
return sqlList.stream().map(sql -> {
SqlInfo sqlInfo = new SqlInfo();
sqlInfo.setSql(sql);
sqlInfo.setType(sql.split("[ ]")[0].toLowerCase());
return sqlInfo;
}).collect(Collectors.toList());
}
}

View File

@@ -15,6 +15,8 @@
<modules>
<module>hsweb-system-database-manager-api</module>
<module>hsweb-system-database-manager-simple</module>
<module>hsweb-system-database-manager-web</module>
<module>hsweb-system-database-manager-starter</module>
</modules>
</project>