Skip to content

Commit 7dbc313

Browse files
author
core-lib
committed
支持自动备份
1 parent f3de4df commit 7dbc313

11 files changed

Lines changed: 223 additions & 8 deletions

src/main/java/io/sqlman/SqlDialectSupport.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,14 @@ public interface SqlDialectSupport {
6262
*/
6363
void unlock(Connection connection) throws SQLException;
6464

65+
/**
66+
* 备份表
67+
*
68+
* @param connection 连接
69+
* @param script 脚本
70+
* @param ordinal 语句下标
71+
* @throws SQLException SQL异常
72+
*/
73+
void backup(Connection connection, SqlScript script, int ordinal) throws SQLException;
74+
6575
}

src/main/java/io/sqlman/SqlSentence.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,10 @@ public interface SqlSentence {
2222
*/
2323
String value();
2424

25+
/**
26+
* 操作表名
27+
*
28+
* @return 操作表名
29+
*/
30+
String table();
2531
}

src/main/java/io/sqlman/dialect/AbstractDialectSupport.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package io.sqlman.dialect;
22

3-
import io.sqlman.SqlDialectSupport;
4-
import io.sqlman.SqlUtils;
5-
import io.sqlman.SqlVersion;
3+
import io.sqlman.*;
64

75
import java.sql.Connection;
86
import java.sql.PreparedStatement;
@@ -126,6 +124,22 @@ public void unlock(Connection connection) throws SQLException {
126124
connection.prepareStatement("DROP TABLE " + table.toUpperCase() + "_LOCK").executeUpdate();
127125
}
128126

127+
@Override
128+
public void backup(Connection connection, SqlScript script, int ordinal) throws SQLException {
129+
SqlSentence sentence = script.sentence(ordinal);
130+
String table = sentence.table();
131+
if (table == null || table.trim().isEmpty()) {
132+
return;
133+
}
134+
try {
135+
connection.prepareStatement("SELECT COUNT(*) FROM " + table).executeQuery();
136+
} catch (SQLException e) {
137+
return;
138+
}
139+
table = table + "_bak_" + script.version().replace('.', '_') + "$" + ordinal;
140+
connection.prepareStatement("CREATE TABLE " + table + " AS SELECT * FROM " + sentence.table()).executeUpdate();
141+
}
142+
129143
public String getTable() {
130144
return table;
131145
}

src/main/java/io/sqlman/dialect/SQLServerDialectSupport.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.sqlman.dialect;
22

33
import io.sqlman.SqlDialectSupport;
4+
import io.sqlman.SqlScript;
5+
import io.sqlman.SqlSentence;
46

57
import java.sql.Connection;
68
import java.sql.SQLException;
@@ -47,4 +49,19 @@ public void create(Connection connection) throws SQLException {
4749
connection.prepareStatement(ddl.toString()).executeUpdate();
4850
}
4951

52+
@Override
53+
public void backup(Connection connection, SqlScript script, int ordinal) throws SQLException {
54+
SqlSentence sentence = script.sentence(ordinal);
55+
String table = sentence.table();
56+
if (table == null || table.trim().isEmpty()) {
57+
return;
58+
}
59+
try {
60+
connection.prepareStatement("SELECT COUNT(*) FROM " + table).executeQuery();
61+
} catch (SQLException e) {
62+
return;
63+
}
64+
table = table + "_bak_" + script.version().replace('.', '_') + "$" + ordinal;
65+
connection.prepareStatement("SELECT * INTO " + table + " FROM " + sentence.table()).executeUpdate();
66+
}
5067
}

src/main/java/io/sqlman/script/DruidScriptResolver.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.sqlman.script;
22

33
import com.alibaba.druid.sql.SQLUtils;
4+
import com.alibaba.druid.sql.ast.SQLObject;
45
import com.alibaba.druid.sql.ast.SQLStatement;
6+
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
57
import com.alibaba.druid.sql.parser.ParserException;
68
import com.alibaba.druid.util.JdbcUtils;
79
import io.sqlman.*;
@@ -57,7 +59,16 @@ public SqlScript resolve(SqlSource source) throws IncorrectSyntaxException, IOEx
5759
while (sql.endsWith(suffix)) {
5860
sql = sql.substring(0, sql.length() - 1);
5961
}
60-
SqlSentence sentence = new DruidSentence(index + 1, sql);
62+
String table = null;
63+
List<SQLObject> children = statement.getChildren();
64+
for (SQLObject child : children) {
65+
if (child instanceof SQLExprTableSource) {
66+
SQLExprTableSource tableSource = (SQLExprTableSource) child;
67+
table = tableSource.getName().toString();
68+
break;
69+
}
70+
}
71+
SqlSentence sentence = new DruidSentence(index + 1, sql, table);
6172
sentences.add(sentence);
6273
}
6374
return new DruidScript(source.name(), source.version(), source.parameters(), source.description(), sentences);

