Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
56d4c7e9
提交
56d4c7e9
authored
8 年前
作者:
Noel Grandin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix for creating and accessing views in MULTITHREADED mode
上级
8baa8042
master
noel-pr1
stumc-Issue#576
version-1.4.198
version-1.4.197
version-1.4.196
version-1.4.195
version-1.4.194
version-1.4.193
无相关合并请求
隐藏空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
318 行增加
和
42 行删除
+318
-42
changelog.html
h2/src/docsrc/html/changelog.html
+2
-0
CreateView.java
h2/src/main/org/h2/command/ddl/CreateView.java
+18
-17
Database.java
h2/src/main/org/h2/engine/Database.java
+16
-0
Schema.java
h2/src/main/org/h2/schema/Schema.java
+26
-25
CaseInsensitiveConcurrentMap.java
h2/src/main/org/h2/value/CaseInsensitiveConcurrentMap.java
+45
-0
NullableKeyConcurrentMap.java
h2/src/main/org/h2/value/NullableKeyConcurrentMap.java
+44
-0
TestMultiThreadingH2.java
h2/src/test/TestMultiThreadingH2.java
+94
-0
TestMultiThread.java
h2/src/test/org/h2/test/db/TestMultiThread.java
+73
-0
没有找到文件。
h2/src/docsrc/html/changelog.html
浏览文件 @
56d4c7e9
...
...
@@ -21,6 +21,8 @@ Change Log
<h2>
Next Version (unreleased)
</h2>
<ul>
<li>
Fix for creating and accessing views in MULTITHREADED mode, test-case courtesy of Daniel Rosenbaum
</li>
<li>
Issue #266: Spatial index not updating, fixed by merging PR #267
</li>
<li>
PR #302: add support for "with"-subqueries into "join"
&
"sub-query" statements
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/command/ddl/CreateView.java
浏览文件 @
56d4c7e9
...
...
@@ -6,7 +6,6 @@
package
org
.
h2
.
command
.
ddl
;
import
java.util.ArrayList
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.CommandInterface
;
import
org.h2.command.dml.Query
;
...
...
@@ -102,25 +101,27 @@ public class CreateView extends SchemaCommand {
// The view creates a Prepared command object, which belongs to a
// session, so we pass the system session down.
Session
sysSession
=
db
.
getSystemSession
();
try
{
if
(
view
==
null
)
{
Schema
schema
=
session
.
getDatabase
().
getSchema
(
session
.
getCurrentSchemaName
());
sysSession
.
setCurrentSchema
(
schema
);
Column
[]
columnTemplates
=
null
;
if
(
columnNames
!=
null
)
{
columnTemplates
=
new
Column
[
columnNames
.
length
];
for
(
int
i
=
0
;
i
<
columnNames
.
length
;
++
i
)
{
columnTemplates
[
i
]
=
new
Column
(
columnNames
[
i
],
Value
.
UNKNOWN
);
synchronized
(
sysSession
)
{
try
{
if
(
view
==
null
)
{
Schema
schema
=
session
.
getDatabase
().
getSchema
(
session
.
getCurrentSchemaName
());
sysSession
.
setCurrentSchema
(
schema
);
Column
[]
columnTemplates
=
null
;
if
(
columnNames
!=
null
)
{
columnTemplates
=
new
Column
[
columnNames
.
length
];
for
(
int
i
=
0
;
i
<
columnNames
.
length
;
++
i
)
{
columnTemplates
[
i
]
=
new
Column
(
columnNames
[
i
],
Value
.
UNKNOWN
);
}
}
view
=
new
TableView
(
getSchema
(),
id
,
viewName
,
querySQL
,
null
,
columnTemplates
,
sysSession
,
false
);
}
else
{
view
.
replace
(
querySQL
,
columnNames
,
sysSession
,
false
,
force
);
view
.
setModified
();
}
view
=
new
TableView
(
getSchema
(),
id
,
viewName
,
querySQL
,
null
,
columnTemplates
,
sysSession
,
false
);
}
else
{
view
.
replace
(
querySQL
,
columnNames
,
sysSession
,
false
,
force
);
view
.
setModified
();
}
finally
{
sysSession
.
setCurrentSchema
(
db
.
getSchema
(
Constants
.
SCHEMA_MAIN
));
}
}
finally
{
sysSession
.
setCurrentSchema
(
db
.
getSchema
(
Constants
.
SCHEMA_MAIN
));
}
if
(
comment
!=
null
)
{
view
.
setComment
(
comment
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/Database.java
浏览文件 @
56d4c7e9
...
...
@@ -14,6 +14,7 @@ import java.util.HashSet;
import
java.util.Properties
;
import
java.util.Set
;
import
java.util.StringTokenizer
;
import
java.util.concurrent.ConcurrentHashMap
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.JavaObjectSerializer
;
...
...
@@ -66,8 +67,10 @@ import org.h2.util.SourceCompiler;
import
org.h2.util.StringUtils
;
import
org.h2.util.TempFileDeleter
;
import
org.h2.util.Utils
;
import
org.h2.value.CaseInsensitiveConcurrentMap
;
import
org.h2.value.CaseInsensitiveMap
;
import
org.h2.value.CompareMode
;
import
org.h2.value.NullableKeyConcurrentMap
;
import
org.h2.value.Value
;
import
org.h2.value.ValueInt
;
...
...
@@ -2773,6 +2776,19 @@ public class Database implements DataHandler {
new
CaseInsensitiveMap
<
V
>();
}
/**
* Create a new hash map. Depending on the configuration, the key is case
* sensitive or case insensitive.
*
* @param <V> the value type
* @return the hash map
*/
public
<
V
>
ConcurrentHashMap
<
String
,
V
>
newConcurrentStringMap
()
{
return
dbSettings
.
databaseToUpper
?
new
NullableKeyConcurrentMap
<
V
>()
:
new
CaseInsensitiveConcurrentMap
<
V
>();
}
/**
* Compare two identifiers (table names, column names,...) and verify they
* are equal. Case sensitivity depends on the configuration.
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/schema/Schema.java
浏览文件 @
56d4c7e9
...
...
@@ -6,8 +6,9 @@
package
org
.
h2
.
schema
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.ddl.CreateTableData
;
import
org.h2.constraint.Constraint
;
...
...
@@ -37,13 +38,13 @@ public class Schema extends DbObjectBase {
private
User
owner
;
private
final
boolean
system
;
private
final
HashMap
<
String
,
Table
>
tablesAndViews
;
private
final
HashMap
<
String
,
Index
>
indexes
;
private
final
HashMap
<
String
,
Sequence
>
sequences
;
private
final
HashMap
<
String
,
TriggerObject
>
triggers
;
private
final
HashMap
<
String
,
Constraint
>
constraints
;
private
final
HashMap
<
String
,
Constant
>
constants
;
private
final
HashMap
<
String
,
FunctionAlias
>
functions
;
private
final
Concurrent
HashMap
<
String
,
Table
>
tablesAndViews
;
private
final
Concurrent
HashMap
<
String
,
Index
>
indexes
;
private
final
Concurrent
HashMap
<
String
,
Sequence
>
sequences
;
private
final
Concurrent
HashMap
<
String
,
TriggerObject
>
triggers
;
private
final
Concurrent
HashMap
<
String
,
Constraint
>
constraints
;
private
final
Concurrent
HashMap
<
String
,
Constant
>
constants
;
private
final
Concurrent
HashMap
<
String
,
FunctionAlias
>
functions
;
/**
* The set of returned unique names that are not yet stored. It is used to
...
...
@@ -64,13 +65,13 @@ public class Schema extends DbObjectBase {
*/
public
Schema
(
Database
database
,
int
id
,
String
schemaName
,
User
owner
,
boolean
system
)
{
tablesAndViews
=
database
.
newStringMap
();
indexes
=
database
.
newStringMap
();
sequences
=
database
.
newStringMap
();
triggers
=
database
.
newStringMap
();
constraints
=
database
.
newStringMap
();
constants
=
database
.
newStringMap
();
functions
=
database
.
newStringMap
();
tablesAndViews
=
database
.
new
Concurrent
StringMap
();
indexes
=
database
.
new
Concurrent
StringMap
();
sequences
=
database
.
new
Concurrent
StringMap
();
triggers
=
database
.
new
Concurrent
StringMap
();
constraints
=
database
.
new
Concurrent
StringMap
();
constants
=
database
.
new
Concurrent
StringMap
();
functions
=
database
.
new
Concurrent
StringMap
();
initDbObjectBase
(
database
,
id
,
schemaName
,
Trace
.
SCHEMA
);
this
.
owner
=
owner
;
this
.
system
=
system
;
...
...
@@ -175,8 +176,8 @@ public class Schema extends DbObjectBase {
}
@SuppressWarnings
(
"unchecked"
)
private
Hash
Map
<
String
,
SchemaObject
>
getMap
(
int
type
)
{
Hash
Map
<
String
,
?
extends
SchemaObject
>
result
;
private
Map
<
String
,
SchemaObject
>
getMap
(
int
type
)
{
Map
<
String
,
?
extends
SchemaObject
>
result
;
switch
(
type
)
{
case
DbObject
.
TABLE_OR_VIEW
:
result
=
tablesAndViews
;
...
...
@@ -202,7 +203,7 @@ public class Schema extends DbObjectBase {
default
:
throw
DbException
.
throwInternalError
(
"type="
+
type
);
}
return
(
Hash
Map
<
String
,
SchemaObject
>)
result
;
return
(
Map
<
String
,
SchemaObject
>)
result
;
}
/**
...
...
@@ -217,7 +218,7 @@ public class Schema extends DbObjectBase {
DbException
.
throwInternalError
(
"wrong schema"
);
}
String
name
=
obj
.
getName
();
Hash
Map
<
String
,
SchemaObject
>
map
=
getMap
(
obj
.
getType
());
Map
<
String
,
SchemaObject
>
map
=
getMap
(
obj
.
getType
());
if
(
SysProperties
.
CHECK
&&
map
.
get
(
name
)
!=
null
)
{
DbException
.
throwInternalError
(
"object already exists: "
+
name
);
}
...
...
@@ -233,7 +234,7 @@ public class Schema extends DbObjectBase {
*/
public
void
rename
(
SchemaObject
obj
,
String
newName
)
{
int
type
=
obj
.
getType
();
Hash
Map
<
String
,
SchemaObject
>
map
=
getMap
(
type
);
Map
<
String
,
SchemaObject
>
map
=
getMap
(
type
);
if
(
SysProperties
.
CHECK
)
{
if
(!
map
.
containsKey
(
obj
.
getName
()))
{
DbException
.
throwInternalError
(
"not found: "
+
obj
.
getName
());
...
...
@@ -357,7 +358,7 @@ public class Schema extends DbObjectBase {
}
private
String
getUniqueName
(
DbObject
obj
,
Hash
Map
<
String
,
?
extends
SchemaObject
>
map
,
String
prefix
)
{
Map
<
String
,
?
extends
SchemaObject
>
map
,
String
prefix
)
{
String
hash
=
Integer
.
toHexString
(
obj
.
getName
().
hashCode
()).
toUpperCase
();
String
name
=
null
;
synchronized
(
temporaryUniqueNames
)
{
...
...
@@ -390,7 +391,7 @@ public class Schema extends DbObjectBase {
* @return the unique name
*/
public
String
getUniqueConstraintName
(
Session
session
,
Table
table
)
{
Hash
Map
<
String
,
Constraint
>
tableConstraints
;
Map
<
String
,
Constraint
>
tableConstraints
;
if
(
table
.
isTemporary
()
&&
!
table
.
isGlobalTemporary
())
{
tableConstraints
=
session
.
getLocalTempTableConstraints
();
}
else
{
...
...
@@ -408,7 +409,7 @@ public class Schema extends DbObjectBase {
* @return the unique name
*/
public
String
getUniqueIndexName
(
Session
session
,
Table
table
,
String
prefix
)
{
Hash
Map
<
String
,
Index
>
tableIndexes
;
Map
<
String
,
Index
>
tableIndexes
;
if
(
table
.
isTemporary
()
&&
!
table
.
isGlobalTemporary
())
{
tableIndexes
=
session
.
getLocalTempTableIndexes
();
}
else
{
...
...
@@ -523,7 +524,7 @@ public class Schema extends DbObjectBase {
* @return a (possible empty) list of all objects
*/
public
ArrayList
<
SchemaObject
>
getAll
(
int
type
)
{
Hash
Map
<
String
,
SchemaObject
>
map
=
getMap
(
type
);
Map
<
String
,
SchemaObject
>
map
=
getMap
(
type
);
return
New
.
arrayList
(
map
.
values
());
}
...
...
@@ -557,7 +558,7 @@ public class Schema extends DbObjectBase {
*/
public
void
remove
(
SchemaObject
obj
)
{
String
objName
=
obj
.
getName
();
Hash
Map
<
String
,
SchemaObject
>
map
=
getMap
(
obj
.
getType
());
Map
<
String
,
SchemaObject
>
map
=
getMap
(
obj
.
getType
());
if
(
SysProperties
.
CHECK
&&
!
map
.
containsKey
(
objName
))
{
DbException
.
throwInternalError
(
"not found: "
+
objName
);
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/CaseInsensitiveConcurrentMap.java
0 → 100644
浏览文件 @
56d4c7e9
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
value
;
import
java.util.concurrent.ConcurrentHashMap
;
import
org.h2.util.StringUtils
;
/**
* A concurrent hash map with a case-insensitive string key, that also allows NULL as a key.
*
* @param <V> the value type
*/
public
class
CaseInsensitiveConcurrentMap
<
V
>
extends
ConcurrentHashMap
<
String
,
V
>
{
private
static
final
long
serialVersionUID
=
1L
;
private
static
final
String
NULL
=
new
String
(
new
byte
[
0
]);
@Override
public
V
get
(
Object
key
)
{
return
super
.
get
(
toUpper
(
key
));
}
@Override
public
V
put
(
String
key
,
V
value
)
{
return
super
.
put
(
toUpper
(
key
),
value
);
}
@Override
public
boolean
containsKey
(
Object
key
)
{
return
super
.
containsKey
(
toUpper
(
key
));
}
@Override
public
V
remove
(
Object
key
)
{
return
super
.
remove
(
toUpper
(
key
));
}
private
static
String
toUpper
(
Object
key
)
{
return
key
==
null
?
NULL
:
StringUtils
.
toUpperEnglish
(
key
.
toString
());
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/NullableKeyConcurrentMap.java
0 → 100644
浏览文件 @
56d4c7e9
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
value
;
import
java.util.concurrent.ConcurrentHashMap
;
/**
* A concurrent hash map that allows null keys
*
* @param <V> the value type
*/
public
class
NullableKeyConcurrentMap
<
V
>
extends
ConcurrentHashMap
<
String
,
V
>
{
private
static
final
long
serialVersionUID
=
1L
;
private
static
final
String
NULL
=
new
String
(
new
byte
[
0
]);
@Override
public
V
get
(
Object
key
)
{
return
super
.
get
(
toUpper
(
key
));
}
@Override
public
V
put
(
String
key
,
V
value
)
{
return
super
.
put
(
toUpper
(
key
),
value
);
}
@Override
public
boolean
containsKey
(
Object
key
)
{
return
super
.
containsKey
(
toUpper
(
key
));
}
@Override
public
V
remove
(
Object
key
)
{
return
super
.
remove
(
toUpper
(
key
));
}
private
static
String
toUpper
(
Object
key
)
{
return
key
==
null
?
NULL
:
key
.
toString
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/TestMultiThreadingH2.java
0 → 100644
浏览文件 @
56d4c7e9
import
java.io.PrintWriter
;
import
java.io.StringWriter
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.ResultSet
;
import
java.sql.Statement
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
public
class
TestMultiThreadingH2
{
private
static
final
String
JDBC_URL
=
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MULTI_THREADED=1;"
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
Class
.
forName
(
"org.h2.Driver"
);
// create some common tables and views
final
Connection
conn
=
DriverManager
.
getConnection
(
JDBC_URL
,
"sa"
,
""
);
final
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"CREATE TABLE INVOICE(INVOICE_ID INT PRIMARY KEY, AMOUNT DECIMAL)"
);
stat
.
execute
(
"CREATE VIEW INVOICE_VIEW as SELECT * FROM INVOICE"
);
stat
.
execute
(
"CREATE TABLE INVOICE_DETAIL(DETAIL_ID INT PRIMARY KEY, INVOICE_ID INT, DESCRIPTION VARCHAR)"
);
stat
.
execute
(
"CREATE VIEW INVOICE_DETAIL_VIEW as SELECT * FROM INVOICE_DETAIL"
);
stat
.
close
();
conn
.
close
();
// create views that reference the common views in different threads
ExecutorService
executor
=
Executors
.
newFixedThreadPool
(
8
);
for
(
int
i
=
0
;
i
<
30000
;
i
++)
{
final
int
j
=
i
;
executor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
try
{
Connection
conn2
=
DriverManager
.
getConnection
(
JDBC_URL
,
"sa"
,
""
);
Statement
stat2
=
conn2
.
createStatement
();
stat2
.
execute
(
"CREATE VIEW INVOICE_VIEW"
+
j
+
" as SELECT * FROM INVOICE_VIEW"
);
// the following query intermittently results in a
// NullPointerException
stat2
.
execute
(
"CREATE VIEW INVOICE_DETAIL_VIEW"
+
j
+
" as SELECT DTL.* FROM INVOICE_VIEW"
+
j
+
" INV JOIN INVOICE_DETAIL_VIEW DTL ON INV.INVOICE_ID = DTL.INVOICE_ID"
+
" WHERE DESCRIPTION='TEST'"
);
ResultSet
rs
=
stat2
.
executeQuery
(
"SELECT * FROM INVOICE_VIEW"
+
j
);
rs
.
next
();
rs
.
close
();
rs
=
stat2
.
executeQuery
(
"SELECT * FROM INVOICE_DETAIL_VIEW"
+
j
);
rs
.
next
();
rs
.
close
();
stat
.
close
();
conn
.
close
();
}
catch
(
Exception
ex
)
{
System
.
out
.
println
(
"exception at iteration "
+
j
+
":\n"
+
getStackTrace
(
ex
)
+
"\n"
);
}
}
});
}
executor
.
shutdown
();
try
{
executor
.
awaitTermination
(
24
,
TimeUnit
.
HOURS
);
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Utility method to get a stacktrace from a string.
*/
public
static
String
getStackTrace
(
Throwable
t
)
{
StringWriter
stringWriter
=
new
StringWriter
();
t
.
printStackTrace
(
new
PrintWriter
(
stringWriter
));
return
stringWriter
.
toString
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/db/TestMultiThread.java
浏览文件 @
56d4c7e9
...
...
@@ -12,7 +12,13 @@ import java.sql.PreparedStatement;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
java.util.ArrayList
;
import
java.util.Random
;
import
java.util.concurrent.Callable
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.Future
;
import
java.util.concurrent.TimeUnit
;
import
org.h2.test.TestAll
;
import
org.h2.test.TestBase
;
import
org.h2.util.SmallLRUCache
;
...
...
@@ -61,6 +67,7 @@ public class TestMultiThread extends TestBase implements Runnable {
testConcurrentAnalyze
();
testConcurrentInsertUpdateSelect
();
testLockModeWithMultiThreaded
();
testViews
();
}
private
void
testConcurrentSchemaChange
()
throws
Exception
{
...
...
@@ -292,4 +299,70 @@ public class TestMultiThread extends TestBase implements Runnable {
deleteDb
(
"lockMode"
);
}
private
void
testViews
()
throws
Exception
{
// currently the combination of LOCK_MODE=0 and MULTI_THREADED
// is not supported
deleteDb
(
"lockMode"
);
final
String
url
=
getURL
(
"lockMode;MULTI_THREADED=1"
,
true
);
// create some common tables and views
final
Connection
conn
=
getConnection
(
url
);
final
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"CREATE TABLE INVOICE(INVOICE_ID INT PRIMARY KEY, AMOUNT DECIMAL)"
);
stat
.
execute
(
"CREATE VIEW INVOICE_VIEW as SELECT * FROM INVOICE"
);
stat
.
execute
(
"CREATE TABLE INVOICE_DETAIL(DETAIL_ID INT PRIMARY KEY, INVOICE_ID INT, DESCRIPTION VARCHAR)"
);
stat
.
execute
(
"CREATE VIEW INVOICE_DETAIL_VIEW as SELECT * FROM INVOICE_DETAIL"
);
stat
.
close
();
conn
.
close
();
// create views that reference the common views in different threads
final
ExecutorService
executor
=
Executors
.
newFixedThreadPool
(
8
);
final
ArrayList
<
Future
<
Void
>>
jobs
=
new
ArrayList
<
Future
<
Void
>>();
for
(
int
i
=
0
;
i
<
1000
;
i
++)
{
final
int
j
=
i
;
jobs
.
add
(
executor
.
submit
(
new
Callable
<
Void
>()
{
@Override
public
Void
call
()
throws
Exception
{
final
Connection
conn2
=
getConnection
(
url
);
Statement
stat2
=
conn2
.
createStatement
();
stat2
.
execute
(
"CREATE VIEW INVOICE_VIEW"
+
j
+
" as SELECT * FROM INVOICE_VIEW"
);
// the following query intermittently results in a
// NullPointerException
stat2
.
execute
(
"CREATE VIEW INVOICE_DETAIL_VIEW"
+
j
+
" as SELECT DTL.* FROM INVOICE_VIEW"
+
j
+
" INV JOIN INVOICE_DETAIL_VIEW DTL ON INV.INVOICE_ID = DTL.INVOICE_ID"
+
" WHERE DESCRIPTION='TEST'"
);
ResultSet
rs
=
stat2
.
executeQuery
(
"SELECT * FROM INVOICE_VIEW"
+
j
);
rs
.
next
();
rs
.
close
();
rs
=
stat2
.
executeQuery
(
"SELECT * FROM INVOICE_DETAIL_VIEW"
+
j
);
rs
.
next
();
rs
.
close
();
stat
.
close
();
conn
.
close
();
return
null
;
}
}));
}
// check for exceptions
for
(
Future
<
Void
>
job
:
jobs
)
{
job
.
get
();
}
executor
.
shutdown
();
executor
.
awaitTermination
(
20
,
TimeUnit
.
SECONDS
);
deleteDb
(
"lockMode"
);
}
}
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论