Java Web应用程序数据访问类中的线程安全性

0 java multithreading java-ee

我的业余爱好项目是Java Web应用程序.这是一个带有表单的简单网页.用户填写表单,提交并显示一些结果.

数据来自JDBC连接.当用户提交时,我验证输入,构建"CREATE ALIAS"语句,"SELECT"语句和"DROP ALIAS"语句.我执行它们并从查询中执行我需要对ResultSet执行的任何操作.

由于我正在使用的特定数据库/ JDBC组合上的ALIASes存在问题,因此每次运行查询时都需要使用唯一名称创建这些ALIAS.我正在使用int来确保每次进入数据库时​​都会增加.

所以,我的数据访问类看起来有点像:

private final static Connection connection = // initialized however

private static int uniqueInvocationNumber = 0;

public static Whatever getData(ValidatedQuery validatedQuery) {
    String aliasName = "TEMPALIAS" + String.valueOf(uniqueInvocationNumber);
    // build statements, execute statements, deal with results
    uniqueInvocationNumber++;
}
Run Code Online (Sandbox Code Playgroud)

这有效.然而,我最近意识到我坚定地坚持使用Jon Skeet的线程知识第0阶段("完全无知 - 忽略任何问题的可能性.") - 我从未编写过线程代码或线程感知代码.我完全不知道当许多用户同时使用该应用程序时会发生什么.

所以我的问题是,(假设我没有通过盲目的运气/ J2EE魔术偶然发现线程安全):

我怎样才能保证这个安全?

我在这里列出了我认为相关的信息,但如果这还不够,请告诉我.

太感谢了.

编辑:这是一个使用Wicket框架的合适的J2EE Web应用程序.我通常在Jetty中部署它.

编辑:关于ALIASes动机的长篇故事,对于那些感兴趣的人:

有问题的数据库是AS400上的DB2(i5,System i,iSeries,这些天IBM正在调用它),我正在使用jt400.

虽然AS400上的DB2有点像任何其他平台上的DB2,但由于遗留的东西,表有一个"成员"的概念.一个成员有点像桌子的一大块.我想要运行的查询是

SELECT thisField FROM thisTable(thisMember)
Run Code Online (Sandbox Code Playgroud)

它将thisMember视为一个表,因此只需为成员中的所有行提供thisField.

现在,像这样的查询在交互式SQL会话中运行良好,但不能通过JDBC工作(我不知道为什么).我使用的解决方法是做类似的事情

CREATE ALIAS tempAlias FOR thisTable(thisMember)
Run Code Online (Sandbox Code Playgroud)

那么一个

SELECT thisField FROM tempAlias
Run Code Online (Sandbox Code Playgroud)

那么一个

DROP ALIAS tempAlias
Run Code Online (Sandbox Code Playgroud)

但是对于一个停止显示的问题有效:当你使用ALIAS重复执行此操作时总是称为"tempAlias",并且有一个thisField从一个查询到下一个查询的长度不同的情况,结果集会在第二次查询时出现乱码查询(第一行的getString很好,下一个有前面有一定数量的空格,下一个空格的前面有相同数量的空格 - 这是来自内存,但它就是这样的).

因此,确保每个ALIAS都有一个明确的名称可以解决这个问题.

我刚刚意识到(花了很多时间来解释这个解释)我可能在抓住解决方法之前没有花足够的时间思考这个问题.不幸的是,我还没有实现为我的卧室购买AS400的梦想;)所以我现在不能尝试任何新的东西.

Jon*_*eet 8

好吧,我暂时忽略任何SQL内容,只关注uniqueInvocationNumber部分.这里有两个问题:

  • 无法保证线程在任何特定点都能看到最新值
  • 增量不是原子的

在Java中解决此问题的最简单方法是使用AtomicInteger:

private static final AtomicInteger uniqueInvocationNumber = new AtomicInteger();

public static Whatever getData(ValidatedQuery validatedQuery) {
    String aliasName = "TEMPALIAS" + uniqueInvocationNumber.getAndIncrement()
    // build statements, execute statements, deal with results
}
Run Code Online (Sandbox Code Playgroud)

请注意,这仍然假设您只在单个服务器上运行单个实例.对于一个可能是合理假设的家庭项目:)

另一个潜在的问题是在不同线程之间共享单个连接.通常,处理数据库连接的更好方法是使用连接池,并在需要的地方"打开/使用/关闭"连接(关闭finally块中的连接).