src/main/java/io/sqlman/script/DruidSentence.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
public class DruidSentence implements SqlSentence {
1212
private final int ordinal;
1313
private final String value;
14+
private final String table;
1415

15-
public DruidSentence(int ordinal, String value) {
16+
public DruidSentence(int ordinal, String value, String table) {
1617
if (ordinal < 1) {
1718
throw new IllegalArgumentException("ordinal must not lesser than 1");
1819
}
@@ -21,6 +22,7 @@ public DruidSentence(int ordinal, String value) {
2122
}
2223
this.ordinal = ordinal;
2324
this.value = value;
25+
this.table = table;
2426
}
2527

2628
@Override
@@ -33,6 +35,11 @@ public String value() {
3335
return value;
3436
}
3537

38+
@Override
39+
public String table() {
40+
return table;
41+
}
42+
3643
@Override
3744
public String toString() {
3845
return value;

src/main/java/io/sqlman/spring/JdbcManagerConfiguration.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.sqlman.spring;
22

33
import io.sqlman.*;
4+
import io.sqlman.version.JdbcIsolation;
5+
import io.sqlman.version.JdbcMode;
46
import io.sqlman.version.JdbcVersionManager;
57
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
68
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -54,12 +56,16 @@ public JdbcVersionManager sqlmanJdbcVersionManager(ApplicationContext applicatio
5456
if (dataSource == null) {
5557
throw new IllegalStateException("no dataSource found in application context named: " + properties.getDataSource());
5658
}
59+
JdbcIsolation defaultIsolation = properties.getDefaultIsolation();
60+
JdbcMode defaultMode = properties.getDefaultMode();
5761
JdbcVersionManager jdbcVersionManager = new JdbcVersionManager(
5862
dataSource,
5963
scriptProvider,
6064
scriptResolver,
6165
dialectSupport,
62-
loggerSupplier
66+
loggerSupplier,
67+
defaultIsolation,
68+
defaultMode
6369
);
6470
jdbcVersionManager.upgrade();
6571
return jdbcVersionManager;

src/main/java/io/sqlman/spring/JdbcManagerProperties.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.sqlman.spring;
22

3+
import io.sqlman.version.JdbcIsolation;
4+
import io.sqlman.version.JdbcMode;
35
import org.springframework.boot.context.properties.ConfigurationProperties;
46

57
/**
@@ -15,11 +17,37 @@ public class JdbcManagerProperties extends AbstractManagerProperties {
1517
*/
1618
private String dataSource = "dataSource";
1719

20+
/**
21+
* default transaction isolation level
22+
*/
23+
private JdbcIsolation defaultIsolation;
24+
25+
/**
26+
* default mode: SAFETY or DANGER which means backup or not backup before the sql sentence being execute
27+
*/
28+
private JdbcMode defaultMode;
29+
1830
public String getDataSource() {
1931
return dataSource;
2032
}
2133

2234
public void setDataSource(String dataSource) {
2335
this.dataSource = dataSource;
2436
}
37+
38+
public JdbcIsolation getDefaultIsolation() {
39+
return defaultIsolation;
40+
}
41+
42+
public void setDefaultIsolation(JdbcIsolation defaultIsolation) {
43+
this.defaultIsolation = defaultIsolation;
44+
}
45+
46+
public JdbcMode getDefaultMode() {
47+
return defaultMode;
48+
}
49+
50+
public void setDefaultMode(JdbcMode defaultMode) {
51+
this.defaultMode = defaultMode;
52+
}
2553
}

src/main/java/io/sqlman/version/JdbcInstruction.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ public interface JdbcInstruction {
1111
* 原子性执行:即整个脚本作为一个事务整体,不可分割。
1212
*/
1313
String INSTRUCTION_ATOMIC = "ATOMIC";
14+
15+
/**
16+
* 安全模式:备份被操作的表
17+
*/
18+
String INSTRUCTION_SAFETY = "SAFETY";
19+
20+
/**
21+
* 危险模式:不备份被操作的表
22+
*/
23+
String INSTRUCTION_DANGER = "DANGER";
24+
1425
/**
1526
* 隔离级别:读未提交
1627
*/
@@ -27,5 +38,4 @@ public interface JdbcInstruction {
2738
* 隔离级别:串行执行
2839
*/
2940
String INSTRUCTION_SERIALIZABLE = "SERIALIZABLE";
30-
3141
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package io.sqlman.version;
2+
3+
import java.util.Set;
4+
5+
/**
6+
* 模式
7+
*
8+
* @author Payne 646742615@qq.com
9+
* 2019/8/2 15:07
10+
*/
11+
public enum JdbcMode {
12+
13+
/**
14+
* 安全模式
15+
*/
16+
SAFETY,
17+
/**
18+
* 危险模式
19+
*/
20+
DANGER;
21+
22+
/**
23+
* 从指令集中获取模式,如果没有模式指令则返回{@code null}
24+
*
25+
* @param instructions 指令集
26+
* @return 对应模式或{@code null}当没有模式指令时
27+
*/
28+
public static JdbcMode valueOf(Set<String> instructions) {
29+
if (instructions == null || instructions.isEmpty()) {
30+
return null;
31+
}
32+
JdbcMode mode = null;
33+
for (JdbcMode value : values()) {
34+
if (instructions.contains(value.name())) {
35+
if (mode != null) {
36+
throw new IllegalArgumentException("multiple mode instructions");
37+
} else {
38+
mode = value;
39+
}
40+
}
41+
}
42+
return mode;
43+
}
44+
45+
}

0 commit comments

Comments
 (0)